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