Re: mod_perl and global %Live_Objects not being initialized

[prev] [thread] [next] [Date index for 2004/11/19]

From: Tim Bunce
Subject: Re: mod_perl and global %Live_Objects not being initialized
Date: 13:47 on 19 Nov 2004
On Wed, Nov 17, 2004 at 04:52:06PM +0000, Tony Bowden wrote:
> On Wed, Nov 17, 2004 at 03:42:11PM +0000, Tim Bunce wrote:
> > I get lots of these errors from the test suite: dbih_setup_fbav:
> > invalid number of fields: 0, NUM_OF_FIELDS attribute probably not set
> > right at .../DBIx/ContextualFetch.pm line 88.
> 
> Oooh. Interesting.
> 
> > That execute()s fine but it seems the driver doesn't think it's
> > a SELECT-like statement and so hasn't setup the NUM_OF_FIELDS attribute.
> > I'm using DBD::SQLite 0.25. Looks like the test code doesn't check
> > the DBD::SQLite version. Should it? Do I need to upgrade?
> 
> Not sure. I haven't come across this.
> 
> I'm on 0.31, so I'm quite far behind as well.

Upgrading to DBD::SQLite 0.31 fixes it.

I've appended a draft patch. Let me know if you're happy with the
general direction and I'll polish it up with docs and tests etc.

Key points are:

1. The 'live object index' concept is better encapsulated now.
2. The %Live_Object hash is now two-level ($class as first level).
3. A class can ask for access to its live object index (for dumping/debugging)
4. The _live_object_fetch() method called by _init() can now
   be overridden to implement a wider variety of policies,
   including full caching, LRU, age-based etc etc.

Tim.

diff -u -r Class-DBI-0.96_50/lib/Class/DBI.pm Class-DBI-0.96_50-liveobj/lib/Class/DBI.pm
--- Class-DBI-0.96_50/lib/Class/DBI.pm	Wed Nov 17 11:41:13 2004
+++ Class-DBI-0.96_50-liveobj/lib/Class/DBI.pm	Fri Nov 19 13:26:51 2004
@@ -23,14 +23,11 @@
 use vars qw($Weaken_Is_Available);
 
 BEGIN {
-	$Weaken_Is_Available = 1;
-	eval {
+	$Weaken_Is_Available = eval {
 		require Scalar::Util;
 		import Scalar::Util qw(weaken);
+		1;
 	};
-	if ($@) {
-		$Weaken_Is_Available = 0;
-	}
 }
 
 use overload
@@ -499,37 +496,45 @@
 }
 
 #----------------------------------------------------------------------
-# Live Object Index (using weak refs if available)
+# Object creation
 #----------------------------------------------------------------------
 
-my %Live_Objects;
-my $Init_Count = 0;
-
 sub _init {
-	my $class = shift;
-	my $data  = shift || {};
-	my $key   = $class->_live_object_key($data);
-	return $Live_Objects{$key} || $class->_fresh_init($key => $data);
+	my ($class, $data) = @_;
+	# give index/caching mechanism being used by this class the
+	# responsibility to get the object so it can, for example,
+	# use a) no index, b) standard weakref based index (the default),
+	# c) non-weakref based "cache" (including LRU or age limited) etc.
+	return $class->_live_object_fetch($data || {}, 1);
 }
 
 sub _fresh_init {
-	my ($class, $key, $data) = @_;
+	my ($class, $data) = @_;
 	my $obj = bless {}, $class;
 	$obj->_attribute_store(%$data);
-
-	# don't store it unless all keys are present
-	if ($key && $Weaken_Is_Available) {
-		weaken($Live_Objects{$key} = $obj);
-
-		# time to clean up your room?
-		$class->purge_dead_from_object_index
-			if ++$Init_Count % $class->purge_object_index_every == 0;
-	}
 	return $obj;
 }
 
+#----------------------------------------------------------------------
+# Live Object Index (using weak refs if available)
+#----------------------------------------------------------------------
+
+my %Live_Objects;
+my $_live_object_store_count = 0;
+
+sub _live_object_index {
+	my ($self) = @_;
+	my $class  = ref($self) || $self;
+	return \%Live_Objects if $class eq "Class::DBI";
+	return $Live_Objects{$class};
+}
+
 sub _live_object_key {
 	my ($me, $data) = @_;
+	# Return key to use for this object in the live object index.
+	# Key string must uniquely and permenantly identify the object.
+	# Return empty string if object doesn't have full indentity yet.
+	# Subclass can use "sub _live_object_key { '' }" to disable.
 	my $class   = ref($me) || $me;
 	my @primary = $class->primary_columns;
 
@@ -540,18 +545,44 @@
 	return join "\030", $class, map $_ . "\032" . $data->{$_}, sort @primary;
 }
 
+sub _live_object_store {
+	my ($self, $key) = @_;
+	return unless $key && $Weaken_Is_Available;
+	my $class = ref $self;
+	weaken($Live_Objects{$class}{$key} = $self);
+	# time to clean up your room?
+	$class->purge_dead_from_object_index
+		if ++$_live_object_store_count % $class->purge_object_index_every == 0;
+}
+
+sub _live_object_fetch {
+	my ($class, $data, $vivify) = @_;
+	my $key = $class->_live_object_key($data);
+	my $obj = $Live_Objects{$class}{$key};
+	return $obj if $obj or !$vivify;
+	$obj = $class->_fresh_init($data);
+	$obj->_live_object_store($key);
+	return $obj;
+}
+
 sub purge_dead_from_object_index {
-	delete @Live_Objects{ grep !defined $Live_Objects{$_}, keys %Live_Objects };
+	while ( my ($class, $lo) = each %Live_Objects ) {
+		my @dead_keys = grep {!defined $lo->{$_} } keys %$lo;
+		delete @{$lo}{ @dead_keys };
+	}
 }
 
 sub remove_from_object_index {
 	my $self    = shift;
-	my $obj_key = $self->_live_object_key($self->{_DATA});
-	delete $Live_Objects{$obj_key};
+	my $class   = ref $self or return;
+	my $obj_key = $class->_live_object_key($self->{_DATA});
+	delete $Live_Objects{$class}{$obj_key};
 }
 
 sub clear_object_index {
-	%Live_Objects = ();
+	my $lo = shift->_live_object_index(@_)
+		or return;
+	%$lo = ();
 }
 
 sub _prepopulate_id {

(message missing)

Re: mod_perl and global %Live_Objects not being initialized
Tim Bunce 13:47 on 19 Nov 2004

Re: mod_perl and global %Live_Objects not being initialized
=?ISO-8859-1?Q?Ask_Bj=F8rn_Hansen?= 03:02 on 19 Nov 2004

Generated at 17:31 on 15 Feb 2005 by mariachi v0.52