Data-ObjectStore
view release on metacpan or search on metacpan
lib/Data/ObjectStore.pm view on Meta::CPAN
package Data::ObjectStore;
use strict;
use warnings;
no warnings 'numeric';
no warnings 'uninitialized';
no warnings 'recursion';
use File::Path qw( make_path );
use Scalar::Util qw(weaken);
use Time::HiRes qw(time);
use vars qw($VERSION);
use Data::RecordStore;
use Data::ObjectStore::Cache;
$VERSION = '2.13';
our $DEBUG = 0;
our $UPGRADING;
use constant {
DATA_PROVIDER => 0,
DIRTY => 1,
WEAK => 2,
STOREINFO => 3,
OPTIONS => 4,
CACHE => 5,
ID => 0,
DATA => 1,
METADATA => 3,
LEVEL => 4,
DIRTY_BIT => 5, #for objs
};
my( @METAFIELDS ) = qw( created updated );
sub open_store {
my( $cls, @options ) = @_;
die "Data::ObjectStore->open_store requires at least one argument" if 0 == @options;
if( 1 == @options ) {
unshift @options, 'DATA_PROVIDER';
}
my( %options ) = @options;
my $data_provider = $options{DATA_PROVIDER};
if( ! ref( $data_provider ) ) {
# the default record store Data::RecordStore
$options{BASE_PATH} = "$data_provider/RECORDSTORE";
$data_provider = Data::RecordStore->open_store( %options );
}
my $cache = $options{CACHE} ? ref( $options{CACHE} ) ? $options{CACHE} : Data::ObjectStore::Cache->new( $options{CACHE} ) : undef;
my $store = bless [
$data_provider,
{}, #DIRTY CACHE
{}, #WEAK CACHE
undef,
\%options,
$cache,
], $cls;
if( ! $UPGRADING ) {
$store->[STOREINFO] = $store->_fetch_store_info_node;
$store->load_root_container;
if( $store->get_store_version < 1.2 ) {
die "Unable to open store of version ".$store->get_store_version.". Please run upgrade_store.";
}
$store->save;
lib/Data/ObjectStore.pm view on Meta::CPAN
} else {
die "Object in the store was marked as '$class' but that is not a 'Data::ObjectStore::Container'";
}
}
};
if( $@ ) {
if( $force ) {
warn "Forcing '$class' to be 'Data::ObjectStore::Container'";
$class = 'Data::ObjectStore::Container';
} else {
die $@;
}
}
}
my $pieces = _thaw( $dryfroze );
my $ret = $class->_reconstitute( $self, $id, $pieces, $meta );
$self->_store_weak( $id, $ret );
return $ret;
} #_fetch
#
# Convert from reference, scalar or undef to value marker
#
sub _xform_in {
my( $self, $val ) = @_;
if( ref( $val ) ) {
my $id = $self->_get_id( $val );
return $id, "r$id";
}
return 0, (defined $val ? "v$val" : 'u');
}
#
# Convert from value marker to reference, scalar or undef
#
sub _xform_out {
my( $self, $val ) = @_;
return undef unless defined( $val ) && $val ne 'u';
if( index($val,'v') == 0 ) {
return substr( $val, 1 );
}
if( $val =~ /^r(\d+)/ ) {
return $self->fetch( $1 );
}
return $self->fetch( $val );
}
sub _store_weak {
my( $self, $id, $ref ) = @_;
if( $self->[CACHE] ) {
$self->[CACHE]->stow( $id, $ref );
}
$self->[WEAK]{$id} = $ref;
weaken( $self->[WEAK]{$id} );
} #_store_weak
sub _dirty {
my( $self, $id ) = @_;
my $item = $self->[WEAK]{$id};
$self->[DIRTY]{$id} = $item;
$item = $self->_knot( $item );
if( $item ) {
$item->[METADATA]{updated} = time();
}
} #_dirty
sub _new_id {
my( $self ) = @_;
my $newid = $self->[DATA_PROVIDER]->next_id;
$newid;
} #_new_id
sub _meta {
my( $self, $thingy ) = @_;
return {
created => $thingy->[METADATA]{created},
updated => $thingy->[METADATA]{updated},
};
} #_meta
sub last_updated {
my( $self, $obj ) = @_;
$obj = $self->_knot( $obj );
return undef unless $obj;
$self->_meta( $obj )->{updated};
}
sub created {
my( $self, $obj ) = @_;
$obj = $self->_knot( $obj );
return undef unless $obj;
$self->_meta( $obj )->{created};
}
# returns the id of the refernce, injesting it if
# necessary.
# used by tests
sub _get_id {
my( $self, $ref ) = @_;
my $class = ref( $ref );
my $thingy;
if ( $class eq 'ARRAY' ) {
$thingy = tied @$ref;
if ( ! $thingy ) {
my $id = $self->_new_id;
my( @items ) = @$ref;
tie @$ref, 'Data::ObjectStore::Array', $self, $id, { created => time, updated => time}, 0, $Data::ObjectStore::Array::MAX_BLOCKS;
my $tied = tied @$ref;
$self->_store_weak( $id, $ref );
$self->_dirty( $id );
( run in 0.766 second using v1.01-cache-2.11-cpan-39bf76dae61 )