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