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

Last change on this file since 31406 was 31218, checked in by ak19, 7 years ago

Changes to get new perl code to work on the Mac Mountain Lion.

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