File Coverage

blib/lib/RDF/Core/Storage/DB_File.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             #
2             # The contents of this file are subject to the Mozilla Public
3             # License Version 1.1 (the "License"); you may not use this file
4             # except in compliance with the License. You may obtain a copy of
5             # the License at http://www.mozilla.org/MPL/
6             #
7             # Software distributed under the License is distributed on an "AS
8             # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9             # implied. See the License for the specific language governing
10             # rights and limitations under the License.
11             #
12             # The Original Code is the RDF::Core module
13             #
14             # The Initial Developer of the Original Code is Ginger Alliance Ltd.
15             # Portions created by Ginger Alliance are
16             # Copyright (C) 2001 Ginger Alliance Ltd.
17             # All Rights Reserved.
18             #
19             # Contributor(s):
20             #
21             # Alternatively, the contents of this file may be used under the
22             # terms of the GNU General Public License Version 2 or later (the
23             # "GPL"), in which case the provisions of the GPL are applicable
24             # instead of those above. If you wish to allow use of your
25             # version of this file only under the terms of the GPL and not to
26             # allow others to use your version of this file under the MPL,
27             # indicate your decision by deleting the provisions above and
28             # replace them with the notice and other provisions required by
29             # the GPL. If you do not delete the provisions above, a recipient
30             # may use your version of this file under either the MPL or the
31             # GPL.
32             #
33              
34             package RDF::Core::Storage::DB_File;
35              
36 1     1   733 use strict;
  1         2  
  1         55  
37             require Exporter;
38              
39             our @ISA = qw(RDF::Core::Storage);
40              
41 1     1   6 use Carp;
  1         1  
  1         67  
42 1     1   1611 use DB_File;
  0            
  0            
