source: main/trunk/greenstone2/perllib/oaiinfo.pm@ 31494

Last change on this file since 31494 was 31409, checked in by ak19, 7 years ago

Adding verbosity setting to oaiinfo.pm to reduce debug output on regular runs of building process. The perl filest that use oaiinfo now pass in the verbosity setting to the oaiinfo constructor.

File size: 23.3 KB
Line 
1# This class based on arcinfo.pm
2package oaiinfo;
3
4use constant INFO_STATUS_INDEX => 0;
5use constant INFO_TIMESTAMP_INDEX => 1;
6use constant INFO_DATESTAMP_INDEX => 2;
7
8use strict;
9
10use arcinfo;
11use dbutil;
12
13# Store timestamp in 2 formats: internal and external (same as oailastmodified and oailastmodifieddate)
14# These times indicate the last modified date for that document. In the case of the doc being deleted,
15# it's the time the doc was deleted.
16
17# File format read in: OID <tab> (Deletion-)Status <tab> Timestamp <tab> Datestamp
18
19# Deletion status can be:
20# E = Doc with OID exists (has not been deleted from collection). Timestamp indicates last time of build
21# D = Doc with OID has been deleted. Timestamp indicates time of deletion
22# PD = Provisionally Deleted. The associated timestamps are momentarily unaltered.
23
24# oaidb is "always incremental": always reflects the I/B/R/D status of archive info db,
25# before the indexing step of the build phase that alters the I/B/R/D contents of archive info db.
26# (I=index, B=been indexed, R=reindex; D=delete)
27
28sub new {
29 my $class = shift(@_);
30 my ($config_filename, $infodbtype, $verbosity) = @_;
31
32 my $self = {
33 'verbosity' => $verbosity || 0,
34 'verbosity_threshold' => 5, # start printing debugging info from verbosity >= threshold
35 'info'=>{} # map of {OID, array[deletion-status,timestamp,datestamp]} pairs
36 };
37
38 if(!defined $infodbtype) {
39 $infodbtype = &dbutil::get_default_infodb_type();
40 }
41 $infodbtype = "gdbm" if ($infodbtype eq "gdbm-txtgz");
42 $self->{'infodbtype'} = $infodbtype;
43
44 # Create and store the db filenames we'll be working with (tmp and livedb)
45 my $etc_dir = &util::get_parent_folder($config_filename);
46
47 my $perform_firsttime_init = 0;
48 $self->{'oaidb_live_filepath'} = &dbutil::get_infodb_file_path($infodbtype, "oai-inf", $etc_dir, $perform_firsttime_init);
49 $self->{'oaidb_tmp_filepath'} = &dbutil::get_infodb_file_path($infodbtype, "oai-inf-tmp", $etc_dir, $perform_firsttime_init);
50 $self->{'etc_dir'} = $etc_dir;
51# print STDERR "############ LIVE DB: $self->{'oaidb_live_filepath'}\n" if $self->{'verbosity'} >= $self->{'verbosity_threshold'};
52# print STDERR "############ TMP DB: $self->{'oaidb_tmp_filepath'}\n" if $self->{'verbosity'} >= $self->{'verbosity_threshold'};
53
54 $self->{'oaidb_file_path'} = $self->{'oaidb_tmp_filepath'}; # db file we're working with
55
56 return bless $self, $class;
57}
58
59# this subroutine will work out the starting contents of the tmp-db (temporary oai db):
60# whether it should start off empty, or with the contents of any existing live-db,
61# or with the contents of any existing tmp-db.
62sub init_tmpdb {
63 my $self = shift(@_);
64 my ($removeold, $have_manifest) = @_;
65
66 # if we have a manifest file, then we pretend we are fully incremental for oaiinfo db.
67 # removeold implies proper full-rebuild, whereas keepold or incremental means incremental
68 if($have_manifest) { # if we have a manifest file, we're not doing removeold/full-rebuild either
69 $removeold = 0;
70 }
71
72 my $do_pd_step = ($removeold) ? 1 : 0;
73 # if $removeold, then proper full rebuild, will carry out step where all E will be marked as PD
74 # else some kind of incremental build, won't do the extra PD pass
75 # which is the step marking existing OIDs (E) as PD (provisionally deleted)
76
77 my $oaidb_live_filepath = $self->{'oaidb_live_filepath'};
78 my $oaidb_tmp_filepath = $self->{'oaidb_tmp_filepath'};
79 my $infodbtype = $self->{'infodbtype'};
80 # Note: the live db can only exist if the collection has been activated at least once before
81 my $livedb_exists = &FileUtils::fileExists($oaidb_live_filepath);
82 my $tmpdb_exists = &FileUtils::fileExists($oaidb_tmp_filepath);
83
84 my $initdb = 0;
85
86 # work out what operation we need to do
87 # work with empty tmpdb
88 # copy_livedb_to_tmpdb
89 # work with existing tmpdb (so existing tmpdb will be topped up)
90
91 # make_contents_of_tmpdb_empty
92 # make_contents_of_tmpdb_that_of_livedb
93 # continue_working_with_tmpdb ("contents_of_tmpdb_is_tmpdb")
94
95 # We're going to prepare the starting state of tmpdb next.
96 # It can start off empty, start off with the contents of livedb, or it can start off with the contents
97 # of the existing tmp db. Which of these three it is depends on the 3 factors: whether livedb exists,
98 # whether tmpdb exists and whether or not removeold is true.
99 # i.o.w. which of the 3 outcomes it is depends on the truth table built on the following 3 variables:
100 # LDB = LiveDB exists
101 # TDB = TmpDB exists
102 # RO = Removeold
103 # OUTCOMES:
104 # clean slate (create an empty tmpdb/make tmpdb empty)
105 # top up tmpDB (work with existing tmpdb)
106 # copy LiveDB to TmpDB (liveDB's contents become the contents of TmpDB, and we'll work with that)
107 #
108 # TRUTH TABLE:
109 # ---------------------------------------
110 # LDB TDB RO | Outcome
111 # ---------------------------------------
112 # 0 0 0 | clean-slate
113 # 0 0 1 | clean-slate
114 # 0 1 0 | top-up-tmpdb
115 # 0 1 1 | erase tmpdb, clean-slate
116 # 1 0 0 | copy livedb to tmpdb
117 # 1 0 1 | copy livedb to tmpdb
118 # 1 1 0 | top-up-tmpdb
119 # 1 1 1 | copy livedb to tmpd
120 # ---------------------------------------
121 #
122 # Dr Bainbridge worked out using Karnaugh maps that, from the above truth table:
123 # => clean-slate/empty-tmpdb = !LDB && (RO || !TDB)
124 # => top-up-tmpdb/work-with-existing-tmpdb = !RO && TDB
125 # => copy-livedb-to-tmpdb = LDB && (!TDB || RO)
126 # I had most of these tests, except that I hadn't (yet) merged the two clean slate instances
127 # of first-build-ever and make-contents-of-tmpdb-empty
128
129 #my $first_build_ever = (!$livedb_exists && !$tmpdb_exists);
130 #my $make_contents_of_tmpdb_empty = (!$livedb_exists && $tmpdb_exists && $removeold);
131 # Karnaugh map allows merging $first_build_ever and $make_contents_of_tmpdb_empty above
132 # into: my $work_with_empty_tmpdb = (!$livedb_exists && (!$tmpdb_exists || $removeold));
133 my $work_with_empty_tmpdb = (!$livedb_exists && (!$tmpdb_exists || $removeold));
134 my $make_contents_of_tmpdb_that_of_livedb = ($livedb_exists && (!$tmpdb_exists || $removeold));
135 my $work_with_existing_tmpdb = ($tmpdb_exists && !$removeold);
136
137 if($work_with_empty_tmpdb) { # we'll use an empty tmpdb
138
139 # If importing the collection for the very first time, neither db exists,
140 # so create an empty tmpdb.
141 #
142 # We also create an empty tmpdb when livedb doesn't exist and $removeold is true.
143 # This can happen if we've never run activate (so no livedb),
144 # yet had done some import (and perhaps building) followed by a full re-import now.
145 # Since there was no activate and we're doing a removeold/full-rebuild now, can just
146 # work with a new tmpdb, even though one already existed, its contents can be wiped out.
147 # In such a scenario, we'll be deleting tmpdb. Then there will be no livedb nor any tmpdb
148 # any more, so same situation as if importing the very first time when no oaidb exists either.
149
150 &dbutil::remove_db_file($self->{'infodbtype'}, $oaidb_tmp_filepath) if $tmpdb_exists; # remove the db file and any assoc files
151 $initdb = 1; # new tmpdb
152
153 # if the oai db is created the first time, it's like incremental and
154 # "keepold" (keepold means "only add, don't reprocess existing"). So
155 # no need to do the special passes dealing with "provisional deletes".
156 $do_pd_step = 0;
157
158 } elsif ($make_contents_of_tmpdb_that_of_livedb) {
159
160 # If the livedb exists and we're doing a full rebuild ($removeold is true),
161 # copy livedb to tmp regardless of if tmpdb already exists.
162 # Or if the livedb exists and tmpdb doesn't exist, it doesn't matter
163 # if we're incremental or not: also copy live to tmp and work with tmp.
164
165 # copy livedb to tmpdb
166 &dbutil::remove_db_file($self->{'infodbtype'}, $oaidb_tmp_filepath) if $tmpdb_exists; # remove the db file and any assoc files
167 &FileUtils::copyFiles($oaidb_live_filepath, $oaidb_tmp_filepath);
168
169 $initdb = 0; # tmpdb exists, since we just copied livedb to tmpdb, so need to init existing tmpdb
170
171 } else { # $work_with_existing_tmpdb, so we'll build on top of what's presently already in tmpdb
172 # (we'll be topping up the current tmpdb)
173
174 # !$removeold, meaning incremental
175 # If incremental and have a tmpdb already, regardless of whether livedb exists,
176 # then work with the existing tmpdb file, as this means we've been
177 # importing (perhaps followed by building) repeatedly without activating the
178 # last time but want to maintain the (incremental) changes in tmpdb.
179
180 $initdb = 0;
181
182 } # Dr Bainbridge drew up Karnaugh maps on the truth table, which proved that all cases
183 # are indeed covered above, so don't need any other catch-all else here
184
185 $self->{'oaidb_file_path'} = &dbutil::get_infodb_file_path($infodbtype, "oai-inf-tmp", $self->{'etc_dir'}, $initdb);
186 # final param follows jmt's $perform_firsttime_init in inexport.pm
187
188# print STDERR "@@@@@ oaidb: $self->{'oaidb_file_path'}\n" if $self->{'verbosity'} >= $self->{'verbosity_threshold'};
189
190 return $do_pd_step;
191}
192
193sub get_filepath {
194 my $self = shift (@_);
195 return $self->{'oaidb_file_path'};
196}
197
198sub import_stage {
199 my $self = shift (@_);
200 my ($removeold, $have_manifest) = @_;
201
202 my $do_pd_step = $self->init_tmpdb($removeold, $have_manifest);
203 # returns 1 if the step to mark oaidb entries as PD is required
204 # if we're doing full rebuilding and it's NOT the first time creating the oai_inf db,
205 # then the tasks to do with PD (provisionally deleted) OAI OIDs should be carried out
206
207 $self->load_info();
208 $self->print_info(); # DEBUGGING
209
210 if ($do_pd_step) {
211 $self->mark_all_existing_as_provisionallydeleted();
212 $self->print_info(); # DEBUGGING
213
214 # save to db file now that we're done
215 $self->save_info();
216 }
217
218}
219
220sub building_stage_before_indexing() {
221 my $self = shift (@_);
222 my ($archivedir) = @_;
223
224 # load archive info db into memory
225 my $arcinfo_doc_filename = &dbutil::get_infodb_file_path($self->{'infodbtype'}, "archiveinf-doc", $archivedir);
226 my $arcinfo_src_filename = &dbutil::get_infodb_file_path($self->{'infodbtype'}, "archiveinf-src", $archivedir);
227 my $archive_info = new arcinfo ($self->{'infodbtype'});
228 $archive_info->load_info ($arcinfo_doc_filename);
229
230 #my $started_from_scratch = &FileUtils::fileTest($self->{'oaidb_tmp_filepath'}, '-z'); # 1 if tmpdb is empty
231 # -z test for file is empty http://www.perlmonks.org/?node_id=927447
232
233 # load the oaidb file's contents into memory.
234 $self->load_info();
235 $self->print_info(); # DEBUGGING
236
237 # process all the index, reindex and delete operations as indicated in arcinfo,
238 # all the while ensuring all PDs are changed back to E for OIDs that exist in both arcinfo and oaiinfo db.
239
240 my $arcinfo_map = $archive_info->{'info'};
241
242 foreach my $OID (keys %$arcinfo_map) {
243 my $arcinf_tuple = $archive_info->{'info'}->{$OID};
244 my $indexing_status = $arcinf_tuple->[arcinfo::INFO_STATUS_INDEX];
245 # use packageName::constant to refer to constants declared in another package,
246 # see http://perldoc.perl.org/constant.html
247
248 print STDERR "######## OID: $OID - status: $indexing_status\n" if $self->{'verbosity'} >= $self->{'verbosity_threshold'};
249
250 if($indexing_status eq "I") {
251 $self->index($OID); # add new as E with current timestamp/or set existing as E with orig timestamp
252 } elsif($indexing_status eq "R") {
253 $self->reindex($OID); # update timestamp and ensure marked as E (if oid doesn't exist, add new)
254 } elsif($indexing_status eq "D") {
255 $self->delete($OID); # set as D with current timestamp
256 } elsif($indexing_status eq "B") { # B for "been indexed"
257 $self->been_indexed($OID); # will flip any PD to E if oid exists, else will add new entry for oid
258 # A new entry may be required if the collection had been built prior to turning this into
259 # an oaicollection. But what if we always maintain an oaidb? Still call $self->index() here.
260 } else {
261 if ($self->{'verbosity'} >= $self->{'verbosity_threshold'}) {
262 print STDERR "### oaiinfo::building_stage_before_indexing(): Unrecognised indexing status $indexing_status\n";
263 }
264 }
265 }
266
267 # once all docs processed, go through oaiiinfo db changing any PDs to D along with current timestamp
268 # to indicate that they're deleted
269 $self->mark_all_provisionallydeleted_as_deleted();
270 $self->print_info();
271
272 # let's save to db file now that we're done
273 $self->save_info();
274
275}
276
277sub activate_collection { # move tmp db to live db
278 my $self = shift (@_);
279
280 my $oaidb_live_filepath = $self->{'oaidb_live_filepath'};
281 my $oaidb_tmp_filepath = $self->{'oaidb_tmp_filepath'};
282
283 my $livedb_exists = &FileUtils::fileExists($oaidb_live_filepath);
284 my $tmpdb_exists = &FileUtils::fileExists($oaidb_tmp_filepath);
285
286 if($tmpdb_exists) {
287 if($livedb_exists) {
288 #&dbutil::remove_db_file($self->{'infodbtype'}, s$oaidb_live_filepath); # remove the db file and any assoc files
289 &dbutil::rename_db_file_to($self->{'infodbtype'}, $oaidb_live_filepath, $oaidb_live_filepath.".bak"); # rename the db file and any assoc files
290 }
291 #&FileUtils::moveFiles($oaidb_tmp_filepath, $oaidb_live_filepath);
292 &dbutil::rename_db_file_to($self->{'infodbtype'}, $oaidb_tmp_filepath, $oaidb_live_filepath); # rename the db file and any assoc files
293
294 if ($self->{'verbosity'} >= $self->{'verbosity_threshold'}) {
295 print STDERR "#### Should now have MOVED $self->{'oaidb_tmp_filepath'} to $self->{'oaidb_live_filepath'}\n";
296 }
297
298 } else {
299 if ($self->{'verbosity'} >= $self->{'verbosity_threshold'}) {
300 print STDERR "@@@@@ In oaiinfo::activate_collection():\n";
301 print STDERR "@@@@@ No tmpdb at $self->{'oaidb_tmp_filepath'}\n";
302 print STDERR "@@@@@ to make 'live' by moving to $self->{'oaidb_live_filepath'}.\n";
303 }
304 }
305}
306
307##################### SPECIFIC TO PD-STEP ####################
308
309
310# mark all existing, E (non-deleted) OIDs as Provisionally Deleted (PD)
311# this subroutine doesn't save to oai-inf.DB
312# the caller should call save_info when they want to save to the db
313sub mark_all_existing_as_provisionallydeleted {
314 my $self = shift (@_);
315
316 print STDERR "@@@@@ oaiinfo::mark_all_E_as_PD(): Marking the E entries as PD\n" if $self->{'verbosity'} >= $self->{'verbosity_threshold'};
317
318 my $infomap = $self->{'info'};
319
320 foreach my $OID (keys %$infomap) { # Mac Mountain Lion wants %$map, won't accept %$self->{'info'}
321 my $OID_info = $self->{'info'}->{$OID};
322 my $curr_status = $OID_info->[INFO_STATUS_INDEX];
323 if($curr_status eq "E") {
324 $OID_info->[INFO_STATUS_INDEX] = "PD";
325 }
326 }
327}
328
329# mark all OIDs that are Provisionally Deleted (PD) as deleted, and set to current timestamp
330# To be called at end of build. Again, the caller should save to DB by calling save_info.
331sub mark_all_provisionallydeleted_as_deleted {
332 my $self = shift (@_);
333
334 print STDERR "@@@@@ oaiinfo::mark_all_PD_as_D(): Marking the PD entries as D\n" if $self->{'verbosity'} >= $self->{'verbosity_threshold'};
335
336 my $infomap = $self->{'info'};
337
338 foreach my $OID (keys %$infomap) {
339 my $OID_info = $self->{'info'}->{$OID};
340 my $curr_status = $OID_info->[INFO_STATUS_INDEX];
341 if($curr_status eq "PD") {
342 $self->set_info($OID, "D", $self->get_current_time());
343 }
344 }
345}
346
347
348##################### GENERAL, NOT SPECIFIC TO PD-STEP ####################
349
350sub print_info {
351 my $self = shift (@_);
352
353 if ($self->{'verbosity'} < $self->{'verbosity_threshold'}) {
354 return;
355 }
356
357 print STDERR "###########################################################\n";
358 print STDERR "@@@@@ oaiinfo::print_info(): oaidb in memory contains: \n";
359
360 my $infomap = $self->{'info'};
361
362 foreach my $OID (keys %$infomap) {
363 print STDERR "OID: $OID";
364 print STDERR " status: " . $self->{'info'}->{$OID}->[INFO_STATUS_INDEX];
365 print STDERR " time: " . $self->{'info'}->{$OID}->[INFO_TIMESTAMP_INDEX];
366 print STDERR " date: " . $self->{'info'}->{$OID}->[INFO_DATESTAMP_INDEX];
367 print STDERR "\n";
368 }
369
370 print STDERR "###########################################################\n";
371}
372
373
374# Find the OID, if it exists, make its status=E for existing. Leave its timestamp alone.
375# If the OID doesn't yet exist, add it as a new entry with status=E and with current timestamp.
376sub index { # Add a new oid with current time and E. If the oid was already present, mark as E
377 my $self = shift (@_);
378 my ($OID) = @_;
379
380 my $OID_info = $self->{'info'}->{$OID};
381
382 if (defined $OID_info) { # if OID is present, this will change status back to E, timestamp unchanged
383 $OID_info->[INFO_STATUS_INDEX] = "E";
384
385 } else { # if OID is not present, then it's now added as existing from current time on
386 $self->set_info($OID, "E", $self->get_current_time());
387 }
388}
389
390# Upon reindexing a document with identifier OID, change its timestamp to current time
391# if a new OID, then add as new entry with status=E and current timestamp
392sub reindex { # update timestamp if oid is already present, if not (unlikely), add as new
393 my $self = shift (@_);
394 my ($OID) = @_;
395
396 my $OID_info = $self->{'info'}->{$OID};
397 $self->set_info($OID, "E", $self->get_current_time()); # Takes care of 3 things:
398 # if OID exists, updates modified time to indicate the doc has been reindexed
399 # if OID exists, ensures any status=PD is flipped back to E for this OID doc (as we know it exists);
400 # if the OID doesn't yet exist, adds a new OID entry with status=E and current timestamp.
401
402}
403
404# Does the same as index():
405# OIDs that have been indexed upon rebuild may still be new to the oaidb: GS2 collections
406# are not OAI collections by default, unlike GS3 collections. Imagine rebuilding a (GS2) collection
407# 5 times and then setting them to be an OAI collection. In that case, the doc OIDs in the collection
408# may not be in the oaidb yet. Unless, we decide (as is the present case) to always maintain an oaidb
409# (always creating an oaidb regardless of whether the collection has OAI support turned on or not).
410sub been_indexed {
411 my $self = shift (@_);
412 my ($OID) = @_;
413
414 $self->index($OID);
415}
416
417# Upon deleting a document with identifier OID,
418# set status to deleted and change its timestamp to current time
419sub delete {
420 my $self = shift (@_);
421 my ($OID) = @_;
422
423 # the following method will set to current time if no timestamp provided,
424 # But by explicit here, the code is easier to follow
425 $self->set_info($OID, "D", $self->get_current_time());
426
427}
428
429#############################################################
430sub get_current_time {
431 my $self = shift (@_);
432 return time; # current time
433
434 # localtime(time) returns an array of values (day, month, year, hour, min, seconds) or singular string
435 # return localtime; # same as localtime(time); # http://perldoc.perl.org/functions/localtime.html
436
437}
438
439sub get_datestamp {
440 my $self = shift (@_);
441 my ($timestamp) = @_;
442
443 my ($seconds, $minutes, $hours, $day_of_month, $month, $year,
444 $wday, $yday, $isdst) = localtime($timestamp);
445
446 my $datestamp = sprintf("%d%02d%02d",1900+$year,$month+1,$day_of_month);
447
448 return $datestamp;
449}
450
451sub _load_info_txt
452{
453 my $self = shift (@_);
454 my ($filename) = @_;
455
456 if (defined $filename && &FileUtils::fileExists($filename)) {
457 open (INFILE, $filename) ||
458 die "oaiinfo::load_info couldn't read $filename\n";
459
460 my ($line, @lineparts);
461 while (defined ($line = <INFILE>)) {
462 $line =~ s/\cM|\cJ//g; # remove end-of-line characters
463 @lineparts = split ("\t", $line);
464 if (scalar(@lineparts) >= 2) {
465 $self->set_info (@lineparts);
466 }
467 }
468 close (INFILE);
469 }
470
471}
472
473sub _load_info_db
474{
475 my $self = shift (@_);
476 my ($filename) = @_;
477
478 my $infodb_map = {};
479
480 &dbutil::read_infodb_file($self->{'infodbtype'}, $filename, $infodb_map);
481
482 foreach my $oid ( keys %$infodb_map ) {
483 my $vals = $infodb_map->{$oid};
484 # interested in oid, timestamp, deletion status
485
486 my ($deletion_status) = ($vals=~/^<status>(.*)$/m);
487 my ($timestamp) = ($vals=~/^<timestamp>(.*)$/m);
488 my ($datestamp) = ($vals=~/^<datestamp>(.*)$/m);
489
490 $self->add_info ($oid, $deletion_status, $timestamp, $datestamp);
491 }
492}
493
494# if no filename is passed in (and you don't generally want to), then
495# it tries to load in <collection>/etc/oai-inf.<db> if it exists
496sub load_info {
497 my $self = shift (@_);
498 my ($filename) = @_;
499
500 $self->{'info'} = {};
501
502 $filename = $self->{'oaidb_file_path'} unless defined $filename;
503
504 if (&FileUtils::fileExists($filename)) {
505 if ($filename =~ m/\.inf$/) {
506 $self->_load_info_txt($filename);
507 }
508 else {
509 $self->_load_info_db($filename);
510 }
511 }
512
513}
514
515sub _save_info_txt {
516 my $self = shift (@_);
517 my ($filename) = @_;
518
519 my ($OID, $info);
520
521 open (OUTFILE, ">$filename") ||
522 die "oaiinfo::save_info couldn't write $filename\n";
523
524 foreach $info (@{$self->get_OID_list()}) {
525 if (defined $info) {
526 print OUTFILE join("\t", @$info), "\n";
527 }
528 }
529 close (OUTFILE);
530}
531
532# if no filename is passed in (and you don't generally want to), then
533# this subroutine tries to write to <collection>/etc/oai-inf.<db>.
534sub _save_info_db {
535 my $self = shift (@_);
536 my ($filename) = @_;
537
538 $filename = $self->{'oaidb_file_path'} unless defined $filename;
539 my $infodbtype = $self->{'infodbtype'};
540
541 # write out again. Open file for overwriting, not appending.
542 # Then write out data structure $self->{'info'} that's been maintaining the data in-memory.
543 my $infodb_handle = &dbutil::open_infodb_write_handle($infodbtype, $filename);
544
545 my $infomap = $self->{'info'};
546 foreach my $oid ( keys %$infomap ) {
547 my $OID_info = $self->{'info'}->{$oid};
548 my $val = "<status>".$OID_info->[INFO_STATUS_INDEX];
549 $val .= "\n<timestamp>".$OID_info->[INFO_TIMESTAMP_INDEX];
550 $val .= "\n<datestamp>".$OID_info->[INFO_DATESTAMP_INDEX]."\n";
551 &dbutil::write_infodb_rawentry($infodbtype,$infodb_handle,$oid,$val);
552 }
553 &dbutil::close_infodb_write_handle($infodbtype, $infodb_handle);
554}
555
556sub save_info {
557 my $self = shift (@_);
558 my ($filename) = @_;
559
560 if(defined $filename) {
561 if ($filename =~ m/(contents)|(\.inf)$/) {
562 $self->_save_info_txt($filename);
563 }
564 else {
565 $self->_save_info_db($filename);
566 }
567 } else {
568 $self->_save_info_db();
569 }
570}
571
572
573sub set_info { # sets existing or appends
574 my $self = shift (@_);
575 my ($OID, $del_status, $timestamp) = @_;
576
577 if(!defined $timestamp) { # get current date timestamp
578 $timestamp = $self->get_current_time();
579 }
580 my $datestamp = $self->get_datestamp($timestamp);
581
582 $self->{'info'}->{$OID} = [$del_status, $timestamp, $datestamp];
583
584}
585
586sub add_info { # called to load a single record from file into memory, so it should be provided all 4 fields
587 my $self = shift (@_);
588 my ($OID, $del_status, $timestamp, $datestamp) = @_;
589
590 $self->{'info'}->{$OID} = [$del_status, $timestamp, $datestamp];
591}
592
593
594# returns a list of the form [[OID, deletion_status, timestamp, datestamp], ...]
595sub get_OID_list
596{
597 my $self = shift (@_);
598
599 my @list = ();
600
601 my $infomap = $self->{'info'};
602 foreach my $OID (keys %$infomap) {
603 my $OID_info = $self->{'info'}->{$OID};
604
605 push (@list, [$OID, $OID_info->[INFO_STATUS_INDEX],
606 $OID_info->[INFO_TIMESTAMP_INDEX],
607 $OID_info->[INFO_DATESTAMP_INDEX]
608 ]);
609 }
610
611 return \@list;
612}
613
614
615# returns the number of entries so far, including deleted ones
616# http://stackoverflow.com/questions/1109095/how-can-i-find-the-number-of-keys-in-a-hash-in-perl
617sub size {
618 my $self = shift (@_);
619 my $infomap = $self->{'info'};
620 return (scalar keys %$infomap);
621}
622
6231;
Note: See TracBrowser for help on using the repository browser.