[Bps-public-commit] Prophet - A disconnected, replicated p2p database branch, master, updated. cd637399ea4769629eca14ccd2a98cb0e0c89f75

jesse jesse at bestpractical.com
Sat Jan 17 17:36:19 EST 2009


The branch, master has been updated
       via  cd637399ea4769629eca14ccd2a98cb0e0c89f75 (commit)
      from  f1e567e3a25cf9c0e7ed3c059b9fdfd3b2b0cf55 (commit)

Summary of changes:
 lib/Prophet/CLI/CollectionCommand.pm |    3 +-
 lib/Prophet/Collection.pm            |   16 +++------
 lib/Prophet/Record.pm                |   24 ++++++++++----
 lib/Prophet/Replica/prophet.pm       |   11 ++++++-
 lib/Prophet/Replica/sqlite.pm        |   57 +++++++++++++++++++++++++++------
 5 files changed, 79 insertions(+), 32 deletions(-)

- Log -----------------------------------------------------------------
commit cd637399ea4769629eca14ccd2a98cb0e0c89f75
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Sat Jan 17 17:35:32 2009 -0500

    list_records now returns record objects rather than record ids
    sqlite replicas now maintain a memory cache of records
    records found through a search are precached.

diff --git a/lib/Prophet/CLI/CollectionCommand.pm b/lib/Prophet/CLI/CollectionCommand.pm
index 5a56fd5..017d747 100644
--- a/lib/Prophet/CLI/CollectionCommand.pm
+++ b/lib/Prophet/CLI/CollectionCommand.pm
@@ -10,8 +10,7 @@ sub get_collection_object {
         type => { default => $self->type },
     });
 
-    my $record_class = $self->_get_record_object(type => $args{type});
-    my $class = $record_class->collection_class;
+    my $class = $self->_get_record_object(type => $args{type})->collection_class;
     Prophet::App->require($class);
 
     my $records = $class->new(
diff --git a/lib/Prophet/Collection.pm b/lib/Prophet/Collection.pm
index ac159b6..2c92d86 100644
--- a/lib/Prophet/Collection.pm
+++ b/lib/Prophet/Collection.pm
@@ -71,25 +71,19 @@ returns true.
 sub matching {
     my $self    = shift;
     my $coderef = shift;
-    return undef unless $self->handle->type_exists( type => $self->type );
+    # return undef unless $self->handle->type_exists( type => $self->type );
     # find all items,
     Carp::cluck unless defined $self->type;
 
-    my $records = $self->handle->list_records( type => $self->type );
-
+    my $records = $self->handle->list_records( record_class => $self->record_class, type => $self->type );
     
     # run coderef against each item;
     # if it matches, add it to items
-    for my $key (@$records) {
-        my $record = $self->record_class->new( { app_handle => $self->app_handle,  handle => $self->handle, type => $self->type } );
-        $record->load( uuid => $key );
-        if ( $coderef->($record) ) {
-            $self->add_item($record);
-        }
-
+    for my $record (@$records) {
+        $self->add_item($record) if ( $coderef->($record) );
     }
 
-    #return a count of items found
+    # XXX TODO return a count of items found
 
 }
 
diff --git a/lib/Prophet/Record.pm b/lib/Prophet/Record.pm
index b8c7a3e..4215e35 100644
--- a/lib/Prophet/Record.pm
+++ b/lib/Prophet/Record.pm
@@ -69,6 +69,8 @@ class_has uuid_generator => (
     default => sub { require Data::UUID; Data::UUID->new()}
 );
 
+
+
 =head1 METHODS
 
 =head2 new  { handle => Prophet::Replica, type => $type }
@@ -280,10 +282,21 @@ sub load {
         return($self->luid) if ($self->luid);
     }
 
-    delete $self->{props};
     return undef;
 }
 
+# a private method to let collection search results instantiate records more quickly
+# (See Prophet::Replica::sqlite)
+sub _instantiate_from_hash {
+    my $self = shift;
+    my %args = ( uuid => undef, luid => undef, @_);
+    # we might not have a luid cheaply (see the prophet filesys backend)
+    $self->luid($args{'luid'}) if (defined $args{'luid'});
+    # We _Always_ have a luid
+    $self->uuid($args{'uuid'});
+    # XXX TODO - expect props as well
+}
+
 sub loaded {
     my $self = shift;
     return $self->uuid ? 1 : 0;
@@ -324,7 +337,6 @@ sub set_props {
 
     $self->canonicalize_props( $args{'props'} );
     $self->validate_props( $args{'props'} ) || return undef;
-    delete $self->{props};
     $self->handle->set_record_props(
         type  => $self->type,
         uuid  => $self->uuid,
@@ -344,12 +356,10 @@ sub get_props {
 
     confess "get_props called on a record that hasn't been loaded or created yet." if !$self->uuid;
 
-   return  $self->handle->get_record_props(
+    return $self->handle->get_record_props(
         uuid => $self->uuid,
-        type => $self->type
-    ) || {};;
-    return $self->{props} || {};
-    #$self->{props} ||=
+        type => $self->type) || {};
+
 }
 
 =head2 prop $name
diff --git a/lib/Prophet/Replica/prophet.pm b/lib/Prophet/Replica/prophet.pm
index 9e2e6db..e79ef86 100644
--- a/lib/Prophet/Replica/prophet.pm
+++ b/lib/Prophet/Replica/prophet.pm
@@ -1001,8 +1001,9 @@ sub record_exists {
 
 sub list_records {
     my $self = shift;
-    my %args = validate( @_ => { type => 1 } );
+    my %args = validate( @_ => { type => 1, record_class => 1 } );
 
+    return [] unless $self->type_exists( type => $args{type} );
     #return just the filenames, which, File::Find::Rule doesn't seem capable of
     my @record_uuids
         = map { my @path = split( qr'/', $_ ); pop @path }
@@ -1012,10 +1013,18 @@ sub list_records {
         )
         );
     return [
+        map { 
+            my $record = $args{record_class}->new( { app_handle => $self->app_handle,  handle => $self, type => $args{type} } );
+            $record->_instantiate_from_hash( uuid => $_);
+            $record;
+        }
         grep {
             $self->_record_cas_filename( type => $args{'type'}, uuid => $_ )
             } @record_uuids
     ];
+    
+        
+        
 }
 
 sub list_types {
diff --git a/lib/Prophet/Replica/sqlite.pm b/lib/Prophet/Replica/sqlite.pm
index af5fe8c..20b51bb 100644
--- a/lib/Prophet/Replica/sqlite.pm
+++ b/lib/Prophet/Replica/sqlite.pm
@@ -79,7 +79,7 @@ has '+resolution_db_handle' => (
     },
 );
 
-
+our $PROP_CACHE;
 
 use constant scheme   => 'sqlite';
 use constant userdata_dir    => 'userdata';
@@ -383,6 +383,7 @@ sub _delete_record_props_from_db {
     my %args = validate( @_, { uuid => 1 } );
 
     $self->dbh->do("DELETE FROM record_props where uuid = ?", {}, $args{uuid});
+    delete $PROP_CACHE->{$args{uuid}};
 
 }
 
@@ -620,7 +621,10 @@ sub set_record_props {
 
     my $inside_edit = $self->current_edit ? 1 : 0;
     $self->begin_edit() unless ($inside_edit);
-
+   
+    # clear the cache  before computing the diffs. this is probably paranoid
+    delete $PROP_CACHE->{$args{uuid}};
+    
     my $old_props = $self->get_record_props( uuid => $args{'uuid'}, type => $args{'type'});
     my %new_props = %$old_props;
 
@@ -634,6 +638,9 @@ sub set_record_props {
 
     $self->_write_record_to_db( type  => $args{'type'}, uuid  => $args{'uuid'}, props => \%new_props);
 
+    # Clear the cache now that we've actually written out changed props
+    delete $PROP_CACHE->{$args{uuid}};
+
     my $change = Prophet::Change->new( {   record_type => $args{'type'}, record_uuid => $args{'uuid'}, change_type => 'update_file' });
     $change->add_prop_change( name => $_, old  => $old_props->{$_}, new  => $args{props}->{$_}) for (keys %{$args{props}});
     $self->current_edit->add_change( change => $change );
@@ -644,11 +651,15 @@ sub set_record_props {
 
 sub get_record_props {
     my $self = shift;
-    my %args = (uuid => undef, type => undef, @_); # validate is slooow validate( @_, { uuid => 1, type => 1 } );
-    my $sth = $self->dbh->prepare( "SELECT prop, value from record_props WHERE uuid = ?");
-    $sth->execute($args{uuid});
-    my $items = $sth->fetchall_arrayref;
-    return {map {  @$_ } @$items}; 
+    my %args = ( uuid => undef, type => undef, @_ )
+        ;    # validate is slooow validate( @_, { uuid => 1, type => 1 } );
+    unless ( exists $PROP_CACHE->{ $args{uuid} } ) {
+        my $sth = $self->dbh->prepare("SELECT prop, value from record_props WHERE uuid = ?");
+        $sth->execute( $args{uuid} );
+        my $items = $sth->fetchall_arrayref;
+        $PROP_CACHE->{ $args{uuid} } = {map {@$_} @$items};
+    }
+    return $PROP_CACHE->{ $args{uuid} };
 }
 
 sub record_exists {
@@ -662,13 +673,37 @@ sub record_exists {
 
 }
 
+=head2 list_records { type => $type }
+
+Returns a reference to a list of record objects for all records of type $type.
+
+Order is not guaranteed.
+
+=cut
+
 sub list_records {
     my $self = shift;
-    my %args = validate( @_ => { type => 1 } );
-
-    my $sth = $self->dbh->prepare("SELECT uuid from records WHERE type = ?");
+    my %args = validate( @_ => { type => 1, record_class => 1 } );
+    my @data;
+    my $sth = $self->dbh->prepare("SELECT records.uuid, records.luid, record_props.prop, record_props.value ".
+        "FROM records, record_props ".
+        "WHERE records.uuid = record_props.uuid AND records.type = ?");
     $sth->execute($args{type});
-    my @data = map { $_->[0]} @{ $sth->fetchall_arrayref};
+
+    my %found;
+
+    for (@{$sth->fetchall_arrayref}) { 
+        $found{$_->[0]}->{luid} = $_->[1];
+        $found{$_->[0]}->{props}->{$_->[2]} = $_->[3];
+    } 
+
+
+    for my $uuid (keys %found) {
+        my $record = $args{record_class}->new( { app_handle => $self->app_handle,  handle => $self, type => $args{type} } );
+        $record->_instantiate_from_hash( uuid => $uuid, luid => $found{$uuid}->{luid});
+        #$PROP_CACHE->{$uuid} = $found{$uuid}->{props};
+        push @data, $record;    
+    } 
     return \@data;
 }
 

-----------------------------------------------------------------------



More information about the Bps-public-commit mailing list