43             require RDF::Core::Storage;
44             require RDF::Core::Literal;
45             require RDF::Core::Resource;
46             require RDF::Core::Statement;
47             require RDF::Core::Enumerator::Memory;
48             require RDF::Core::Enumerator::DB_File;
49              
50              
51             #There are several entities stored in one file (tied hash) _data. Their key is a prefix + generated number, value is context dependent.
52             #Prefixes:
53             #in _data hash
54             use constant NAMESPACE => 'ns'; #resource's namespace
55             use constant VALUE => 'lv'; #resource's value
56             use constant LITERAL => 'lt'; #object's literal value
57             use constant LIT_TYPE => 'ld'; #object's literal datatype
58             use constant LIT_LANG => 'll'; #object's literal language
59             use constant SUBJECT => 'su'; #subject number
60             use constant PREDICATE => 'pr'; #predicate number
61             use constant OBJECT_RES => 'or'; #object number, if object is resource
62             use constant OBJECT_LIT => 'ol'; #object number, if object is literal
63             use constant SUBJECT_SIZE => 'ss'; #number of statements where given
64             # resource is subject
65             use constant PREDICATE_SIZE => 'ps'; #number of statements where given
66             # resource is predicate
67             use constant OBJECTRES_SIZE => 'os'; #number of statements where given
68             # resource is object
69             use constant OBJECTLIT_SIZE => 'ls'; #number of statements where given
70             # literal is object
71             use constant ALL_KEY => 'all'; #number of all statements in the model
72             #in idxStmt hash - it has duplicate values allowed
73             use constant SUBJECT_IDX => 'si'; #array of statements where given
74             # resource is subject
75             use constant PREDICATE_IDX => 'pi'; #array of statements where given
76             # resource is predicate
77             use constant OBJECTRES_IDX => 'oi'; #array of statements where given
78             # resource is object
79             use constant OBJECTLIT_IDX => 'li'; #array of statements where given
80             # literal is object
81              
82             #There are two more hashes - idxRes and idxLit. Their key is URI or literal
83             # value and their value is number of resource or literal in _data
84              
85             $SIG{INT} = \&__catch_zap;
86             my $writing;
87             my $die;
88             sub __catch_zap {
89             my $signame = shift;
90             if ($writing) {
91             warn"Finishing operation...";
92             $die++
93             } else {
94             die;
95             }
96              
97             }
98              
99             sub new {
100             my ($pkg, %options) = @_;
101             $pkg = ref $pkg || $pkg;
102             my $self = {};
103             $self->{_options} = \%options;
104             $self->{_steps}=0;
105              
106             $self->{_data} = {};
107             $self->{_idxStmt} = {};
108             $self->{_idxRes} = {};
109             $self->{_idxLit} = {};
110             ################################
111             #set options
112             #DB_File defaults
113             $self->{_options}->{Name} ||= undef;
114             $self->{_options}->{Flags} ||= O_CREAT|O_RDWR;
115             $self->{_options}->{Mode} ||= 0666;
116             #max nr of statements to be returned as in memory enumerator with getStmts
117             $self->{_options}->{MemLimit} ||= 0;
118             ################################
119             #tie hashes
120             my $file = $self->{_options}->{Name} && $self->{_options}->{Name}.'_data';
121             tie %{$self->{_data}}, 'DB_File', $file, $self->{_options}->{Flags},
122             $self->{_options}->{Mode}, $DB_HASH
123             or die "Couldn't tie ", $file || 'undef',": $!";
124             $file = $self->{_options}->{Name} && $self->{_options}->{Name}.'_idxLit';
125             tie %{$self->{_idxLit}}, 'DB_File', $file, $self->{_options}->{Flags},
126             $self->{_options}->{Mode}, $DB_HASH
127             or die "Couldn't tie ", $file || 'undef',": $!";
128             $file = $self->{_options}->{Name} && $self->{_options}->{Name}.'_idxRes';
129             tie %{$self->{_idxRes}}, 'DB_File', $file, $self->{_options}->{Flags},
130             $self->{_options}->{Mode}, $DB_HASH
131             or die "Couldn't tie ", $file || 'undef',": $!";
132             $DB_BTREE->{'flags'} = R_DUP;
133             $file = $self->{_options}->{Name} && $self->{_options}->{Name}.'_idxStmt';
134             tie %{$self->{_idxStmt}}, 'DB_File', $file, $self->{_options}->{Flags},
135             $self->{_options}->{Mode}, $DB_BTREE
136             or die "Couldn't tie ", $file || 'undef',": $!";
137             ################################
138             #init counter
139             $self->{_data}->{+ALL_KEY} = 0;
140              
141             bless $self, $pkg;
142             }
143             sub addStmt {
144             my ($self, $stmt) = @_;
145             #print "Entering addStmt ",$self->_getCounter('debug'),"\n";
146              
147             $writing = 1;
148             if ($self->existsStmt($stmt->getSubject,
149             $stmt->getPredicate,$stmt->getObject)) {
150             $writing=0;
151             die if $die;
152             return 0;
153             }
154             #Add subject to resources
155             my $subjectID;
156             if (!defined($subjectID = $self->{_idxRes}->{$stmt->getSubject->getURI})) {
157             $subjectID = $self->_getCounter('resource');
158             $self->{_data}->{+NAMESPACE.$subjectID} =
159             $stmt->getSubject->getNamespace;
160             $self->{_data}->{+VALUE.$subjectID} = $stmt->getSubject->getLocalValue;
161             $self->{_idxRes}->{$stmt->getSubject->getURI} = $subjectID;
162             }
163             #Add predicate to resources
164             my $predicateID;
165             if (!defined ($predicateID =
166             $self->{_idxRes}->{$stmt->getPredicate->getURI})) {
167             $predicateID = $self->_getCounter('resource');
168             $self->{_data}->{+NAMESPACE.$predicateID} =
169             $stmt->getPredicate->getNamespace;
170             $self->{_data}->{+VALUE.$predicateID} =
171             $stmt->getPredicate->getLocalValue;
172             $self->{_idxRes}->{$stmt->getPredicate->getURI} = $predicateID;
173             }
174             #Add object to resources or literals
175             my $objectID;
176             if ($stmt->getObject->isLiteral) {
177             my $value = $stmt->getObject->getValue;
178             my $lang = $stmt->getObject->getLang;
179             my $dt = $stmt->getObject->getDatatype;
180             my $idxLitKey = sprintf("L%s<%s>%s", $value, $lang, $dt);
181             if (!defined ($objectID = $self->{_idxLit}->{ $idxLitKey })) {
182             $objectID = $self->_getCounter('literal');
183             $self->{_data}->{+LITERAL.$objectID}=$stmt->getObject->getValue;
184             $self->{_data}->{+LIT_LANG.$objectID} =
185             $stmt->getObject->getLang
186             if $stmt->getObject->getLang;
187             $self->{_data}->{+LIT_TYPE.$objectID}=
188             $stmt->getObject->getDatatype
189             if $stmt->getObject->getDatatype;
190             $self->{_idxLit}->{ $idxLitKey } = $objectID;
191             }
192             } else {
193             if (!defined ($objectID = $self->{_idxRes}->{$stmt->getObject->getURI})) {
194             $objectID = $self->_getCounter('resource');
195             $self->{_data}->{+NAMESPACE.$objectID} = $stmt->getObject->getNamespace;
196             $self->{_data}->{+VALUE.$objectID} = $stmt->getObject->getLocalValue;
197             $self->{_idxRes}->{$stmt->getObject->getURI} = $objectID;
198             }
199             }
200             #Add statement and refresh indexes
201             my $stmtID = $self->_getCounter('statement');
202             $self->{_data}->{+SUBJECT.$stmtID} = $subjectID;
203             $self->{_data}->{+SUBJECT_SIZE.$subjectID}++;
204             $self->{_idxStmt}->{+SUBJECT_IDX.$subjectID} = $stmtID;
205             $self->{_data}->{+PREDICATE.$stmtID} = $predicateID;
206             $self->{_data}->{+PREDICATE_SIZE.$predicateID}++;
207             $self->{_idxStmt}->{+PREDICATE_IDX.$predicateID} = $stmtID;
208             if ($stmt->getObject->isLiteral) {
209             $self->{_data}->{+OBJECT_LIT.$stmtID} = $objectID;
210             $self->{_data}->{+OBJECTLIT_SIZE.$objectID}++;
211             $self->{_idxStmt}->{+OBJECTLIT_IDX.$objectID} = $stmtID;
212             } else {
213             $self->{_data}->{+OBJECT_RES.$stmtID} = $objectID;
214             $self->{_data}->{+OBJECTRES_SIZE.$objectID}++;
215             $self->{_idxStmt}->{+OBJECTRES_IDX.$objectID} = $stmtID;
216             }
217             $self->{_data}->{+ALL_KEY} ++;
218             $self->_synchronize;
219             $writing=0;
220             die if $die;
221             return 1
222             }
223              
224             sub removeStmt {
225             my ($self, $stmt) = @_;
226             return 0 unless
227             my $key = $self->_getKey($stmt);
228             $writing = 1;
229             my $idxStmt = tied %{$self->{_idxStmt}};
230             #Decrement number of occurences of resource/literal, delete not used
231             # resource/literal, remove statement from resource's/literal's index
232             # and index itself, if empty, remove statement
233             my $subjectID = $self->{_data}->{+SUBJECT.$key};
234             delete $self->{_data}->{+SUBJECT.$key};
235             $idxStmt->del_dup(SUBJECT_IDX.$subjectID, $key);
236             unless (--$self->{_data}->{+SUBJECT_SIZE.$subjectID}) {
237             delete $self->{_data}->{+SUBJECT_SIZE.$subjectID};
238             }
239             unless ($self->{_data}->{+SUBJECT_SIZE.$subjectID} ||
240             $self->{_data}->{+PREDICATE_SIZE.$subjectID} ||
241             $self->{_data}->{+OBJECTRES_SIZE.$subjectID}) {
242             delete $self->{_data}->{+NAMESPACE.$subjectID};
243             delete $self->{_data}->{+VALUE.$subjectID};
244             delete $self->{_idxRes}->{$stmt->getSubject->getURI};
245             }
246             my $predicateID = $self->{_data}->{+PREDICATE.$key};
247             delete $self->{_data}->{+PREDICATE.$key};
248             $idxStmt->del_dup(PREDICATE_IDX.$predicateID, $key);
249             unless (--$self->{_data}->{+PREDICATE_SIZE.$predicateID}) {
250             delete $self->{_data}->{+PREDICATE_SIZE.$predicateID};
251             }
252             unless ($self->{_data}->{+SUBJECT_SIZE.$predicateID} ||
253             $self->{_data}->{+PREDICATE_SIZE.$predicateID} ||
254             $self->{_data}->{+OBJECTRES_SIZE.$predicateID}) {
255             delete $self->{_data}->{+NAMESPACE.$predicateID};
256             delete $self->{_data}->{+VALUE.$predicateID};
257             delete $self->{_idxRes}->{$stmt->getPredicate->getURI};
258             }
259             my $objectID;
260             if ($stmt->getObject->isLiteral) {
261             $objectID = $self->{_data}->{+OBJECT_LIT.$key};
262             delete $self->{_data}->{+OBJECT_LIT.$key};
263             $idxStmt->del_dup(OBJECTLIT_IDX.$objectID, $key);
264             unless (--$self->{_data}->{+OBJECTLIT_SIZE.$objectID}) {
265             delete $self->{_data}->{+OBJECTLIT_SIZE.$objectID};
266             delete $self->{_data}->{+LITERAL.$objectID};
267             delete $self->{_data}->{+LIT_TYPE.$objectID};
268             delete $self->{_data}->{+LIT_LANG.$objectID};
269             my $value = $stmt->getObject->getValue;
270             my $lang = $stmt->getObject->getLang;
271             my $dt = $stmt->getObject->getDatatype;
272             my $idxLitKey = sprintf("L%s<%s>%s", $value, $lang, $dt);
273             delete $self->{_idxLit}->{ $idxLitKey };
274             }
275             } else {
276             $objectID = $self->{_data}->{+OBJECT_RES.$key};
277             delete $self->{_data}->{+OBJECT_RES.$key};
278             $idxStmt->del_dup(OBJECTRES_IDX.$objectID, $key);
279             unless (--$self->{_data}->{+OBJECTRES_SIZE.$objectID}) {
280             delete $self->{_data}->{+OBJECTRES_SIZE.$objectID};
281             }
282             unless ($self->{_data}->{+OBJECTRES_SIZE.$objectID} ||
283             $self->{_data}->{+SUBJECT_SIZE.$objectID} ||
284             $self->{_data}->{+PREDICATE_SIZE.$objectID}) {
285             delete $self->{_data}->{+NAMESPACE.$objectID};
286             delete $self->{_data}->{+VALUE.$objectID};
287             delete $self->{_idxRes}->{$stmt->getObject->getURI};
288             }
289             }
290             $self->{_data}->{+ALL_KEY} --;
291             undef $idxStmt;
292             $self->_synchronize;
293             $writing = 0;
294             die if $die;
295             return 1;
296             }
297              
298             sub existsStmt {
299             #print "Entering existsStmt\n";
300             my ($self, $subject, $predicate, $object) = @_;
301             my $retval = 0;
302             return $self->{_data}->{+ALL_KEY} > 0 ? 1 : 0
303             if !defined $subject && !defined $predicate && !defined $object;
304             foreach (@{$self->_getIndexArray($subject, $predicate, $object)}) {
305             my ($subURI, $predURI, $objValue, $index);
306             $index = $self->{_data}->{+SUBJECT.$_};
307             $subURI = $self->{_data}->{+NAMESPACE.$index}.
308             $self->{_data}->{+VALUE.$index};
309             $index = $self->{_data}->{+PREDICATE.$_};
310             $predURI = $self->{_data}->{+NAMESPACE.$index}.
311             $self->{_data}->{+VALUE.$index};
312             if (exists $self->{_data}->{+OBJECT_LIT.$_}) {
313             $index = $self->{_data}->{+OBJECT_LIT.$_};
314             $objValue = $self->{_data}->{+LITERAL.$index};
315             } else {
316             $index = $self->{_data}->{+OBJECT_RES.$_};
317             $objValue = $self->{_data}->{+NAMESPACE.$index}.
318             $self->{_data}->{+VALUE.$index};
319             }
320             if ((!defined $subject || $subURI eq $subject->getURI) &&
321             (!defined $predicate || $predURI eq $predicate->getURI) &&
322             (!defined $object || $objValue eq $object->getLabel)
323             ) {
324             $retval = 1; #found statement
325             last;
326             }
327             }
328             #print "Returning $retval\n";
329             return $retval;
330             }
331              
332             sub getStmts {
333             my ($self, $subject, $predicate, $object) = @_;
334             my $enumerator;
335             my $indexArray = $self->_getIndexArray($subject, $predicate, $object);
336             my $processInMemory = !$self->{_options}->{MemLimit} ||
337             @$indexArray < $self->{_options}->{MemLimit} ||
338             (defined $subject && defined $predicate && defined $object);
339             my @data; #for gathering data in memory
340             my $resultArray; #index for DB_File enumerator
341             if (!$processInMemory &&
342             #if DB_File enumerator is to be returned and at least two elements of triple are undef, you already have what you need
343             (!defined $subject && !defined $predicate ||
344             !defined $subject && !defined $object ||
345             !defined $predicate && !defined $object)) {
346             $resultArray = $indexArray
347             } else {
348             #otherwise loop through index and check statements
349             while (my $stmtIdx = pop @$indexArray) {
350             my ($subNS,$subLV,$predNS,$predLV, $objNS, $objLV, $objValue,
351             $litLang, $litDatatype, $index);
352             my $isLiteral;
353             $index = $self->{_data}->{+SUBJECT.$stmtIdx};
354             $subNS = $self->{_data}->{+NAMESPACE.$index};
355             $subLV = $self->{_data}->{+VALUE.$index};
356             $index = $self->{_data}->{+PREDICATE.$stmtIdx};
357             $predNS = $self->{_data}->{+NAMESPACE.$index};
358             $predLV = $self->{_data}->{+VALUE.$index};
359             if ($isLiteral = exists($self->{_data}->{+OBJECT_LIT.$stmtIdx})) {
360             $index = $self->{_data}->{+OBJECT_LIT.$stmtIdx};
361             $objValue = $self->{_data}->{+LITERAL.$index};
362             $litDatatype = $self->{_data}->{+LIT_TYPE.$index};
363             $litLang = $self->{_data}->{+LIT_LANG.$index};
364             } else {
365             $index = $self->{_data}->{+OBJECT_RES.$stmtIdx};
366             $objNS = $self->{_data}->{+NAMESPACE.$index};
367             $objLV = $self->{_data}->{+VALUE.$index};
368             $objValue = $objNS.$objLV;
369             }
370             if ((!defined $subject || $subNS.$subLV eq $subject->getURI) &&
371             (!defined $predicate || $predNS.$predLV eq $predicate->getURI) &&
372             (!defined $object || $objValue eq $object->getLabel)
373             ) { #found statement
374             if ($processInMemory) {
375             my $newsub = new RDF::Core::Resource($subNS,$subLV);
376             my $newpred = new RDF::Core::Resource($predNS,$predLV);
377             my $newobj;
378             if ($isLiteral) {
379             $newobj = new RDF::Core::Literal($objValue, $litLang,
380             $litDatatype);
381             } else {
382             $newobj = new RDF::Core::Resource($objNS,$objLV)
383             }
384             my $statement = new RDF::Core::Statement($newsub,$newpred,$newobj);
385             push @data, $statement;
386             } else {
387             push @$resultArray, $stmtIdx;
388             }
389             }
390             }
391             }
392             if ($processInMemory) {
393             $enumerator = RDF::Core::Enumerator::Memory->new(\@data) ;
394             } else {
395             $enumerator = RDF::Core::Enumerator::DB_File->new($self->{_data},$resultArray);
396             }
397             return $enumerator;
398             }
399             sub countStmts {
400             my ($self, $subject, $predicate, $object) = @_;
401             my $count = 0;
402              
403             return ($self->{_data}->{+ALL_KEY})
404             if !defined $subject && !defined $predicate && !defined $object;
405             foreach (@{$self->_getIndexArray($subject, $predicate, $object)}) {
406             my ($subNS,$subLV,$predNS,$predLV, $objNS, $objLV, $objValue, $index);
407             my $isLiteral;
408             $index = $self->{_data}->{+SUBJECT.$_};
409             $subNS = $self->{_data}->{+NAMESPACE.$index};
410             $subLV = $self->{_data}->{+VALUE.$index};
411             $index = $self->{_data}->{+PREDICATE.$_};
412             $predNS = $self->{_data}->{+NAMESPACE.$index};
413             $predLV = $self->{_data}->{+VALUE.$index};
414             if ($isLiteral = exists($self->{_data}->{+OBJECT_LIT.$_})) {
415             $index = $self->{_data}->{+OBJECT_LIT.$_};
416             $objValue = $self->{_data}->{+LITERAL.$index};
417             } else {
418             $index = $self->{_data}->{+OBJECT_RES.$_};
419             $objNS = $self->{_data}->{+NAMESPACE.$index};
420             $objLV = $self->{_data}->{+VALUE.$index};
421             $objValue = $objNS.$objLV;
422             }
423             if ((!defined $subject || $subNS.$subLV eq $subject->getURI) &&
424             (!defined $predicate || $predNS.$predLV eq $predicate->getURI) &&
425             (!defined $object || $objValue eq $object->getLabel)
426             ) { #found statement
427             $count++;
428             }
429             }
430             return $count;
431             }
432             sub _getCounter {
433             my ($self,$counterName) = @_;
434             return $self->{_data}->{'_'.$counterName} = ++$self->{_data}->{'_'.$counterName} || 1;
435             }
436             sub _getKey {
437             my ($self, $stmt) = @_;
438              
439              
440             foreach (@{$self->_getIndexArray($stmt->getSubject, $stmt->getPredicate, $stmt->getObject)}) {
441             my ($subURI, $predURI, $objValue, $index);
442             $index = $self->{_data}->{+SUBJECT.$_};
443             $subURI = $self->{_data}->{+NAMESPACE.$index}.$self->{_data}->{+VALUE.$index};
444             $index = $self->{_data}->{+PREDICATE.$_};
445             $predURI = $self->{_data}->{+NAMESPACE.$index}.$self->{_data}->{+VALUE.$index};
446             if ($stmt->getObject->isLiteral) {
447             $index = $self->{_data}->{+OBJECT_LIT.$_};
448             $objValue = $self->{_data}->{+LITERAL.$index};
449             } else {
450             $index = $self->{_data}->{+OBJECT_RES.$_};
451             $objValue = $self->{_data}->{+NAMESPACE.$index}.$self->{_data}->{+VALUE.$index};
452             }
453             if ($subURI eq $stmt->getSubject->getURI &&
454             $predURI eq $stmt->getPredicate->getURI &&
455             $objValue eq $stmt->getObject->getLabel
456             ) { #found statement
457             return $_;
458             }
459             }
460             return 0; #didn't find statement
461             }
462             sub _getIndexArray {
463             #find the smallest index array
464             my ($self, $subject, $predicate, $object) = @_;
465             my $idxStmt = tied %{$self->{_idxStmt}};
466             my @indexArray;
467             my $found = 0;
468             my $idxLength = 0;
469             my $keyBest;
470              
471             if (defined $subject) {
472             my $subjectID = $self->{_idxRes}->{$subject->getURI} || '';
473             $found = 1;
474             $idxLength = $self->{_data}->{+SUBJECT_SIZE.$subjectID} || 0;
475             $keyBest = SUBJECT_IDX.$subjectID;
476             }
477             if (defined $predicate) {
478             my $predicateID = $self->{_idxRes}->{$predicate->getURI} || '';
479             if (!$found || $idxLength >
480             ($self->{_data}->{+PREDICATE_SIZE.$predicateID} || 0)) {
481             $found = 1;
482             $idxLength = $self->{_data}->{+PREDICATE_SIZE.$predicateID} || 0;
483             $keyBest = PREDICATE_IDX.$predicateID;
484             }
485             }
486             if (defined $object) {
487             my $objectID;
488             if ($object->isLiteral) {
489             my $value = $object->getValue;
490             my $lang = $object->getLang;
491             my $dt = $object->getDatatype;
492             my $idxLitKey = sprintf("L%s<%s>%s", $value, $lang, $dt);
493             $objectID = $self->{_idxLit}->{ $idxLitKey } || '';
494             $idxLength = $self->{_data}->{+OBJECTLIT_SIZE.$objectID} || 0;
495             $keyBest = OBJECTLIT_IDX.$objectID;
496             } else {
497             $objectID = $self->{_idxRes}->{$object->getURI} || '';
498             $idxLength = $self->{_data}->{+OBJECTRES_SIZE.$objectID} || 0;
499             $keyBest = OBJECTRES_IDX.$objectID;
500             }
501             $found = 1;
502             }
503             if ($found) {
504             @indexArray = $idxStmt->get_dup($keyBest);
505             } else {
506             foreach (keys %{$self->{_data}}) {
507             my $prefix = SUBJECT;
508             if (/^$prefix/) {
509             push(@indexArray,$');
510             }
511             }
512             }
513             return \@indexArray;
514             }
515              
516             sub _synchronize {
517             my ($self) = @_;
518             my $sync;
519             if (my $sync = $self->{_options}->{Sync}) {
520             if (++$self->{_steps} > $sync) {
521             $self->{_steps} = 0;
522             foreach (($self->{_data}, $self->{_idxStmt}, $self->{_idxRes},
523             $self->{_idxLit})) {
524             if (defined) {
525             my $t = tied %$_;
526             next unless $t;
527             $t->sync;
528             }
529             }
530             }
531             }
532             }
533              
534              
535              
536             sub DESTROY {
537             my $self = shift;
538             #untie hashes
539             foreach (($self->{_data}, $self->{_idxStmt}, $self->{_idxRes},
540             $self->{_idxLit})) {
541             if (defined) {
542             my $t = tied %$_;
543             next unless $t;
544             $t->sync;
545             undef $t;
546             untie %$_;
547             }
548             }
549             }
550              
551             1;
552             __END__