Got arrays working, requiring that make_reference and clone be added and functional
[dbsrgits/DBM-Deep.git] / lib / DBM / Deep / Engine / DBI.pm
CommitLineData
2c70efe1 1package DBM::Deep::Engine::DBI;
2
3use 5.006_000;
4
5use strict;
6use warnings FATAL => 'all';
7
8use base 'DBM::Deep::Engine';
9
d6ecf579 10use DBM::Deep::Sector::DBI ();
11use DBM::Deep::Storage::DBI ();
12
13sub sector_type { 'DBM::Deep::Sector::DBI' }
19b913ce 14sub iterator_class { 'DBM::Deep::Iterator::DBI' }
d6ecf579 15
a4d36ff6 16sub new {
17 my $class = shift;
18 my ($args) = @_;
19
20 $args->{storage} = DBM::Deep::Storage::DBI->new( $args )
21 unless exists $args->{storage};
22
23 my $self = bless {
24 storage => undef,
25 }, $class;
26
27 # Grab the parameters we want to use
28 foreach my $param ( keys %$self ) {
29 next unless exists $args->{$param};
30 $self->{$param} = $args->{$param};
31 }
32
33 return $self;
34}
35
36sub setup {
37 my $self = shift;
38 my ($obj) = @_;
39
40 # Default the id to 1. This means that we will be creating a row if there
41 # isn't one. The assumption is that the row_id=1 cannot never be deleted. I
42 # don't know if this is a good assumption.
43 $obj->{base_offset} ||= 1;
44
45 my ($rows) = $self->storage->read_from(
46 refs => $obj->_base_offset,
47 qw( ref_type ),
48 );
49
50 # We don't have a row yet.
51 unless ( @$rows ) {
52 $self->storage->write_to(
53 refs => $obj->_base_offset,
54 ref_type => $obj->_type,
55 );
56 }
57
58 my $sector = DBM::Deep::Sector::DBI::Reference->new({
59 engine => $self,
60 offset => $obj->_base_offset,
61 });
62}
d6ecf579 63
2c70efe1 64sub read_value {
65 my $self = shift;
66 my ($obj, $key) = @_;
a4d36ff6 67
68 my $sector = $self->load_sector( $obj->_base_offset, 'refs' )
69 or return;
70
71# if ( $sector->staleness != $obj->_staleness ) {
72# return;
73# }
74
75# my $key_md5 = $self->_apply_digest( $key );
76
77 my $value_sector = $sector->get_data_for({
78 key => $key,
79# key_md5 => $key_md5,
80 allow_head => 1,
81 });
82
83 unless ( $value_sector ) {
84 $value_sector = DBM::Deep::Sector::DBI::Scalar->new({
85 engine => $self,
86 data => undef,
87 });
88
89 $sector->write_data({
90# key_md5 => $key_md5,
91 key => $key,
92 value => $value_sector,
93 });
94 }
95
96 return $value_sector->data;
2c70efe1 97}
98
99sub get_classname {
100 my $self = shift;
101 my ($obj) = @_;
350896ee 102
103 return;
2c70efe1 104}
105
106sub make_reference {
107 my $self = shift;
108 my ($obj, $old_key, $new_key) = @_;
641aa32d 109
110 my $sector = $self->load_sector( $obj->_base_offset, 'refs' )
111 or return;
112
113# if ( $sector->staleness != $obj->_staleness ) {
114# return;
115# }
116
117 my $value_sector = $sector->get_data_for({
118 key => $old_key,
119 allow_head => 1,
120 });
121
122 unless ( $value_sector ) {
123 $value_sector = DBM::Deep::Sector::DBI::Scalar->new({
124 engine => $self,
125 data => undef,
126 });
127
128 $sector->write_data({
129 key => $old_key,
130 value => $value_sector,
131 });
132 }
133
134 if ( $value_sector->isa( 'DBM::Deep::Sector::DBI::Reference' ) ) {
135 $sector->write_data({
136 key => $new_key,
137 value => $value_sector,
138 });
139 $value_sector->increment_refcount;
140 }
141 else {
142 $sector->write_data({
143 key => $new_key,
144 value => $value_sector->clone,
145 });
146 }
147
148 return;
2c70efe1 149}
150
a4d36ff6 151# exists returns '', not undefined.
2c70efe1 152sub key_exists {
153 my $self = shift;
154 my ($obj, $key) = @_;
a4d36ff6 155
156 my $sector = $self->load_sector( $obj->_base_offset, 'refs' )
157 or return '';
158
159# if ( $sector->staleness != $obj->_staleness ) {
160# return '';
161# }
162
163 my $data = $sector->get_data_for({
164# key_md5 => $self->_apply_digest( $key ),
165 key => $key,
166 allow_head => 1,
167 });
168
169 # exists() returns 1 or '' for true/false.
170 return $data ? 1 : '';
2c70efe1 171}
172
173sub delete_key {
174 my $self = shift;
175 my ($obj, $key) = @_;
a4d36ff6 176
177 my $sector = $self->load_sector( $obj->_base_offset, 'refs' )
178 or return '';
179
180# if ( $sector->staleness != $obj->_staleness ) {
181# return '';
182# }
183
184 return $sector->delete_key({
185# key_md5 => $self->_apply_digest( $key ),
186 key => $key,
187 allow_head => 0,
188 });
2c70efe1 189}
190
191sub write_value {
192 my $self = shift;
193 my ($obj, $key, $value) = @_;
194
195 my $r = Scalar::Util::reftype( $value ) || '';
196 {
197 last if $r eq '';
198 last if $r eq 'HASH';
199 last if $r eq 'ARRAY';
200
201 DBM::Deep->_throw_error(
202 "Storage of references of type '$r' is not supported."
203 );
204 }
205
206 # Load the reference entry
207 # Determine if the row was deleted under us
208 #
209
a4d36ff6 210 my $sector = $self->load_sector( $obj->_base_offset, 'refs' )
211 or die "Cannot load sector at '@{[$obj->_base_offset]}'\n";;
212
213 my ($type, $class);
2c70efe1 214 if ( $r eq 'ARRAY' || $r eq 'HASH' ) {
215 my $tmpvar;
216 if ( $r eq 'ARRAY' ) {
217 $tmpvar = tied @$value;
218 } elsif ( $r eq 'HASH' ) {
219 $tmpvar = tied %$value;
220 }
221
222 if ( $tmpvar ) {
223 my $is_dbm_deep = eval { local $SIG{'__DIE__'}; $tmpvar->isa( 'DBM::Deep' ); };
224
225 unless ( $is_dbm_deep ) {
226 DBM::Deep->_throw_error( "Cannot store something that is tied." );
227 }
228
229 unless ( $tmpvar->_engine->storage == $self->storage ) {
230 DBM::Deep->_throw_error( "Cannot store values across DBM::Deep files. Please use export() instead." );
231 }
232
233 # Load $tmpvar's sector
234
235 # First, verify if we're storing the same thing to this spot. If we
236 # are, then this should be a no-op. -EJS, 2008-05-19
237
238 # See whether or not we are storing ourselves to ourself.
239 # Write the sector as data in this reference (keyed by $key)
a4d36ff6 240 my $value_sector = $self->load_sector( $tmpvar->_base_offset );
241 $sector->write_data({
242 key => $key,
243 key_md5 => $self->_apply_digest( $key ),
244 value => $value_sector,
245 });
2c70efe1 246 $value_sector->increment_refcount;
247
248 return 1;
249 }
250
251 $type = substr( $r, 0, 1 );
a4d36ff6 252 $class = 'DBM::Deep::Sector::DBI::Reference';
2c70efe1 253 }
254 else {
255 if ( tied($value) ) {
256 DBM::Deep->_throw_error( "Cannot store something that is tied." );
257 }
a4d36ff6 258
259 $class = 'DBM::Deep::Sector::DBI::Scalar';
260 $type = 'S';
2c70efe1 261 }
262
a4d36ff6 263 # Create this after loading the reference sector in case something bad
264 # happens. This way, we won't allocate value sector(s) needlessly.
265 my $value_sector = $class->new({
266 engine => $self,
267 data => $value,
268 type => $type,
269 });
270
271 $sector->write_data({
272 key => $key,
273# key_md5 => $self->_apply_digest( $key ),
274 value => $value_sector,
275 });
276
2c70efe1 277 # This code is to make sure we write all the values in the $value to the
278 # disk and to make sure all changes to $value after the assignment are
279 # reflected on disk. This may be counter-intuitive at first, but it is
280 # correct dwimmery.
281 # NOTE - simply tying $value won't perform a STORE on each value. Hence,
282 # the copy to a temp value.
283 if ( $r eq 'ARRAY' ) {
284 my @temp = @$value;
285 tie @$value, 'DBM::Deep', {
286 base_offset => $value_sector->offset,
a4d36ff6 287# staleness => $value_sector->staleness,
2c70efe1 288 storage => $self->storage,
289 engine => $self,
290 };
291 @$value = @temp;
292 bless $value, 'DBM::Deep::Array' unless Scalar::Util::blessed( $value );
293 }
294 elsif ( $r eq 'HASH' ) {
295 my %temp = %$value;
296 tie %$value, 'DBM::Deep', {
297 base_offset => $value_sector->offset,
a4d36ff6 298# staleness => $value_sector->staleness,
2c70efe1 299 storage => $self->storage,
300 engine => $self,
301 };
302
303 %$value = %temp;
304 bless $value, 'DBM::Deep::Hash' unless Scalar::Util::blessed( $value );
305 }
306
307 return 1;
308}
309
2c70efe1 310sub begin_work {
311 my $self = shift;
312 my ($obj) = @_;
313}
314
315sub rollback {
316 my $self = shift;
317 my ($obj) = @_;
318}
319
320sub commit {
321 my $self = shift;
322 my ($obj) = @_;
323}
324
325
3261;
327__END__