|
% those are the ported lines of code |
|
% they come from here: https://github.com/apache/couchdb-couch-replicator/blob/master/src/couch_replicator.erl#L863-L906 |
|
|
|
compare_replication_logs(SrcDoc, TgtDoc) -> |
|
#doc{body={RepRecProps}} = SrcDoc, |
|
#doc{body={RepRecPropsTgt}} = TgtDoc, |
|
case get_value(<<"session_id">>, RepRecProps) == |
|
get_value(<<"session_id">>, RepRecPropsTgt) of |
|
true -> |
|
% if the records have the same session id, |
|
% then we have a valid replication history |
|
OldSeqNum = get_value(<<"source_last_seq">>, RepRecProps, ?LOWEST_SEQ), |
|
OldHistory = get_value(<<"history">>, RepRecProps, []), |
|
{OldSeqNum, OldHistory}; |
|
false -> |
|
SourceHistory = get_value(<<"history">>, RepRecProps, []), |
|
TargetHistory = get_value(<<"history">>, RepRecPropsTgt, []), |
|
couch_log:notice("Replication records differ. " |
|
"Scanning histories to find a common ancestor.", []), |
|
couch_log:debug("Record on source:~p~nRecord on target:~p~n", |
|
[RepRecProps, RepRecPropsTgt]), |
|
compare_rep_history(SourceHistory, TargetHistory) |
|
end. |
|
|
|
compare_rep_history(S, T) when S =:= [] orelse T =:= [] -> |
|
couch_log:notice("no common ancestry -- performing full replication", []), |
|
{?LOWEST_SEQ, []}; |
|
compare_rep_history([{S} | SourceRest], [{T} | TargetRest] = Target) -> |
|
SourceId = get_value(<<"session_id">>, S), |
|
case has_session_id(SourceId, Target) of |
|
true -> |
|
RecordSeqNum = get_value(<<"recorded_seq">>, S, ?LOWEST_SEQ), |
|
couch_log:notice("found a common replication record with source_seq ~p", |
|
[RecordSeqNum]), |
|
{RecordSeqNum, SourceRest}; |
|
false -> |
|
TargetId = get_value(<<"session_id">>, T), |
|
case has_session_id(TargetId, SourceRest) of |
|
true -> |
|
RecordSeqNum = get_value(<<"recorded_seq">>, T, ?LOWEST_SEQ), |
|
couch_log:notice("found a common replication record with source_seq ~p", |
|
[RecordSeqNum]), |
|
{RecordSeqNum, TargetRest}; |
|
false -> |
|
compare_rep_history(SourceRest, TargetRest) |
|
end |
|
end. |
|
|
|
|
|
has_session_id(_SessionId, []) -> |
|
false; |
|
has_session_id(SessionId, [{Props} | Rest]) -> |
|
case get_value(<<"session_id">>, Props, nil) of |
|
SessionId -> |
|
true; |
|
_Else -> |
|
has_session_id(SessionId, Rest) |
|
end. |
Typo on L33 but yes, this looks like a faithful JS implementation of the Erlang algorithm.