| T2 documentation | Contained in the T2 distribution. |
T2::Storage - Database handle, object cache
# load the application schema, connect to the database
my $storage = T2::Storage->open("MyApp");
# store an object with a schema
$storage->insert($object);
The Tangram T2 Storage class. Currently, this is a subclass of Tangram::Storage, but it is planned to slowly move pieces of Tangram proper into this new core.
This function opens a connection to a named database source. It takes between one and two parameters:
The `site' to connect to. This is a named data source, a bit like
using ODBC but stored in a text file rather than an opaque registry.
This should correspond to a file in etc/ called $site.dsn, as
extracted by T2::Storage::get_dsn_info (see get_dsn_info).
This should be either a Tangram::Schema object, or a T2::Schema object.
Gets the database information for $site_name, in the form ($dsn, $username, $password, $schema); If $dont_get_schema is set, no attempt to load the Tangram schema is made.
Returns the site name that was used to connect to this database.
Save an object to the database (that is, do an insert if this is a new object or an update if it is already persistent).
A smarter version of unload_all() that really makes sure all objects are cleaned up from memory, using Class::Tangram's clear_refs() method.
Make double damned sure that this instance of the Storage handle doesn't hold any locks
Returns a current DBI handle, though you are not guaranteed to get Tangram's own handle.
Sam Vilain, <samv@cpan.org>
| T2 documentation | Contained in the T2 distribution. |
# -*- cperl -*-
package T2::Storage; use strict 'vars', 'subs'; use Tangram; use Tangram::FlatArray; use Carp; use Tangram::Storage; use vars qw(@ISA @EXPORT_OK); @ISA = qw(Tangram::Storage); @EXPORT_OK = qw(@ISA);
sub open ($$;$) { my ($class, $site_name, $schema) = (@_); my @dsn = get_dsn_info($site_name, $schema); $schema ||= pop @dsn; die "can't get a schema for $site_name" unless ($schema and ($schema->isa("Tangram::Schema") || $schema->isa("T2::Schema"))); $schema = $schema->schema if $schema->isa("T2::Schema"); my $dbi_driver = (split ':', $dsn[0])[1]; my $tangram_d = "Tangram::$dbi_driver"; my $self; local $SIG{__DIE__} = sub { $@ = $_[0] }; eval "use $tangram_d"; if ( $@ ) { # connect to the database $self = $class->SUPER::connect($schema, @dsn) or die $DBI::errstr; } else { my $t2_storage = "T2::Storage::$dbi_driver"; unless ( keys %{"${t2_storage}::"}) { @{"${t2_storage}::ISA"} = ("Tangram::${dbi_driver}::Storage", "T2::Storage"); } $self = $t2_storage->connect($schema, @dsn) or die $DBI::errstr; } # setup the object and return $self->{site_name} = $site_name; return $self; }
use Scalar::Util qw(blessed); our @dsn_path = qw(. etc ../etc); sub get_dsn_info { my $self; if (blessed $_[0] and $_[0]->isa(__PACKAGE__)) { $self = shift; } my ($site_name, $dont_get_schema) = (@_); $site_name ||= $self->{site_name} if $self; # read in the DSN info my $dsn_file; for my $path (@dsn_path) { ( -f ($dsn_file = "$path/${site_name}.dsn")) && last; } CORE::open DSN, "<$dsn_file" or die ("Failed to load site DSN configuration file " ."${site_name}.dsn (search path: @dsn_path); $!"); my ($dsn, $username, $auth, $schema_eval); while (<DSN>) { chomp; m/^\s*dsn\s+\b(.*?)\s*$/ && ($dsn = $1); m/^\s*user\s+\b(.*?)\s*$/ && ($username = $1); m/^\s*auth\s+\b(.*?)\s*$/ && ($auth = $1); m/^\s*schema\s+\b(.*?)\s*$/ && ($schema_eval = $1); } close DSN; if ($dont_get_schema) { return ($dsn, $username, $auth); } else { #no strict; # get schema - try to avoid this string eval eval "use T2::Schema" unless $INC{"T2/Schema.pm"}; my $schema = eval $schema_eval; if ($@) { $schema = T2::Schema->read($schema_eval); } return ($dsn, $username, $auth, $schema); } }
sub site_name($) { my ($self) = (@_); $self->isa("T2::Storage") or die "type mismatch"; return $self->{site_name}; }
sub save($@) { my ($self, @objs) = (@_); $self->isa("T2::Storage") or die "type mismatch"; my @return_vals; for my $obj (@objs) { if ($self->id($obj)) { push @return_vals, $self->update($obj); } else { push @return_vals, $self->insert($obj); } } return @return_vals; } sub ping { my $self = shift; eval { # *thwap* naughty! $self->{db}->do("select 1 + 1"); }; return !$@ }
sub unload_all { my $self = shift; my $objects = $self->{objects}; if ($objects and ref $objects eq "HASH") { while (my $oid = each %$objects) { if (defined $objects->{$oid}) { if (my $x = UNIVERSAL::can($objects->{$oid}, "clear_refs")) { $x->($objects->{$oid}); } $self->goodbye($objects->{$oid}, $oid); } } } while (my $oid = each %$objects) { next unless defined $objects->{$oid}; warn __PACKAGE__."::unload_all: cached ref to oid $oid " ."is not weak" if (!$Tangram::no_weakrefs and !Scalar::Util::isweak($objects->{$oid})); my $x; warn __PACKAGE__."::unload_all: refcnt of oid $oid is $x" if (!$Tangram::no_weakrefs and $x = Set::Object::rc($objects->{$oid})); } $self->{ids} = {}; $self->{objects} = {}; $self->{prefetch} = {}; print $Tangram::TRACE __PACKAGE__.": cache dumped\n" if $Tangram::TRACE; #$self->SUPER::unload_all(); }
sub rollback_all { my $self = shift; while (@{ $self->{tx} }) { $self->tx_rollback } eval { $self->dbi_handle->rollback; }; #local($self->{db}->{AutoCommit}) = 1; }
sub dbi_handle { my $self = shift; my $site_name = shift; $site_name ||= $self->{site_name}; if ($self->{db} && $self->{db}->do("SELECT 1 + 1")) { return $self->{db}; } else { my @dsn = $self->get_dsn_info($site_name, 1); return DBI->connect(@dsn); } } sub reopen_connection { my $self = shift; $self->{db} = $self->open_connection; }
1;