[Bps-public-commit] r11408 - in SVN-PropDB: . doc lib/Prophet/Sync/Source lib/Prophet/Test
jesse at bestpractical.com
jesse at bestpractical.com
Wed Apr 2 21:48:03 EDT 2008
Author: jesse
Date: Wed Apr 2 21:48:02 2008
New Revision: 11408
Modified:
SVN-PropDB/ (props changed)
SVN-PropDB/doc/todo
SVN-PropDB/lib/Prophet/Sync/Source.pm
SVN-PropDB/lib/Prophet/Sync/Source/SVN.pm
SVN-PropDB/lib/Prophet/Test/Participant.pm
Log:
r29018 at 70-5-158-116: jesse | 2008-04-02 15:45:39 -1000
* checkpoint
Modified: SVN-PropDB/doc/todo
==============================================================================
--- SVN-PropDB/doc/todo (original)
+++ SVN-PropDB/doc/todo Wed Apr 2 21:48:02 2008
@@ -1,12 +1,21 @@
Todo
-- test byzantine sync behaviour
-- handle conflicting conflict resolutions
+- ::CLI should automatically discover an app's model class based on the type name
+- Creation of bug tracking model classes
+
+
+
+- validation on bug tracker fields (status/severity)
+
+- ability to add comments to a bug (visible history entries)
+
+- push to a remote prophet
+- pull from a remote RT by url and query
+- push to a remote RT
-- base bug tracking schema
- Replace this todo list with a svb database
- elegant support for large attachments
- RESTy web server API to let third-parties build non-perl apps against a Prophet Depot
@@ -51,3 +60,7 @@
- prompt for resolution of conflicts
- handle file_conflict
+- test byzantine sync behaviour
+- handle conflicting conflict resolutions
+- base bug tracking schema
+
Modified: SVN-PropDB/lib/Prophet/Sync/Source.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Sync/Source.pm (original)
+++ SVN-PropDB/lib/Prophet/Sync/Source.pm Wed Apr 2 21:48:02 2008
@@ -55,7 +55,8 @@
use_resdb => { optional => 1 },
resolver => { optional => 1 },
resolver_class => { optional => 1 },
- conflict_callback => { optional => 1 }
+ conflict_callback => { optional => 1 },
+ reporting_callback => { optional => 1 }
}
);
@@ -73,14 +74,183 @@
$self->integrate_changeset(
changeset => $changeset,
conflict_callback => $args{conflict_callback},
+ reporting_callback => $args{'reporting_callback'},
resolver => $args{resolver},
resolver_class => $args{'resolver_class'},
resdb => $resdb
);
+
}
}
+=head2 integrate_changeset L<Prophet::ChangeSet>
+
+If there are conflicts, generate a nullification change, figure out a conflict resolution and apply the nullification, original change and resolution all at once (as three separate changes).
+
+If there are no conflicts, just apply the change.
+
+=cut
+
+sub integrate_changeset {
+ my $self = shift;
+ my %args = validate(
+ @_,
+ { changeset => { isa => 'Prophet::ChangeSet' },
+ resolver => { optional => 1 },
+ resolver_class => { optional => 1 },
+ resdb => { optional => 1 },
+ conflict_callback => { optional => 1 },
+ reporting_callback => {optional =>1}
+ }
+ );
+
+ my $changeset = $args{'changeset'};
+
+ # when we start to integrate a changeset, we need to do a bit of housekeeping
+ # We never want to merge in:
+ # merge tickets that describe merges from the local node
+
+ # When we integrate changes, sometimes we will get handed changes we already know about.
+ # - changes from local
+ # - changes from some other party we've merged from
+ # - merge tickets for the same
+ # we'll want to skip or remove those changesets
+
+ return if $changeset->original_source_uuid eq $self->prophet_handle->uuid;
+
+ $self->remove_redundant_data($changeset); #Things we have already seen
+
+ return if ( $changeset->is_empty or $changeset->is_nullification );
+
+ if ( my $conflict = $self->conflicts_from_changeset($changeset) ) {
+ $args{conflict_callback}->($conflict) if $args{'conflict_callback'};
+ $conflict->resolvers( [ sub { $args{resolver}->(@_) } ] ) if $args{resolver};
+ if ( $args{resolver_class} ) {
+ $args{resolver_class}->require || die $@;
+ $conflict->resolvers( [ sub { warn "CAlling ".$args{resolver_class};
+ $args{resolver_class}->new->run(@_); } ] )
+
+ }
+ my $resolutions = $conflict->generate_resolution( $args{resdb} );
+
+ #figure out our conflict resolution
+
+ # IMPORTANT: these should be an atomic unit. dying here would be poor. BUT WE WANT THEM AS THREEDIFFERENT SVN REVS
+ # integrate the nullification change
+ $self->prophet_handle->record_changeset( $conflict->nullification_changeset );
+
+ # integrate the original change
+ $self->prophet_handle->integrate_changeset($changeset);
+
+ # integrate the conflict resolution change
+ $self->prophet_handle->record_resolutions( $conflict->resolution_changeset,
+ $self->ressource ? $self->ressource->prophet_handle : $self->prophet_handle );
+ $args{'reporting_callback'}->( changeset => $changeset, conflict => $conflict ) if ($args{'reporting_callback'}) ;
+
+
+ } else {
+ $self->prophet_handle->integrate_changeset($changeset);
+ $args{'reporting_callback'}->( changeset => $changeset ) if ($args{'reporting_callback'}) ;
+
+
+ }
+
+
+
+}
+
+
+=head2 accepts_changesets
+
+Returns true if this source is one we know how to write to (and have permission to write to)
+
+Returns false otherwise
+
+=cut
+
+sub accepts_changesets {
+ my $self = shift;
+
+ return 1 if $self->prophet_handle;
+ return undef;
+}
+
+=head2 has_seen_changeset Prophet::ChangeSet
+
+Returns true if we've previously integrated this changeset, even if we originally recieved it from a different peer
+
+=cut
+
+sub has_seen_changeset {
+ my $self = shift;
+ my ($changeset) = validate_pos( @_, { isa => "Prophet::ChangeSet" } );
+
+ # If the changeset originated locally, we never want it
+ return 1 if $changeset->original_source_uuid eq $self->uuid;
+
+ # Otherwise, if the we have a merge ticket from the source, we don't want the changeset
+ my $last = $self->last_changeset_from_source( $changeset->original_source_uuid );
+
+ # if the source's sequence # is >= the changeset's sequence #, we can safely skip it
+ return 1 if ( $last >= $changeset->original_sequence_no );
+ return undef;
+}
+
+=head2 changeset_will_conflict Prophet::ChangeSet
+
+Returns true if any change that's part of this changeset won't apply cleanly to the head of the current replica
+
+=cut
+
+sub changeset_will_conflict {
+ my $self = shift;
+ my ($changeset) = validate_pos( @_, { isa => "Prophet::ChangeSet" } );
+
+ return 1 if ( $self->conflicts_from_changeset($changeset) );
+
+ return undef;
+
+}
+
+=head2 conflicts_from_changeset Prophet::ChangeSet
+
+Returns a L<Prophet::Conflict/> object if the supplied L<Prophet::ChangeSet/>
+will generate conflicts if applied to the current replica.
+
+Returns undef if the current changeset wouldn't generate a conflict.
+
+=cut
+
+sub conflicts_from_changeset {
+ my $self = shift;
+ my ($changeset) = validate_pos( @_, { isa => "Prophet::ChangeSet" } );
+
+ my $conflict = Prophet::Conflict->new( { changeset => $changeset, prophet_handle => $self->prophet_handle } );
+
+ $conflict->analyze_changeset();
+
+ return undef unless @{ $conflict->conflicting_changes };
+
+ return $conflict;
+
+}
+
+sub remove_redundant_data {
+ my ( $self, $changeset ) = @_;
+
+ # XXX: encapsulation
+ $changeset->{changes} = [
+ grep { $self->is_resdb || $_->node_type ne '_prophet_resolution' } grep {
+ !( $_->node_type eq $Prophet::Handle::MERGETICKET_METATYPE && $_->node_uuid eq $self->prophet_handle->uuid )
+ } $changeset->changes
+ ];
+}
+
+
+
+
+
sub fetch_resolutions {
my $self = shift;
my %args = validate(
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 Wed Apr 2 21:48:02 2008
@@ -144,157 +144,6 @@
return $changeset;
}
-=head2 accepts_changesets
-
-Returns true if this source is one we know how to write to (and have permission to write to)
-
-Returns false otherwise
-
-=cut
-
-sub accepts_changesets {
- my $self = shift;
-
- return 1 if $self->prophet_handle;
- return undef;
-}
-
-=head2 has_seen_changeset Prophet::ChangeSet
-
-Returns true if we've previously integrated this changeset, even if we originally recieved it from a different peer
-
-=cut
-
-sub has_seen_changeset {
- my $self = shift;
- my ($changeset) = validate_pos( @_, { isa => "Prophet::ChangeSet" } );
-
- # If the changeset originated locally, we never want it
- return 1 if $changeset->original_source_uuid eq $self->uuid;
-
- # Otherwise, if the we have a merge ticket from the source, we don't want the changeset
- my $last = $self->last_changeset_from_source( $changeset->original_source_uuid );
-
- # if the source's sequence # is >= the changeset's sequence #, we can safely skip it
- return 1 if ( $last >= $changeset->original_sequence_no );
- return undef;
-}
-
-=head2 changeset_will_conflict Prophet::ChangeSet
-
-Returns true if any change that's part of this changeset won't apply cleanly to the head of the current replica
-
-=cut
-
-sub changeset_will_conflict {
- my $self = shift;
- my ($changeset) = validate_pos( @_, { isa => "Prophet::ChangeSet" } );
-
- return 1 if ( $self->conflicts_from_changeset($changeset) );
-
- return undef;
-
-}
-
-=head2 conflicts_from_changeset Prophet::ChangeSet
-
-Returns a L<Prophet::Conflict/> object if the supplied L<Prophet::ChangeSet/>
-will generate conflicts if applied to the current replica.
-
-Returns undef if the current changeset wouldn't generate a conflict.
-
-=cut
-
-sub conflicts_from_changeset {
- my $self = shift;
- my ($changeset) = validate_pos( @_, { isa => "Prophet::ChangeSet" } );
-
- my $conflict = Prophet::Conflict->new( { changeset => $changeset, prophet_handle => $self->prophet_handle } );
-
- $conflict->analyze_changeset();
-
- return undef unless @{ $conflict->conflicting_changes };
-
- return $conflict;
-
-}
-
-=head2 integrate_changeset L<Prophet::ChangeSet>
-
-If there are conflicts, generate a nullification change, figure out a conflict resolution and apply the nullification, original change and resolution all at once (as three separate changes).
-
-If there are no conflicts, just apply the change.
-
-=cut
-
-sub integrate_changeset {
- my $self = shift;
- my %args = validate(
- @_,
- { changeset => { isa => 'Prophet::ChangeSet' },
- resolver => { optional => 1 },
- resolver_class => { optional => 1 },
- resdb => { optional => 1 },
- conflict_callback => { optional => 1 }
- }
- );
-
- my $changeset = $args{'changeset'};
-
- # when we start to integrate a changeset, we need to do a bit of housekeeping
- # We never want to merge in:
- # merge tickets that describe merges from the local node
-
- # When we integrate changes, sometimes we will get handed changes we already know about.
- # - changes from local
- # - changes from some other party we've merged from
- # - merge tickets for the same
- # we'll want to skip or remove those changesets
-
- return if $changeset->original_source_uuid eq $self->prophet_handle->uuid;
-
- $self->remove_redundant_data($changeset); #Things we have already seen
-
- return if ( $changeset->is_empty or $changeset->is_nullification );
-
- if ( my $conflict = $self->conflicts_from_changeset($changeset) ) {
- $args{conflict_callback}->($conflict) if $args{'conflict_callback'};
- $conflict->resolvers( [ sub { $args{resolver}->(@_) } ] ) if $args{resolver};
- if ( $args{resolver_class} ) {
- $args{resolver_class}->require || die $@;
- $conflict->resolvers( [ sub { $args{resolver_class}->run(@_); } ] )
-
- }
- my $resolutions = $conflict->generate_resolution( $args{resdb} );
-
- #figure out our conflict resolution
-
- # IMPORTANT: these should be an atomic unit. dying here would be poor. BUT WE WANT THEM AS THREEDIFFERENT SVN REVS
- # integrate the nullification change
- $self->prophet_handle->record_changeset( $conflict->nullification_changeset );
-
- # integrate the original change
- $self->prophet_handle->integrate_changeset($changeset);
-
- # integrate the conflict resolution change
- $self->prophet_handle->record_resolutions( $conflict->resolution_changeset,
- $self->ressource ? $self->ressource->prophet_handle : $self->prophet_handle );
- } else {
- $self->prophet_handle->integrate_changeset($changeset);
-
- }
-}
-
-sub remove_redundant_data {
- my ( $self, $changeset ) = @_;
-
- # XXX: encapsulation
- $changeset->{changes} = [
- grep { $self->is_resdb || $_->node_type ne '_prophet_resolution' } grep {
- !( $_->node_type eq $Prophet::Handle::MERGETICKET_METATYPE && $_->node_uuid eq $self->prophet_handle->uuid )
- } $changeset->changes
- ];
-}
=head2 last_changeset_from_source $SOURCE_UUID
@@ -314,6 +163,8 @@
# XXX TODO this is hacky as hell and violates abstraction barriers in the name of doing things over the RA
# because we want to be able to sync to a remote replica someday.
+
+
return ( $props->{'last-changeset'} || 0 );
}
Modified: SVN-PropDB/lib/Prophet/Test/Participant.pm
==============================================================================
--- SVN-PropDB/lib/Prophet/Test/Participant.pm (original)
+++ SVN-PropDB/lib/Prophet/Test/Participant.pm Wed Apr 2 21:48:02 2008
@@ -192,7 +192,8 @@
my $ret;
my $pool = SVN::Pool->new_default;
if ( my $sub = $cli->can( 'do_' . $cmd ) ) {
- in_gladiator { $ret = $sub->($cli) };
+ # in_gladiator
+ { $ret = $sub->($cli) }
} else {
die "I don't know how to do the $cmd";
}
More information about the Bps-public-commit
mailing list