return DBM::Deep::Array->TIEARRAY( @_ );
}
-#XXX Unneeded now ...
-#sub DESTROY {
-#}
-
sub lock {
- ##
- # If db locking is set, flock() the db file. If called multiple
- # times before unlock(), then the same number of unlocks() must
- # be called before the lock is released.
- ##
my $self = shift->_get_self;
- my ($type) = @_;
- $type = LOCK_EX unless defined $type;
-
- if (!defined($self->_fh)) { return; }
-
- if ($self->_fileobj->{locking}) {
- if (!$self->_fileobj->{locked}) {
- flock($self->_fh, $type);
-
- # refresh end counter in case file has changed size
- my @stats = stat($self->_fh);
- $self->_fileobj->{end} = $stats[7];
-
- # double-check file inode, in case another process
- # has optimize()d our file while we were waiting.
- if ($stats[1] != $self->_fileobj->{inode}) {
- $self->_fileobj->close;
- $self->_fileobj->open;
- $self->{engine}->setup_fh( $self );
- flock($self->_fh, $type); # re-lock
-
- # This may not be necessary after re-opening
- $self->_fileobj->{end} = (stat($self->_fh))[7]; # re-end
- }
- }
- $self->_fileobj->{locked}++;
-
- return 1;
- }
-
- return;
+ return $self->_fileobj->lock( $self, @_ );
}
sub unlock {
- ##
- # If db locking is set, unlock the db file. See note in lock()
- # regarding calling lock() multiple times.
- ##
my $self = shift->_get_self;
-
- if (!defined($self->_fh)) { return; }
-
- if ($self->_fileobj->{locking} && $self->_fileobj->{locked} > 0) {
- $self->_fileobj->{locked}--;
- if (!$self->_fileobj->{locked}) { flock($self->_fh, LOCK_UN); }
-
- return 1;
- }
-
- return;
+ return $self->_fileobj->unlock( $self, @_ );
}
sub _copy_value {
SIG_HEADER,
pack('N', 1), # header version
pack('N', 12), # header size
- pack('N', 0), # file version
+ pack('N', 0), # currently running transaction IDs
pack('S', $self->{long_size}),
pack('A', $self->{long_pack}),
pack('S', $self->{data_size}),
);
unless ( $file_signature eq SIG_FILE ) {
- $self->{fileobj}->close;
+ $self->_fileobj->close;
$self->_throw_error( "Signature not found -- file is not a Deep DB" );
}
unless ( $sig_header eq SIG_HEADER ) {
- $self->{fileobj}->close;
+ $self->_fileobj->close;
$self->_throw_error( "Old file version found." );
}
my $buffer2;
$bytes_read += read( $fh, $buffer2, $size );
- my ($file_version, @values) = unpack( 'N S A S A S', $buffer2 );
+ my ($running_transactions, @values) = unpack( 'N S A S A S', $buffer2 );
+
+ $self->_fileobj->set_transaction_offset( 13 );
+
if ( @values < 5 || grep { !defined } @values ) {
- $self->{fileobj}->close;
+ $self->_fileobj->close;
$self->_throw_error("Corrupted file - bad header");
}
filter_fetch_value => undef,
transaction_id => 0,
+ transaction_offset => 0,
}, $class;
# Grab the parameters we want to use
return;
}
+##
+# If db locking is set, flock() the db file. If called multiple
+# times before unlock(), then the same number of unlocks() must
+# be called before the lock is released.
+##
+sub lock {
+ my $self = shift;
+ my ($obj, $type) = @_;
+ $type = LOCK_EX unless defined $type;
+
+ if (!defined($self->{fh})) { return; }
+
+ if ($self->{locking}) {
+ if (!$self->{locked}) {
+ flock($self->{fh}, $type);
+
+ # refresh end counter in case file has changed size
+ my @stats = stat($self->{fh});
+ $self->{end} = $stats[7];
+
+ # double-check file inode, in case another process
+ # has optimize()d our file while we were waiting.
+ if ($stats[1] != $self->{inode}) {
+ $self->close;
+ $self->open;
+
+ #XXX This needs work
+ $obj->{engine}->setup_fh( $obj );
+
+ flock($self->{fh}, $type); # re-lock
+
+ # This may not be necessary after re-opening
+ $self->{end} = (stat($self->{fh}))[7]; # re-end
+ }
+ }
+ $self->{locked}++;
+
+ return 1;
+ }
+
+ return;
+}
+
+##
+# If db locking is set, unlock the db file. See note in lock()
+# regarding calling lock() multiple times.
+##
+sub unlock {
+ my $self = shift;
+
+ if (!defined($self->{fh})) { return; }
+
+ if ($self->{locking} && $self->{locked} > 0) {
+ $self->{locked}--;
+ if (!$self->{locked}) { flock($self->{fh}, LOCK_UN); }
+
+ return 1;
+ }
+
+ return;
+}
+
+sub set_transaction_offset {
+ my $self = shift;
+ $self->{transaction_offset} = shift;
+}
+
sub begin_transaction {
my $self = shift;
+ my $fh = $self->{fh};
+
+ seek( $fh, $self->{transaction_offset}, SEEK_SET );
+
$self->{transaction_id}++;
}
sub end_transaction {
my $self = shift;
+# seek( $fh, $self->{transaction_offset}, SEEK_SET );
+
$self->{transaction_id} = 0;
}
# Should the transaction be in the Root and not the Engine? How would that
# work?
+# What about the following:
+# $db->{foo} = {};
+# $db2 = $db->{foo};
+# $db2->begin_work;
+# $db->{foo} = 3;
+
__END__
Plan for transactions: