diff --git a/db/active_replicator.go b/db/active_replicator.go index 597d6a7641..45fc9f30a2 100644 --- a/db/active_replicator.go +++ b/db/active_replicator.go @@ -258,6 +258,9 @@ func connect(arc *activeReplicatorCommon, idSuffix string) (blipSender *blip.Sen return nil, nil, err } + // set client type to SGW on active peer + bsc.SetClientType(BLIPClientTypeSGR2) + // set active subprotocol after handshake err = bsc.SetActiveCBMobileSubprotocol(blipContext.ActiveSubprotocol()) if err != nil { diff --git a/db/blip.go b/db/blip.go index 9d9a14ddf3..c0087a4397 100644 --- a/db/blip.go +++ b/db/blip.go @@ -84,7 +84,7 @@ func defaultBlipLogger(ctx context.Context) blip.LogFn { } // blipRevMessageProperties returns a set of BLIP message properties for the given parameters. -func blipRevMessageProperties(revisionHistory []string, deleted bool, seq SequenceID, replacedRevID string) blip.Properties { +func blipRevMessageProperties(revisionHistory []string, deleted bool, seq SequenceID, replacedRevID string, revTreeProperty []string) blip.Properties { properties := make(blip.Properties) // TODO: Assert? db.SequenceID.MarshalJSON can never error @@ -95,6 +95,10 @@ func blipRevMessageProperties(revisionHistory []string, deleted bool, seq Sequen properties[RevMessageHistory] = strings.Join(revisionHistory, ",") } + if len(revTreeProperty) > 0 { + properties[RevMessageTreeHistory] = strings.Join(revTreeProperty, ",") + } + if deleted { properties[RevMessageDeleted] = "1" } diff --git a/db/blip_handler.go b/db/blip_handler.go index 48ac4047c7..11fd953485 100644 --- a/db/blip_handler.go +++ b/db/blip_handler.go @@ -908,12 +908,18 @@ func (bsc *BlipSyncContext) sendRevAsDelta(ctx context.Context, sender *blip.Sen if redactedRev != nil { var history []string + var revTreeProperty []string if !bsc.useHLV() { history = toHistory(redactedRev.History, knownRevs, maxHistory) } else { history = append(history, redactedRev.hlvHistory) } - properties := blipRevMessageProperties(history, redactedRev.Deleted, seq, "") + if bsc.sendRevTreeProperty() { + revTreeProperty = append(revTreeProperty, redactedRev.RevID) + revTreeProperty = append(revTreeProperty, toHistory(redactedRev.History, knownRevs, maxHistory)...) + } + + properties := blipRevMessageProperties(history, redactedRev.Deleted, seq, "", revTreeProperty) return bsc.sendRevisionWithProperties(ctx, sender, docID, revID, collectionIdx, redactedRev.BodyBytes, nil, properties, seq, nil) } @@ -1078,6 +1084,9 @@ func (bh *blipHandler) processRev(rq *blip.Message, stats *processRevStats) (err var incomingHLV *HybridLogicalVector // Build history/HLV var legacyRevList []string + // we can probably use legacyRevList instead of this but to avoid hooking this up to write code we will use + // separate list for now, pending CBG-4790 + var revTreeProperty []string changeIsVector := strings.Contains(rev, "@") if !bh.useHLV() || !changeIsVector { newDoc.RevID = rev @@ -1103,6 +1112,14 @@ func (bh *blipHandler) processRev(rq *blip.Message, stats *processRevStats) (err newDoc.HLV = incomingHLV } + // if the client is SGW and there are no legacy revs being sent (i.e. doc is not a pre-upgraded doc) check the rev tree property + if bh.clientType == BLIPClientTypeSGR2 && len(legacyRevList) == 0 { + revTree, ok := rq.Properties[RevMessageTreeHistory] + if ok { + revTreeProperty = append(revTreeProperty, strings.Split(revTree, ",")...) // nolint: all + } + } + newDoc.UpdateBodyBytes(bodyBytes) injectedAttachmentsForDelta := false diff --git a/db/blip_sync_context.go b/db/blip_sync_context.go index 1d06871cd4..b6cf923879 100644 --- a/db/blip_sync_context.go +++ b/db/blip_sync_context.go @@ -605,12 +605,17 @@ func (bsc *BlipSyncContext) setUseDeltas(clientCanUseDeltas bool) { func (bsc *BlipSyncContext) sendDelta(ctx context.Context, sender *blip.Sender, docID string, collectionIdx *int, deltaSrcRevID string, revDelta *RevisionDelta, seq SequenceID, resendFullRevisionFunc func() error) error { var history []string + var revTreeProperty []string if bsc.useHLV() { history = append(history, revDelta.HlvHistory) } else { history = revDelta.RevisionHistory } - properties := blipRevMessageProperties(history, revDelta.ToDeleted, seq, "") + if bsc.sendRevTreeProperty() { + revTreeProperty = append(revTreeProperty, revDelta.ToRevID) + revTreeProperty = append(revTreeProperty, revDelta.RevisionHistory...) + } + properties := blipRevMessageProperties(history, revDelta.ToDeleted, seq, "", revTreeProperty) properties[RevMessageDeltaSrc] = deltaSrcRevID base.DebugfCtx(ctx, base.KeySync, "Sending rev %q %s as delta. DeltaSrc:%s", base.UD(docID), revDelta.ToRevID, deltaSrcRevID) @@ -768,14 +773,20 @@ func (bsc *BlipSyncContext) sendRevision(ctx context.Context, sender *blip.Sende history = append(history, docRev.hlvHistory) } } + + var revTreeHistoryProperty []string if legacyRev { // append current revID and rest of rev tree after hlv history revTreeHistory := toHistory(docRev.History, knownRevs, maxHistory) history = append(history, docRev.RevID) history = append(history, revTreeHistory...) + } else if bsc.sendRevTreeProperty() { + // if no legacy revs being sent and we are communicating with SGW client we should send revision history in the rev message + revTreeHistoryProperty = append(revTreeHistoryProperty, docRev.RevID) // we need current rev + revTreeHistoryProperty = append(revTreeHistoryProperty, toHistory(docRev.History, knownRevs, maxHistory)...) } - properties := blipRevMessageProperties(history, docRev.Deleted, seq, replacedRevID) + properties := blipRevMessageProperties(history, docRev.Deleted, seq, replacedRevID, revTreeHistoryProperty) if base.LogDebugEnabled(ctx, base.KeySync) { replacedRevMsg := "" if replacedRevID != "" { @@ -851,3 +862,9 @@ func (bsc *BlipSyncContext) reportStats(updateImmediately bool) { func (bsc *BlipSyncContext) useHLV() bool { return bsc.activeCBMobileSubprotocol >= CBMobileReplicationV4 } + +// sendRevTreeProperty returns true if the rev tree property should be sent in the rev message. That is if we are +// replicating with version vectors and the client we're communicating with is a SGW peer +func (bsc *BlipSyncContext) sendRevTreeProperty() bool { + return bsc.activeCBMobileSubprotocol >= CBMobileReplicationV4 && bsc.clientType == BLIPClientTypeSGR2 +} diff --git a/db/blip_sync_messages.go b/db/blip_sync_messages.go index 68de19d6c6..6740a38bfd 100644 --- a/db/blip_sync_messages.go +++ b/db/blip_sync_messages.go @@ -77,6 +77,7 @@ const ( RevMessageDeleted = "deleted" RevMessageSequence = "sequence" RevMessageHistory = "history" + RevMessageTreeHistory = "revTree" RevMessageNoConflicts = "noconflicts" RevMessageDeltaSrc = "deltaSrc" RevMessageReplacedRev = "replacedRev"