[Bps-public-commit] r11025 - in SVN-PropDB: . bin doc lib/Prophet

jesse at bestpractical.com jesse at bestpractical.com
Fri Mar 7 12:54:58 EST 2008


Author: jesse
Date: Fri Mar  7 12:54:58 2008
New Revision: 11025

Added:
   SVN-PropDB/doc/
   SVN-PropDB/doc/glossary
   SVN-PropDB/doc/notes-on-merging
      - copied unchanged from r11024, /SVN-PropDB/notes
   SVN-PropDB/doc/todo
Removed:
   SVN-PropDB/notes
Modified:
   SVN-PropDB/   (props changed)
   SVN-PropDB/bin/merger
   SVN-PropDB/lib/Prophet/Change.pm
   SVN-PropDB/lib/Prophet/ChangeSet.pm
   SVN-PropDB/lib/Prophet/Handle.pm
   SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm

Log:
 r28177 at 31b:  jesse | 2008-03-07 12:53:01 -0500
 * checkpoint


Modified: SVN-PropDB/bin/merger
==============================================================================
--- SVN-PropDB/bin/merger	(original)
+++ SVN-PropDB/bin/merger	Fri Mar  7 12:54:58 2008
@@ -19,11 +19,10 @@
             "someone did a bad job cloning your database") if ($target->unique_id eq $source->unique_id);
 
 if ( $target->accepts_changesets ) {
-    my @changesets_to_integrate = $source->fetch_changesets( 
-            after => $target->last_changeset_for_source(source => $source->unique_id) );
+    my $changesets_to_integrate = $source->fetch_changesets( after => $target->last_changeset_for_source(source => $source->unique_id) );
 
-    for my $changeset (@changesets_to_integrate) {
-        next if ( $target->has_seen_changeset(source => $source->unique_id, changeset => $changeset->unique_id));
+    for my $changeset (@$changesets_to_integrate) {
+        next if ( $target->has_seen_changeset(source => $source->unique_id, changeset => $changeset->changeset_uuid));
         if ( $target->changeset_will_conflict($changeset) ) {
             die "Conflicts are hard";
 
@@ -41,7 +40,7 @@
             $target->apply_changeset($changeset);
         }
 
-        $target->record_changeset_for_source(source => $source->unique_id, changeset => $changeset->);
+        $target->record_changeset_for_source(source => $source->unique_id, changeset => $changeset->changeset_uuid);
     }
 
 } else {

Added: SVN-PropDB/doc/glossary
==============================================================================
--- (empty file)
+++ SVN-PropDB/doc/glossary	Fri Mar  7 12:54:58 2008
@@ -0,0 +1,60 @@
+Wikipedia Fallacies_of_Distributed_Computing
+
+The Fallacies of Distributed Computing are a set of common but flawed assumptions made by programmers when first developing distributed applications. The fallacies are summarized as follows [1]:
+
+   1. The network is reliable.
+   2. Latency is zero.
+   3. Bandwidth is infinite.
+   4. The network is secure.
+   5. Topology doesn't change.
+   6. There is one administrator.
+   7. Transport cost is zero.
+   8. The network is homogeneous.
+
+
+nihao
+
+Glossary:
+
+
+Database
+    A term to describe a uniquely identified set of object types and records sharing a single 'base' revision and Replica identifier
+    A database contains multiple Records
+    
+Replica
+    An instance of a database. Replicas are expected to contain all Changesets from any other replica they have been synchronized with, but those Changesets are not guaranteed to be in the same sequence on each replica
+    
+Changeset
+    A changeset contains "old" and "new" versions of a set of database "Records", they can be of any Record Type.
+
+Change
+    An entry in a changeset. Contains all the updates to a given record for this changeset
+   
+Record
+    A Record is composed of zero or more Attributes and a universally unique identifier. Each record is categorized into a Record Type.
+        
+    (Discussion:    Really? I was just storing them under different dirs in the database. the goal was to provide a little separation between different kinds of nodes for managability.
+
+(ah fine. then need to forget about changing types ;)    
+indeed. 
+
+
+Record Type 
+    A Record Type is a category or "bucket" for zero or more records applications may define specific behaviours for Records of a certain Record Type, but Prophet does no more than to tag Records with a Record Type.
+Record Types are uniquely identified with a textual name and a UUID
+    
+    
+
+Attribute
+    A key-value pair on a Record.    
+
+Conflict
+    A Conflict occurs when a Changeset is being applied and the current state of a Replica meets any of the following criteria:
+
+        * The Replica already contains a node marked as "created" in the changeset
+        * The Replica doesn't contain a node marked as "deleted" in the changeset
+        * The Replica doesn't contain a node marked as "updated" in the changeset
+        * The Replica contains a node marked as "updated" in the changeset, but the current state of the properties on the node does not match the "old" state of the node in the changeset.
+    
+Resolution
+    When the local Replica 

Added: SVN-PropDB/doc/todo
==============================================================================
--- (empty file)
+++ SVN-PropDB/doc/todo	Fri Mar  7 12:54:58 2008
@@ -0,0 +1,12 @@
+- ability to record a merge ticket for a uuid
+- ability to read all merge tickets
+
+- 
+
+- ability to 'pull' non-conflicting updates from a remote db
+- ability to 'pull' conflicting updates from a remote db
+- ability to 'push' updates to a remote db
+- base bug tracking schemb
+- naive support for large attachments
+- elegant support for large attachments
+- Replace this todo list with a svb database

Modified: SVN-PropDB/lib/Prophet/Change.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Change.pm	(original)
+++ SVN-PropDB/lib/Prophet/Change.pm	Fri Mar  7 12:54:58 2008
@@ -9,6 +9,11 @@
 use Params::Validate;
 __PACKAGE__->mk_accessors(qw/node_type node_uuid change_type/);
 
+sub prop_changes {
+    my $self = shift;
+    return @{$self->{prop_changes}};
+}
+
 sub add_prop_change {
     my $self = shift;
     my %args = validate(@_, { name => 1, old => 0, new => 0 } );

Modified: SVN-PropDB/lib/Prophet/ChangeSet.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/ChangeSet.pm	(original)
+++ SVN-PropDB/lib/Prophet/ChangeSet.pm	Fri Mar  7 12:54:58 2008
@@ -7,7 +7,7 @@
 
 use base qw/Class::Accessor/;
 
-__PACKAGE__->mk_accessors(qw/change_uuid source_uuid/);
+__PACKAGE__->mk_accessors(qw/changeset_uuid source_uuid/);
 
 sub add_change {
     my $self = shift;
@@ -17,4 +17,9 @@
 
 }
 
+sub changes { 
+        my $self = shift;
+        return @{$self->{'changes'}||[]}
+    }
+
 1;

Modified: SVN-PropDB/lib/Prophet/Handle.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Handle.pm	(original)
+++ SVN-PropDB/lib/Prophet/Handle.pm	Fri Mar  7 12:54:58 2008
@@ -12,7 +12,7 @@
 use SVN::Repos;
 use SVN::Fs;
 
-__PACKAGE__->mk_accessors(qw(repo_path repo_handle db_root));
+__PACKAGE__->mk_accessors(qw(repo_path repo_handle db_root current_edit));
 
 sub new {
     my $class = shift;
@@ -54,9 +54,10 @@
     my $self = shift;
     my $dir  = shift;
     unless ( $self->current_root->is_dir($dir) ) {
-        my $edit = $self->begin_edit;
-        $edit->root->make_dir($dir);
-        $self->commit_edit($edit);
+        my $inside_edit = $self->current_edit ? 1: 0;
+        $self->begin_edit() unless ($inside_edit);
+        $self->current_edit->root->make_dir($dir);
+        $self->commit_edit() unless ($inside_edit);
     }
 
 }
@@ -64,86 +65,90 @@
 sub begin_edit {
     my $self = shift;
     my $fs   = $self->repo_handle->fs;
-    my $txn  = $fs->begin_txn( $fs->youngest_rev );
+    $self->current_edit( $fs->begin_txn( $fs->youngest_rev ));
 
-    return $txn;
+    return $self->current_edit;
 }
 
 sub commit_edit {
     my $self = shift;
     my $txn  = shift;
-    $txn->change_prop( 'svn:author', $ENV{'USER'} );
-    $txn->commit;
+    $self->current_edit->change_prop( 'svn:author', $ENV{'USER'} );
+    $self->current_edit->commit;
+    $self->current_edit(undef);
 
 }
 
 sub create_node {
     my $self = shift;
     my %args = validate( @_, { uuid => 1, props => 1, type => 1 } );
-    $self->_create_nonexistent_dir(
-        join( '/', $self->db_root, $args{'type'} ) );
-    my $edit = $self->begin_edit();
+
+    $self->_create_nonexistent_dir( join( '/', $self->db_root, $args{'type'} ) );
+
+    my $inside_edit = $self->current_edit ? 1: 0;
+    $self->begin_edit() unless ($inside_edit);
 
     my $file = $self->file_for( uuid => $args{uuid}, type => $args{'type'} );
-    $edit->root->make_file($file);
+    $self->current_edit->root->make_file($file);
     {
-        my $stream = $edit->root->apply_text( $file, undef );
+        my $stream = $self->current_edit->root->apply_text( $file, undef );
         print $stream Dumper( $args{'props'} );
         close $stream;
     }
     $self->_set_node_props(
         uuid  => $args{uuid},
         props => $args{props},
-        edit  => $edit,
         type  => $args{'type'}
     );
-    $self->commit_edit($edit);
+    $self->commit_edit() unless ($inside_edit);
 
 }
 
 sub _set_node_props {
     my $self = shift;
-    my %args
-        = validate( @_, { uuid => 1, props => 1, edit => 1, type => 1 } );
+    my %args = validate( @_, { uuid => 1, props => 1, type => 1 } );
+
     my $file = $self->file_for( uuid => $args{uuid}, type => $args{type} );
     foreach my $prop ( keys %{ $args{'props'} } ) {
-        $args{edit}
-            ->root->change_node_prop( $file, $prop, $args{'props'}->{$prop},
-            undef );
+        $self->current_edit->root->change_node_prop( $file, $prop, $args{'props'}->{$prop}, undef );
     }
 }
 
 sub delete_node {
     my $self = shift;
     my %args = validate( @_, { uuid => 1, type => 1 } );
-    my $edit = $self->begin_edit();
-    $edit->root->delete(
-        $self->file_for( uuid => $args{uuid}, type => $args{type} ) );
-    $self->commit_edit($edit);
 
+    my $inside_edit = $self->current_edit ? 1: 0;
+    $self->begin_edit() unless ($inside_edit);
+
+     $self->current_edit->root->delete( $self->file_for( uuid => $args{uuid}, type => $args{type} ) );
+    $self->commit_edit() unless ($inside_edit);
+    return 1;
 }
 
 sub set_node_props {
     my $self = shift;
     my %args = validate( @_, { uuid => 1, props => 1, type => 1 } );
-    my $edit = $self->begin_edit();
+
+    my $inside_edit = $self->current_edit ? 1: 0;
+    $self->begin_edit() unless ($inside_edit);
+    
     my $file = $self->file_for( uuid => $args{uuid}, type => $args{'type'} );
     $self->_set_node_props(
         uuid  => $args{uuid},
         props => $args{props},
-        edit  => $edit,
         type  => $args{'type'}
     );
-    $self->commit_edit($edit);
+    $self->commit_edit() unless ($inside_edit);
 
 }
 
 sub get_node_props {
     my $self = shift;
     my %args = validate( @_, { uuid => 1, type => 1, root => undef } );
+
     my $root = $args{'root'} || $self->current_root;
-    return $root->node_proplist(
-        $self->file_for( uuid => $args{'uuid'}, type => $args{'type'} ) );
+    return $root->node_proplist( $self->file_for( uuid => $args{'uuid'}, type => $args{'type'} ) );
 }
 
 sub file_for {
@@ -171,9 +176,10 @@
 sub record_changeset_for_source {
     my $self = shift;
     my %args = validate( @_, { source => 1,  changeset => 1} );
-    my %props = $self->get_node_props(uuid => $args{'source'}, type => $MERGETICKET_METATYPE);
-    unless ($props{'last-rev'}) {
-            $self->create_node( uuid => $args{'source'}, type => $MERGETICKET_METATYPE );
+
+    my $props = eval { $self->get_node_props(uuid => $args{'source'}, type => $MERGETICKET_METATYPE)};
+    unless ($props->{'last-rev'}) {
+            eval { $self->create_node( uuid => $args{'source'}, type => $MERGETICKET_METATYPE, props => {} )};
     }
     $self->set_node_props(uuid => $args{'source'}, type => $MERGETICKET_METATYPE, props => { 'last-rev' => $args{'changeset'}});
 

Modified: SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm	(original)
+++ SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm	Fri Mar  7 12:54:58 2008
@@ -53,28 +53,29 @@
     my @results;
     my $last_editor;
     my $handle_replayed_txn = sub {
-        $last_editor
-            = Prophet::Sync::Source::SVN::ReplayEditor->new( _debug => 0 );
+        $last_editor = Prophet::Sync::Source::SVN::ReplayEditor->new( _debug => 0 );
         $last_editor->ra( $self->ra );
         return $last_editor;
     };
 
     for my $rev ( 1 .. $self->ra->get_latest_revnum ) {
-        $Prophet::Sync::Source::SVN::ReplayEditor::CURRENT_REMOTE_REVNO
-            = $rev;
+        # This horrible hack is here because I have no idea how to pass custom variables into the editor
+        $Prophet::Sync::Source::SVN::ReplayEditor::CURRENT_REMOTE_REVNO = $rev;
 
-# This horrible hack is here because I have no idea how to pass custom variables into the editor
         $self->ra->replay( $rev, 0, 1, $handle_replayed_txn->() );
-
-        push @results, $last_editor->dump_deltas;
+        push @results, $self->_recode_changeset( $last_editor->dump_deltas);
 
     }
+    return \@results;
+}
+
+
+sub _recode_changeset {
+    my $self = shift;
+    my $entry = shift;
 
-    # XXX TODO, we should be creating the changesets directly earlier
-    my @changesets;
-    for my $entry (@results) {
         my $changeset = Prophet::ChangeSet->new(
-            {   change_uuid => $entry->{'revision'},
+            {   changeset_uuid => $entry->{'revision'}.'@'.$self->unique_id,
                 source_uuid => $self->unique_id
             }
         );
@@ -87,42 +88,69 @@
                         change_type => $entry->{'paths'}->{$path}->{'fs'}
                     }
                 );
-                for my $name (
-                    keys %{ $entry->{'paths'}->{$path}->{prop_deltas} } )
-                {
+                for my $name ( keys %{ $entry->{'paths'}->{$path}->{prop_deltas} } ) {
                     warn "Changing $name for $change";
                     $change->add_prop_change(
                         name => $name,
-                        old =>
-                            $entry->{paths}->{$path}->{prop_deltas}->{$name}
-                            ->{'old'},
-                        new =>
-                            $entry->{paths}->{$path}->{prop_deltas}->{$name}
-                            ->{'new'},
+                        old => $entry->{paths}->{$path}->{prop_deltas}->{$name}->{'old'},
+                        new => $entry->{paths}->{$path}->{prop_deltas}->{$name}->{'new'},
                     );
                 }
 
                 $changeset->add_change( change => $change );
             } else {
-                warn "Discarding change to a non-record: $path";
-                warn "Someday, we should be less stupid about this";
+                     warn "Discarding change to a non-record: $path";
             }
 
         }
-        warn YAML::Dump($changeset);
-
+        return $changeset;
     }
-
-    exit;
-    return \@changesets;
-}
-
 sub accepts_changesets {
     my $self = shift;
     return 1 if $self->prophet_handle;
     return undef;
 }
 
+
+sub has_seen_changeset { warn "\tneed to implement has_seen_changeset"; return undef;}
+sub changeset_will_conflict { warn "\tneed to implement changeset_will_conflict"; return undef }
+sub apply_changeset {
+    my $self = shift;
+    my $changeset = shift;
+    # open up a change handle locally
+    warn "Applying Changeset ".$changeset->changeset_uuid;
+
+    $self->prophet_handle->begin_edit();
+
+    for my $change ($changeset->changes) {
+        warn "\tApplying a change";
+        warn "\t".$change->change_type;
+
+        my %new_props = map { $_->name => $_->new_value } $change->prop_changes;
+
+        if ($change->change_type eq 'add_file') {
+                warn "\tAdded a file - ".$change->node_type,$change->node_uuid;
+                $self->prophet_handle->create_node(type => $change->node_type, uuid => $change->node_uuid, props => \%new_props);
+        } elsif ($change->change_type eq 'add_dir') {
+                warn "\tAdded a dir - ".$change->node_type,$change->node_uuid;
+        } elsif ($change->change_type eq 'update_file') {
+                warn "\tUpdated a file - ".$change->node_type,$change->node_uuid;
+                $self->prophet_handle->set_node_props(type => $change->node_type, uuid => $change->node_uuid, props => \%new_props);
+        } elsif ($change->change_type eq 'delete') {
+                warn "\tDeleted file - ".$change->node_type,$change->node_uuid;
+                $self->prophet_handle->delete_node(type => $change->node_type, uuid => $change->node_uuid);
+        }
+
+    }
+
+    $self->prophet_handle->commit_edit();
+
+    # finalize the local change
+}
+
+
+
+
 # XXX TODO this is hacky as hell and violates abstraction barriers in the name of doing things over the RA
 sub last_changeset_for_source {
     my $self = shift;



More information about the Bps-public-commit mailing list