Removed lava in DBM::Deep::File
[dbsrgits/DBM-Deep.git] / lib / DBM / Deep / File.pm
CommitLineData
460b1067 1package DBM::Deep::File;
2
3use 5.6.0;
4
5use strict;
6use warnings;
7
c3aafc14 8our $VERSION = q(0.99_03);
460b1067 9
86867f3a 10use Fcntl qw( :DEFAULT :flock :seek );
460b1067 11
12sub new {
13 my $class = shift;
14 my ($args) = @_;
15
16 my $self = bless {
359a01ac 17 autobless => 1,
460b1067 18 autoflush => undef,
19 end => 0,
20 fh => undef,
21 file => undef,
22 file_offset => 0,
23 locking => undef,
24 locked => 0,
25 filter_store_key => undef,
26 filter_store_value => undef,
27 filter_fetch_key => undef,
28 filter_fetch_value => undef,
29 }, $class;
30
31 # Grab the parameters we want to use
32 foreach my $param ( keys %$self ) {
33 next unless exists $args->{$param};
34 $self->{$param} = $args->{$param};
35 }
36
37 if ( $self->{fh} && !$self->{file_offset} ) {
38 $self->{file_offset} = tell( $self->{fh} );
39 }
40
41 $self->open unless $self->{fh};
42
43 return $self;
44}
45
46sub open {
47 my $self = shift;
48
633df1fd 49 # Adding O_BINARY should remove the need for the binmode below. However,
460b1067 50 # I'm not going to remove it because I don't have the Win32 chops to be
51 # absolutely certain everything will be ok.
52 my $flags = O_RDWR | O_CREAT | O_BINARY;
53
54 my $fh;
55 sysopen( $fh, $self->{file}, $flags )
56 or die "DBM::Deep: Cannot sysopen file '$self->{file}': $!\n";
57 $self->{fh} = $fh;
58
59 # Even though we use O_BINARY, better be safe than sorry.
60 binmode $fh;
61
62 if ($self->{autoflush}) {
63 my $old = select $fh;
64 $|=1;
65 select $old;
66 }
67
68 return 1;
69}
70
71sub close {
72 my $self = shift;
73
74 if ( $self->{fh} ) {
75 close $self->{fh};
76 $self->{fh} = undef;
77 }
78
79 return 1;
80}
81
7dcefff3 82sub set_inode {
83 my $self = shift;
84
3ed26433 85 unless ( defined $self->{inode} ) {
7dcefff3 86 my @stats = stat($self->{fh});
87 $self->{inode} = $stats[1];
88 $self->{end} = $stats[7];
89 }
90
91 return 1;
92}
93
019404df 94sub print_at {
95 my $self = shift;
96 my $loc = shift;
97
98 local ($/,$\);
99
100 my $fh = $self->{fh};
7dcefff3 101 if ( defined $loc ) {
102 seek( $fh, $loc + $self->{file_offset}, SEEK_SET );
103 }
104
019404df 105 print( $fh @_ );
106
107 return 1;
108}
109
7dcefff3 110sub read_at {
111 my $self = shift;
112 my ($loc, $size) = @_;
9bc79bb6 113 print join(":",map{$_||''}caller) . " - read_at(@{[$loc || 'undef']}, $size)\n" if $::DEBUG;
7dcefff3 114
115 local ($/,$\);
116
117 my $fh = $self->{fh};
118 if ( defined $loc ) {
119 seek( $fh, $loc + $self->{file_offset}, SEEK_SET );
120 }
121
122 my $buffer;
123 read( $fh, $buffer, $size);
124
125 return $buffer;
126}
127
128sub increment_pointer {
129 my $self = shift;
130 my ($size) = @_;
131
132 if ( defined $size ) {
133 seek( $self->{fh}, $size, SEEK_CUR );
134 }
135
136 return 1;
137}
138
460b1067 139sub DESTROY {
140 my $self = shift;
141 return unless $self;
142
143 $self->close;
144
145 return;
146}
147
019404df 148sub request_space {
149 my $self = shift;
150 my ($size) = @_;
151
7dcefff3 152 #XXX Do I need to reset $self->{end} here? I need a testcase
019404df 153 my $loc = $self->{end};
154 $self->{end} += $size;
155
156 return $loc;
157}
158
15ba72cc 159##
160# If db locking is set, flock() the db file. If called multiple
161# times before unlock(), then the same number of unlocks() must
162# be called before the lock is released.
163##
164sub lock {
165 my $self = shift;
166 my ($obj, $type) = @_;
42717e46 167
15ba72cc 168 $type = LOCK_EX unless defined $type;
169
170 if (!defined($self->{fh})) { return; }
171
172 if ($self->{locking}) {
173 if (!$self->{locked}) {
174 flock($self->{fh}, $type);
175
176 # refresh end counter in case file has changed size
177 my @stats = stat($self->{fh});
178 $self->{end} = $stats[7];
179
180 # double-check file inode, in case another process
181 # has optimize()d our file while we were waiting.
3ed26433 182 if (defined($self->{inode}) && $stats[1] != $self->{inode}) {
15ba72cc 183 $self->close;
184 $self->open;
185
186 #XXX This needs work
187 $obj->{engine}->setup_fh( $obj );
188
189 flock($self->{fh}, $type); # re-lock
190
191 # This may not be necessary after re-opening
192 $self->{end} = (stat($self->{fh}))[7]; # re-end
193 }
194 }
195 $self->{locked}++;
196
197 return 1;
198 }
199
200 return;
201}
202
203##
204# If db locking is set, unlock the db file. See note in lock()
205# regarding calling lock() multiple times.
206##
207sub unlock {
208 my $self = shift;
209
210 if (!defined($self->{fh})) { return; }
211
212 if ($self->{locking} && $self->{locked} > 0) {
213 $self->{locked}--;
214 if (!$self->{locked}) { flock($self->{fh}, LOCK_UN); }
215
216 return 1;
217 }
218
219 return;
220}
221
696cadb7 222sub flush {
223 my $self = shift;
224
225 # Flush the filehandle
226 my $old_fh = select $self->{fh};
227 my $old_af = $|; $| = 1; $| = $old_af;
228 select $old_fh;
229
230 return 1;
231}
232
460b1067 2331;
234__END__