line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
########################################################################### |
2
|
|
|
|
|
|
|
### Trinket::Directory::DataAccess::RAM |
3
|
|
|
|
|
|
|
### |
4
|
|
|
|
|
|
|
### Access to directory of persistent objects. |
5
|
|
|
|
|
|
|
### |
6
|
|
|
|
|
|
|
### $Id: RAM.pm,v 1.2 2001/02/16 07:25:45 deus_x Exp $ |
7
|
|
|
|
|
|
|
### |
8
|
|
|
|
|
|
|
### TODO: |
9
|
|
|
|
|
|
|
### -- Callbacks for Object to accomdate on-demand property get/set |
10
|
|
|
|
|
|
|
### -- Do something meaningful in close() |
11
|
|
|
|
|
|
|
### -- Save contents of RAM directories? implement in open()/close()? |
12
|
|
|
|
|
|
|
### -- Cooperate with ACLs |
13
|
|
|
|
|
|
|
### -- Implement a cursor for access to search results |
14
|
|
|
|
|
|
|
### -- Implement support for data types (char is only type for now) |
15
|
|
|
|
|
|
|
### -- Should DESTROY() do something? (per warning) |
16
|
|
|
|
|
|
|
### -- How do we handle the left over undefined storage slots left by |
17
|
|
|
|
|
|
|
### deleted objects? (Compact the database? Renumber everything |
18
|
|
|
|
|
|
|
### and all references to those numbers? Use a hash instead?) |
19
|
|
|
|
|
|
|
### -- Prevent serialization of any properties of type 'ref'? |
20
|
|
|
|
|
|
|
### -- Minimize search leaf subs even further? |
21
|
|
|
|
|
|
|
### |
22
|
|
|
|
|
|
|
########################################################################### |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
package Trinket::Directory::DataAccess::RAM; |
25
|
|
|
|
|
|
|
|
26
|
1
|
|
|
1
|
|
9
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
74
|
|
27
|
1
|
|
|
1
|
|
7
|
use vars qw($VERSION @ISA @EXPORT $DESCRIPTION $AUTOLOAD); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
140
|
|
28
|
1
|
|
|
1
|
|
21
|
no warnings qw( uninitialized ); |
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
92
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# {{{ Begin POD |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=head1 NAME |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
Trinket::Directory::DataAccess::RAM - |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 DESCRIPTION |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
TODO |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=cut |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# }}} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# {{{ METADATA |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
BEGIN |
47
|
|
|
|
|
|
|
{ |
48
|
1
|
|
|
1
|
|
3
|
$VERSION = "0.0"; |
49
|
1
|
|
|
|
|
21
|
@ISA = qw( Trinket::Directory::DataAccess ); |
50
|
1
|
|
|
|
|
27
|
$DESCRIPTION = 'Base object directory'; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# }}} |
54
|
|
|
|
|
|
|
|
55
|
1
|
|
|
1
|
|
7
|
use Trinket::Directory::DataAccess; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
52
|
|
56
|
|
|
|
|
|
|
|
57
|
1
|
|
|
1
|
|
5
|
use Trinket::Object; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
11
|
|
58
|
1
|
|
|
1
|
|
6
|
use Trinket::Directory::FilterParser; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
134
|
|
59
|
1
|
|
|
1
|
|
1061
|
use Bit::Vector::Overload; |
|
1
|
|
|
|
|
15797
|
|
|
1
|
|
|
|
|
89
|
|
60
|
1
|
|
|
1
|
|
13
|
use Storable qw( thaw freeze ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
97
|
|
61
|
1
|
|
|
1
|
|
1046
|
use MIME::Base64 qw(encode_base64 decode_base64); |
|
1
|
|
|
|
|
882
|
|
|
1
|
|
|
|
|
124
|
|
62
|
1
|
|
|
1
|
|
7
|
use Carp qw( confess croak cluck ); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
78
|
|
63
|
1
|
|
|
1
|
|
7
|
use Data::Dumper qw( Dumper ); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
115
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
Bit::Vector->Configuration("out=bin"); |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
### Class-global collection of directories. |
68
|
|
|
|
|
|
|
our %DIRS = (); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# {{{ METHODS |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=head1 METHODS |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=over 4 |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=cut |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# }}} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# {{{ init(): Object initializer |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=item init({...}) |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
TODO |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=cut |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub init |
89
|
|
|
|
|
|
|
{ |
90
|
1
|
|
|
1
|
|
6
|
no strict 'refs'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
3406
|
|
91
|
6
|
|
|
6
|
1
|
13
|
my ($self, $props) = @_; |
92
|
|
|
|
|
|
|
|
93
|
6
|
|
|
|
|
23
|
$self->{directory} = undef; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
return |
96
|
6
|
|
|
|
|
17
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# }}} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# {{{ create() |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=item $dir->create($params) |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
Create a new object directory, destroys any existing directory |
105
|
|
|
|
|
|
|
associated with the given parameters. |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=cut |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub create |
110
|
|
|
|
|
|
|
{ |
111
|
1
|
|
|
1
|
1
|
3
|
my ($self, $name, $params) = @_; |
112
|
|
|
|
|
|
|
|
113
|
1
|
|
|
|
|
3
|
$self->{dir_name} = $name; |
114
|
|
|
|
|
|
|
|
115
|
1
|
|
|
|
|
10
|
my $dir_name = $self->{dir_name}; |
116
|
1
|
|
|
|
|
7
|
$DIRS{$dir_name} = |
117
|
|
|
|
|
|
|
{ |
118
|
|
|
|
|
|
|
created => 1, |
119
|
|
|
|
|
|
|
objects => [], |
120
|
|
|
|
|
|
|
indices => {} |
121
|
|
|
|
|
|
|
}; |
122
|
1
|
|
|
|
|
3
|
$self->{directory} = $DIRS{$dir_name}; |
123
|
1
|
50
|
|
|
|
5
|
$self->{save_file} = $params->{file} if $params->{file}; |
124
|
|
|
|
|
|
|
|
125
|
1
|
|
|
|
|
4
|
return 1; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# }}} |
129
|
|
|
|
|
|
|
# {{{ open() |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=item $dir->open($params) |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
TODO |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=cut |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub open |
138
|
|
|
|
|
|
|
{ |
139
|
5
|
|
|
5
|
1
|
12
|
my ($self, $dir_name, $params) = @_; |
140
|
|
|
|
|
|
|
|
141
|
5
|
50
|
|
|
|
17
|
$self->{save_file} = $params->{file} if $params->{file}; |
142
|
5
|
|
|
|
|
15
|
$self->{dir_name} = $dir_name; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
### Load save file |
145
|
5
|
50
|
|
|
|
17
|
if (defined $self->{save_file}) |
146
|
|
|
|
|
|
|
{ |
147
|
0
|
|
|
|
|
0
|
local *FIN; |
148
|
0
|
|
|
|
|
0
|
local $/; undef $/; |
|
0
|
|
|
|
|
0
|
|
149
|
0
|
0
|
|
|
|
0
|
open (FIN, $self->{save_file}) || |
150
|
|
|
|
|
|
|
die "Could not open ".$self->{save_file}.": $!"; |
151
|
0
|
|
|
|
|
0
|
my $serial = ; |
152
|
0
|
|
|
|
|
0
|
close (FIN); |
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
0
|
$DIRS{$self->{dir_name}} = thaw(decode_base64($serial)); |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
5
|
100
|
|
|
|
46
|
return undef if ($DIRS{$dir_name}->{created} ne 1); |
158
|
|
|
|
|
|
|
|
159
|
3
|
|
|
|
|
8
|
$self->{directory} = $DIRS{$dir_name}; |
160
|
3
|
50
|
|
|
|
11
|
$self->{cache_objects} && $self->clear_cache(); |
161
|
|
|
|
|
|
|
|
162
|
3
|
|
|
|
|
14
|
return 1; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# }}} |
166
|
|
|
|
|
|
|
# {{{ close() |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=item $dir->close($params) |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
TODO |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=cut |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub close { |
175
|
2
|
|
|
2
|
1
|
6
|
my ($self, $params) = @_; |
176
|
|
|
|
|
|
|
|
177
|
2
|
50
|
|
|
|
9
|
if (defined $self->{save_file}) { |
178
|
0
|
|
|
|
|
0
|
my $serial = $self->serialize(); |
179
|
0
|
|
|
|
|
0
|
local *FOUT; |
180
|
0
|
0
|
|
|
|
0
|
open (FOUT, "> ".$self->{save_file}) || |
181
|
|
|
|
|
|
|
die "Could not open ".$self->{save_file}.": $!"; |
182
|
0
|
|
|
|
|
0
|
print FOUT $serial; |
183
|
0
|
|
|
|
|
0
|
close (FOUT); |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
2
|
|
|
|
|
5
|
return 1; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# }}} |
190
|
|
|
|
|
|
|
# {{{ serialize() |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub serialize { |
193
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
194
|
|
|
|
|
|
|
#return Dumper($DIRS{$self->{dir_name}}); |
195
|
0
|
|
|
|
|
0
|
return encode_base64(freeze($DIRS{$self->{dir_name}})); |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# }}} |
199
|
|
|
|
|
|
|
# {{{ deserialize() |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub deserialize { |
202
|
0
|
|
|
0
|
0
|
0
|
my ($self, $data) = @_; |
203
|
|
|
|
|
|
|
|
204
|
0
|
|
|
|
|
0
|
eval { |
205
|
|
|
|
|
|
|
#my $VAR1; |
206
|
|
|
|
|
|
|
#eval $data; |
207
|
|
|
|
|
|
|
#$DIRS{$self->{dir_name}} = $VAR1; |
208
|
0
|
|
|
|
|
0
|
$DIRS{$self->{dir_name}} = thaw(decode_base64($data)); |
209
|
0
|
|
|
|
|
0
|
$self->{directory} = $DIRS{$self->{dir_name}}; |
210
|
|
|
|
|
|
|
}; |
211
|
0
|
0
|
|
|
|
0
|
if ($@) { |
212
|
0
|
|
|
|
|
0
|
return undef; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
0
|
|
|
|
|
0
|
return 1; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# }}} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# {{{ store_object(): |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub store_object { |
223
|
106
|
|
|
106
|
0
|
161
|
my ($self, $obj) = @_; |
224
|
|
|
|
|
|
|
|
225
|
106
|
|
|
|
|
162
|
my ($serialized, $dirty, $dirty_name, $dirty_vals, $dirty_old, |
226
|
|
|
|
|
|
|
$dirty_new, $id, $dir, $is_new); |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
### Get the object's id |
229
|
106
|
|
|
|
|
328
|
$id = $obj->get_id(); |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
### Check if this is an attempt to store an object with the id of |
232
|
|
|
|
|
|
|
### an object which has been previously deleted. If so, undefine |
233
|
|
|
|
|
|
|
### the object's id and proceed. |
234
|
106
|
100
|
66
|
|
|
420
|
if ( (defined $id) && ( $self->is_deleted_id($id) ) ) |
235
|
1
|
|
|
|
|
3
|
{ $obj->set_id($id = undef); } |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
### Does this object have an id? If not, give it one. |
238
|
106
|
|
|
|
|
190
|
$is_new = 0; |
239
|
106
|
50
|
|
|
|
436
|
if (!defined $id) { |
240
|
106
|
|
|
|
|
504
|
$obj->set_id($id = $self->get_new_id()); |
241
|
106
|
|
|
|
|
421
|
$is_new = 1; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
106
|
|
|
|
|
209
|
eval { |
245
|
|
|
|
|
|
|
### HACK: We don't want to serialize the directory. Actually, |
246
|
|
|
|
|
|
|
### there are a lot of things we don't want to serialize. Will |
247
|
|
|
|
|
|
|
### have to find a way to handle this cleanly |
248
|
|
|
|
|
|
|
#$obj->set_directory(undef); |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
### Serialize and store the object. |
251
|
106
|
|
|
|
|
422
|
foreach my $prop_name ($obj->list_properties()) { |
252
|
954
|
|
|
|
|
2888
|
$obj->get($prop_name); |
253
|
|
|
|
|
|
|
} |
254
|
106
|
|
|
|
|
624
|
$self->{directory}->{objects}->[$id] = $obj; |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
### Update dirty indexes... |
257
|
106
|
50
|
|
|
|
496
|
if ($dirty = $obj->_find_dirty_indices()) { |
258
|
106
|
|
|
|
|
203
|
while (($dirty_name, $dirty_vals) = each %{$dirty}) { |
|
741
|
|
|
|
|
4212
|
|
259
|
635
|
|
|
|
|
1967
|
($dirty_old, $dirty_new) = |
260
|
|
|
|
|
|
|
($dirty_vals->[DIRTY_OLD_VALUE], |
261
|
|
|
|
|
|
|
$dirty_vals->[DIRTY_NEW_VALUE]); |
262
|
|
|
|
|
|
|
|
263
|
635
|
100
|
|
|
|
1491
|
if ($dirty_old) |
264
|
3
|
|
|
|
|
11
|
{ $self->delete_from_index($id, $dirty_name, $dirty_old); } |
265
|
635
|
|
|
|
|
1873
|
$self->store_in_index($id, $dirty_name, $dirty_new); |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
}; |
269
|
|
|
|
|
|
|
|
270
|
106
|
50
|
|
|
|
273
|
if ($@) { |
271
|
0
|
|
|
|
|
0
|
confess ($@); |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
106
|
50
|
|
|
|
238
|
if ($is_new) { |
275
|
106
|
|
|
|
|
528
|
my @parent_classes = $obj->_derive_ancestry(); |
276
|
106
|
|
|
|
|
441
|
foreach my $class (@parent_classes) { |
277
|
318
|
|
|
|
|
898
|
$self->store_in_index($id, 'class', $class); |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
### Storage failure. Recover, fire a warning, and return |
282
|
|
|
|
|
|
|
### empty-handed. (croaking now, should cluck.) |
283
|
106
|
50
|
|
|
|
296
|
if ($@) |
284
|
0
|
|
|
|
|
0
|
{ croak ($@); return undef; } |
|
0
|
|
|
|
|
0
|
|
285
|
|
|
|
|
|
|
|
286
|
106
|
|
|
|
|
1218
|
return $id; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# }}} |
290
|
|
|
|
|
|
|
# {{{ retrieve_object(): |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub retrieve_object |
293
|
|
|
|
|
|
|
{ |
294
|
28
|
|
|
28
|
0
|
52
|
my ($self, $id) = @_; |
295
|
28
|
|
|
|
|
154
|
return $self->{directory}->{objects}->[$id]; |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# }}} |
299
|
|
|
|
|
|
|
# {{{ delete_object |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
sub delete_object |
302
|
|
|
|
|
|
|
{ |
303
|
5
|
|
|
5
|
0
|
10
|
my ($self, $id, $obj) = @_; |
304
|
|
|
|
|
|
|
|
305
|
5
|
|
|
|
|
16
|
$self->{directory}->{objects}->[$id] = undef; |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
### Delete all indexes for this object's properties |
308
|
|
|
|
|
|
|
#my $name; |
309
|
|
|
|
|
|
|
#foreach $name ($obj->list_properties()) |
310
|
|
|
|
|
|
|
# { $self->delete_from_index($id, $name); } |
311
|
|
|
|
|
|
|
|
312
|
5
|
|
|
|
|
14
|
return 1; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
# }}} |
316
|
|
|
|
|
|
|
# {{{ search_objects |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
### Define a mapping of search filter LoL node names to methods |
319
|
|
|
|
|
|
|
my %op_methods = |
320
|
|
|
|
|
|
|
( |
321
|
|
|
|
|
|
|
'AND' => '_search_join_op', |
322
|
|
|
|
|
|
|
'OR' => '_search_join_op', |
323
|
|
|
|
|
|
|
'NOT' => '_search_join_op', |
324
|
|
|
|
|
|
|
'EQ' => '_search_leaf_op', |
325
|
|
|
|
|
|
|
'APPROX' => '_search_leaf_op', |
326
|
|
|
|
|
|
|
'GT' => '_search_leaf_op', |
327
|
|
|
|
|
|
|
'GE' => '_search_leaf_op', |
328
|
|
|
|
|
|
|
'LT' => '_search_leaf_op', |
329
|
|
|
|
|
|
|
'LE' => '_search_leaf_op', |
330
|
|
|
|
|
|
|
); |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
sub search_objects |
333
|
|
|
|
|
|
|
{ |
334
|
15
|
|
|
15
|
0
|
22
|
my ($self, $parsed) = @_; |
335
|
|
|
|
|
|
|
|
336
|
15
|
|
|
|
|
39
|
my ($op, $operand) = ($parsed->[SEARCH_OP], $parsed->[SEARCH_OPERAND]); |
337
|
|
|
|
|
|
|
|
338
|
15
|
|
50
|
|
|
53
|
my $op_method = $op_methods{$op} || die "No '$op' method!"; |
339
|
|
|
|
|
|
|
|
340
|
15
|
50
|
33
|
|
|
73
|
cluck('Bad filter') if ( (!defined $op) || (!defined $operand) ); |
341
|
|
|
|
|
|
|
|
342
|
15
|
|
|
|
|
133
|
my ($result) = $self->$op_method($op, $operand); |
343
|
|
|
|
|
|
|
|
344
|
15
|
|
|
|
|
191
|
return $result->Index_List_Read(); |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
# }}} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
# {{{ _search_join_op |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
my %_search_join_subs = |
352
|
|
|
|
|
|
|
( |
353
|
|
|
|
|
|
|
AND => sub |
354
|
|
|
|
|
|
|
{ |
355
|
|
|
|
|
|
|
my $result_vec = shift; |
356
|
|
|
|
|
|
|
while(@_) { |
357
|
|
|
|
|
|
|
my $sub_vec = shift; |
358
|
|
|
|
|
|
|
my $tmp_vec = $result_vec->Shadow(); |
359
|
|
|
|
|
|
|
$tmp_vec->Intersection($result_vec, $sub_vec); |
360
|
|
|
|
|
|
|
$result_vec = $tmp_vec; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
return $result_vec; |
363
|
|
|
|
|
|
|
}, |
364
|
|
|
|
|
|
|
OR => sub |
365
|
|
|
|
|
|
|
{ |
366
|
|
|
|
|
|
|
my $result_vec = shift; |
367
|
|
|
|
|
|
|
while(@_) { |
368
|
|
|
|
|
|
|
my $sub_vec = shift; |
369
|
|
|
|
|
|
|
my $tmp_vec = $result_vec->Shadow(); |
370
|
|
|
|
|
|
|
$tmp_vec->Union($result_vec, $sub_vec); |
371
|
|
|
|
|
|
|
$result_vec = $tmp_vec; |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
return $result_vec; |
374
|
|
|
|
|
|
|
}, |
375
|
|
|
|
|
|
|
NOT => sub |
376
|
|
|
|
|
|
|
{ |
377
|
|
|
|
|
|
|
my $result_vec = shift; |
378
|
|
|
|
|
|
|
my $tmp_vec = $result_vec->Shadow(); |
379
|
|
|
|
|
|
|
$tmp_vec->Complement($result_vec); |
380
|
|
|
|
|
|
|
return $tmp_vec; |
381
|
|
|
|
|
|
|
}, |
382
|
|
|
|
|
|
|
); |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
sub _search_join_op |
385
|
|
|
|
|
|
|
{ |
386
|
9
|
|
|
9
|
|
17
|
my ($self, $op, $operand) = @_; |
387
|
|
|
|
|
|
|
|
388
|
9
|
|
|
|
|
15
|
my $result; |
389
|
9
|
|
|
|
|
11
|
my ($i, $sub_op, $sub_operand, $sub_op_method, $sub_result); |
390
|
9
|
|
|
|
|
14
|
my @sub_results = (); |
391
|
|
|
|
|
|
|
|
392
|
9
|
|
|
|
|
23
|
my $id_range = $self->get_id_range(); |
393
|
|
|
|
|
|
|
|
394
|
9
|
|
|
|
|
31
|
for (my $i=0; $i<@$operand; $i+=2) |
395
|
|
|
|
|
|
|
{ |
396
|
18
|
|
|
|
|
42
|
($sub_op, $sub_operand) = |
397
|
|
|
|
|
|
|
($operand->[SEARCH_OP + $i], $operand->[SEARCH_OPERAND + $i]); |
398
|
|
|
|
|
|
|
|
399
|
18
|
|
50
|
|
|
57
|
$sub_op_method = $op_methods{$sub_op} || |
400
|
|
|
|
|
|
|
die "No '$sub_op' method!"; |
401
|
18
|
|
|
|
|
55
|
$sub_result = $self->$sub_op_method($sub_op, $sub_operand); |
402
|
|
|
|
|
|
|
|
403
|
18
|
|
|
|
|
59
|
push @sub_results, $sub_result; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
9
|
|
|
|
|
30
|
my $result_vec = $_search_join_subs{$op}->(@sub_results); |
407
|
|
|
|
|
|
|
|
408
|
9
|
|
|
|
|
58
|
return $result_vec; |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# }}} |
412
|
|
|
|
|
|
|
# {{{ _search_leaf_op |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
my %_search_leaf_subs = |
415
|
|
|
|
|
|
|
( |
416
|
|
|
|
|
|
|
'EQ' => sub { |
417
|
|
|
|
|
|
|
my ($index, $val) = @_; |
418
|
|
|
|
|
|
|
my @ids; |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
### Get all ids whose value is equal to the given value. |
421
|
|
|
|
|
|
|
if ($val eq '*') { |
422
|
|
|
|
|
|
|
foreach my $k1 (keys %{$index}) |
423
|
|
|
|
|
|
|
{ push @ids, keys %{$index->{$k1}}; } |
424
|
|
|
|
|
|
|
} else { |
425
|
|
|
|
|
|
|
@ids = keys %{$index->{$val}}; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
return \@ids; |
429
|
|
|
|
|
|
|
}, |
430
|
|
|
|
|
|
|
'APPROX' => sub |
431
|
|
|
|
|
|
|
{ |
432
|
|
|
|
|
|
|
my ($index, $val) = @_; |
433
|
|
|
|
|
|
|
my @ids; |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
return \@ids; |
436
|
|
|
|
|
|
|
}, |
437
|
|
|
|
|
|
|
'GT' => sub |
438
|
|
|
|
|
|
|
{ |
439
|
|
|
|
|
|
|
my ($index, $val) = @_; |
440
|
|
|
|
|
|
|
my @ids; |
441
|
|
|
|
|
|
|
foreach my $k (keys %$index) |
442
|
|
|
|
|
|
|
{ push @ids, keys %{$index->{$k}} if ($val < $k); } |
443
|
|
|
|
|
|
|
return \@ids; |
444
|
|
|
|
|
|
|
}, |
445
|
|
|
|
|
|
|
'GE' => sub |
446
|
|
|
|
|
|
|
{ |
447
|
|
|
|
|
|
|
my ($index, $val) = @_; |
448
|
|
|
|
|
|
|
my @ids; |
449
|
|
|
|
|
|
|
foreach my $k (keys %$index) |
450
|
|
|
|
|
|
|
{ push @ids, keys %{$index->{$k}} if ($val <= $k); } |
451
|
|
|
|
|
|
|
return \@ids; |
452
|
|
|
|
|
|
|
}, |
453
|
|
|
|
|
|
|
'LT' => sub |
454
|
|
|
|
|
|
|
{ |
455
|
|
|
|
|
|
|
my ($index, $val) = @_; |
456
|
|
|
|
|
|
|
my @ids; |
457
|
|
|
|
|
|
|
foreach my $k (keys %$index) |
458
|
|
|
|
|
|
|
{ push @ids, keys %{$index->{$k}} if ($val > $k); } |
459
|
|
|
|
|
|
|
return \@ids; |
460
|
|
|
|
|
|
|
}, |
461
|
|
|
|
|
|
|
'LE' => sub |
462
|
|
|
|
|
|
|
{ |
463
|
|
|
|
|
|
|
my ($index, $val) = @_; |
464
|
|
|
|
|
|
|
my @ids; |
465
|
|
|
|
|
|
|
foreach my $k (keys %$index) |
466
|
|
|
|
|
|
|
{ push @ids, keys %{$index->{$k}} if ($val >= $k); } |
467
|
|
|
|
|
|
|
return \@ids; |
468
|
|
|
|
|
|
|
}, |
469
|
|
|
|
|
|
|
); |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
sub _search_leaf_op |
472
|
|
|
|
|
|
|
{ |
473
|
24
|
|
|
24
|
|
40
|
my ($self, $op, $operand) = @_; |
474
|
|
|
|
|
|
|
|
475
|
24
|
|
|
|
|
33
|
my $result; |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
### Assert that this is an operation taking two string nodes |
478
|
24
|
50
|
33
|
|
|
122
|
if ( ($operand->[0] ne "STRING") || ($operand->[2] ne "STRING") ) |
479
|
|
|
|
|
|
|
{ |
480
|
0
|
|
|
|
|
0
|
cluck("Bad or unimplemented filter format"); |
481
|
0
|
|
|
|
|
0
|
return undef; |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
24
|
|
|
|
|
49
|
my ($name, $val) = ($operand->[1], $operand->[3]); |
485
|
|
|
|
|
|
|
|
486
|
24
|
|
|
|
|
53
|
my $id_range = $self->get_id_range(); |
487
|
24
|
|
|
|
|
142
|
my $result = new Bit::Vector($id_range); |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
### Grab a reference to the named index. |
490
|
24
|
|
|
|
|
60
|
my $index = $self->{directory}->{indices}->{$name}; |
491
|
|
|
|
|
|
|
|
492
|
24
|
|
|
|
|
70
|
my $ids = $_search_leaf_subs{$op}->($index, $val); |
493
|
|
|
|
|
|
|
|
494
|
24
|
|
|
|
|
231
|
$result->Index_List_Store(@$ids); |
495
|
|
|
|
|
|
|
|
496
|
24
|
|
|
|
|
117
|
return $result; |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
# }}} |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
# {{{ is_ready(): |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
sub is_ready |
504
|
|
|
|
|
|
|
{ |
505
|
667
|
|
|
667
|
0
|
891
|
my $self = shift; |
506
|
|
|
|
|
|
|
|
507
|
667
|
100
|
|
|
|
1993
|
return undef if (!defined $self->{directory}); |
508
|
|
|
|
|
|
|
|
509
|
665
|
|
|
|
|
3102
|
return ( $self->{directory}->{created} eq 1 ); |
510
|
|
|
|
|
|
|
} |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
# }}} |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
# {{{ get_new_id(): |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
sub get_new_id |
517
|
|
|
|
|
|
|
{ |
518
|
106
|
|
|
106
|
0
|
219
|
my $self = shift; |
519
|
|
|
|
|
|
|
|
520
|
106
|
|
|
|
|
145
|
return scalar(@{$self->{directory}->{objects}}); |
|
106
|
|
|
|
|
498
|
|
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
# }}} |
524
|
|
|
|
|
|
|
# {{{ is_deleted_id(): |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
sub is_deleted_id |
527
|
|
|
|
|
|
|
{ |
528
|
1
|
|
|
1
|
0
|
3
|
my ($self, $id) = @_; |
529
|
|
|
|
|
|
|
|
530
|
1
|
|
33
|
|
|
12
|
return ( exists ($self->{directory}->{objects}->[$id]) && |
531
|
|
|
|
|
|
|
!defined ($self->{directory}->{objects}->[$id]) ); |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
# }}} |
535
|
|
|
|
|
|
|
# {{{ get_id_range() |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
sub get_id_range |
538
|
|
|
|
|
|
|
{ |
539
|
33
|
|
|
33
|
0
|
48
|
my $self = shift; |
540
|
|
|
|
|
|
|
|
541
|
33
|
|
|
|
|
39
|
return scalar(@{$self->{directory}->{objects}}); |
|
33
|
|
|
|
|
92
|
|
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
# }}} |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
# {{{ index_exists() |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
sub index_exists |
549
|
|
|
|
|
|
|
{ |
550
|
956
|
|
|
956
|
0
|
1799
|
my ($self, $name) = @_; |
551
|
|
|
|
|
|
|
|
552
|
956
|
|
|
|
|
4313
|
return ( defined ( $self->{directory}->{indices}->{$name} ) ); |
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
# }}} |
556
|
|
|
|
|
|
|
# {{{ create_index() |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
sub create_index |
559
|
|
|
|
|
|
|
{ |
560
|
7
|
|
|
7
|
0
|
11
|
my ($self, $name) = @_; |
561
|
|
|
|
|
|
|
|
562
|
7
|
|
|
|
|
18
|
$self->{directory}->{indices}->{$name} = {}; |
563
|
|
|
|
|
|
|
|
564
|
7
|
|
|
|
|
13
|
return 1; |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
# }}} |
568
|
|
|
|
|
|
|
# {{{ delete_from_index() |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
sub delete_from_index { |
571
|
3
|
|
|
3
|
0
|
10
|
my ($self, $id, $name, $value) = @_; |
572
|
|
|
|
|
|
|
|
573
|
3
|
50
|
|
|
|
10
|
return undef if (!$self->index_exists($name)); |
574
|
|
|
|
|
|
|
|
575
|
3
|
|
|
|
|
9
|
my $name_index = $self->{directory}->{indices}->{$name}; |
576
|
|
|
|
|
|
|
|
577
|
3
|
50
|
|
|
|
10
|
if (defined $value) { |
578
|
3
|
|
|
|
|
12
|
delete $name_index->{$value}->{$id}; |
579
|
3
|
|
|
|
|
18
|
delete $name_index->{$value} |
580
|
3
|
50
|
|
|
|
5
|
if (! keys(%{$name_index->{$value}}) ); |
581
|
|
|
|
|
|
|
} else { |
582
|
0
|
|
|
|
|
0
|
foreach $value ( keys %{$name_index} ) { |
|
0
|
|
|
|
|
0
|
|
583
|
0
|
0
|
|
|
|
0
|
delete $name_index->{$value}->{$id} |
584
|
|
|
|
|
|
|
if ($name_index->{$value}->{$id}); |
585
|
0
|
0
|
|
|
|
0
|
if (! keys(%{$name_index->{$value}}) ) { |
|
0
|
|
|
|
|
0
|
|
586
|
0
|
|
|
|
|
0
|
delete $name_index->{$value}; |
587
|
0
|
|
|
|
|
0
|
last; |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# }}} |
594
|
|
|
|
|
|
|
# {{{ store_in_index() |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
sub store_in_index |
597
|
|
|
|
|
|
|
{ |
598
|
953
|
|
|
953
|
0
|
2232
|
my ($self, $id, $name, $value) = @_; |
599
|
|
|
|
|
|
|
|
600
|
953
|
100
|
|
|
|
2451
|
$self->create_index($name) |
601
|
|
|
|
|
|
|
if (!$self->index_exists($name)); |
602
|
|
|
|
|
|
|
|
603
|
953
|
|
|
|
|
5027
|
$self->{directory}->{indices}->{$name}->{$value}->{$id} = 1; |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
# }}} |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
# {{{ DESTROY |
609
|
|
|
|
|
|
|
|
610
|
0
|
|
|
0
|
|
|
sub DESTROY { |
611
|
|
|
|
|
|
|
## no-op to pacify warnings |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
# }}} |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
# {{{ End POD |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
=back |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
=head1 AUTHOR |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
Maintained by Leslie Michael Orchard > |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
=head1 COPYRIGHT |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
Copyright (c) 2000, Leslie Michael Orchard. All Rights Reserved. |
628
|
|
|
|
|
|
|
This module is free software; you can redistribute it and/or |
629
|
|
|
|
|
|
|
modify it under the same terms as Perl itself. |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
=cut |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
# }}} |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
1; |
636
|
|
|
|
|
|
|
__END__ |