@@ -1211,7 +1211,7 @@ func (db *DatabaseCollectionWithUser) Put(ctx context.Context, docid string, bod
1211
1211
return newRevID , doc , err
1212
1212
}
1213
1213
1214
- func (db * DatabaseCollectionWithUser ) PutExistingCurrentVersion (ctx context.Context , newDoc * Document , newDocHLV * HybridLogicalVector , existingDoc * sgbucket.BucketDocument , revTreeHistory []string ) (doc * Document , cv * Version , newRevID string , err error ) {
1214
+ func (db * DatabaseCollectionWithUser ) PutExistingCurrentVersion (ctx context.Context , newDoc * Document , newDocHLV * HybridLogicalVector , existingDoc * sgbucket.BucketDocument , revTreeHistory []string , revTreeISGRProperty bool ) (doc * Document , cv * Version , newRevID string , err error ) {
1215
1215
var matchRev string
1216
1216
if existingDoc != nil {
1217
1217
doc , unmarshalErr := db .unmarshalDocumentWithXattrs (ctx , newDoc .ID , existingDoc .Body , existingDoc .Xattrs , existingDoc .Cas , DocUnmarshalRev )
@@ -1262,7 +1262,14 @@ func (db *DatabaseCollectionWithUser) PutExistingCurrentVersion(ctx context.Cont
1262
1262
} else {
1263
1263
previousRevTreeID = revTreeHistory [0 ]
1264
1264
prevGeneration , _ = ParseRevID (ctx , previousRevTreeID )
1265
- newGeneration = prevGeneration + 1
1265
+ // if incoming rev tree list is from a legacy pre upgraded doc, we should have new revID generation based
1266
+ // off the previous current rev +1. If we have rev tree list filled from ISGR's rev tree property then we
1267
+ // should use the current rev of inc
1268
+ if ! revTreeISGRProperty {
1269
+ newGeneration = prevGeneration + 1
1270
+ } else {
1271
+ newGeneration = prevGeneration
1272
+ }
1266
1273
}
1267
1274
revTreeConflictChecked := false
1268
1275
var parent string
@@ -1276,6 +1283,12 @@ func (db *DatabaseCollectionWithUser) PutExistingCurrentVersion(ctx context.Cont
1276
1283
if addNewerVersionsErr != nil {
1277
1284
return nil , nil , false , nil , addNewerVersionsErr
1278
1285
}
1286
+ if revTreeISGRProperty {
1287
+ err = doc .alignRevTreeHistory (ctx , newDoc , revTreeHistory )
1288
+ if err != nil {
1289
+ return nil , nil , false , nil , err
1290
+ }
1291
+ }
1279
1292
} else {
1280
1293
if doc .HLV .isDominating (newDocHLV ) {
1281
1294
base .DebugfCtx (ctx , base .KeyCRUD , "PutExistingCurrentVersion(%q): No new versions to add. existing: %#v new:%#v" , base .UD (newDoc .ID ), doc .HLV , newDocHLV )
@@ -1289,15 +1302,28 @@ func (db *DatabaseCollectionWithUser) PutExistingCurrentVersion(ctx context.Cont
1289
1302
}
1290
1303
// the new document has a dominating hlv, so we can ignore any legacy rev revtree information on the incoming document
1291
1304
revTreeConflictChecked = true
1292
- previousRevTreeID = doc .CurrentRev
1305
+ if ! revTreeISGRProperty {
1306
+ previousRevTreeID = doc .CurrentRev
1307
+ } else {
1308
+ // align rev tree here for ISGR replications
1309
+ err = doc .alignRevTreeHistory (ctx , newDoc , revTreeHistory )
1310
+ if err != nil {
1311
+ return nil , nil , false , nil , err
1312
+ }
1313
+ }
1293
1314
} else {
1294
- if len (revTreeHistory ) > 0 {
1315
+ // if the legacy rev list is from ISGR property, we should not do a conflict check
1316
+ if len (revTreeHistory ) > 0 && ! revTreeISGRProperty {
1295
1317
// conflict check on rev tree history, if there is a rev in rev tree history we have the parent of locally we are not in conflict
1296
1318
parent , currentRevIndex , err = db .revTreeConflictCheck (ctx , revTreeHistory , doc , newDoc .Deleted )
1297
1319
if err != nil {
1298
1320
base .InfofCtx (ctx , base .KeyCRUD , "conflict detected between the two HLV's for doc %s, incoming version %s, local version %s, and conflict found in rev tree history" , base .UD (doc .ID ), newDocHLV .GetCurrentVersionString (), doc .HLV .GetCurrentVersionString ())
1299
1321
return nil , nil , false , nil , err
1300
1322
}
1323
+ err = doc .addNewerRevisionsToHistory (newDoc , currentRevIndex , parent , revTreeHistory )
1324
+ if err != nil {
1325
+ return nil , nil , false , nil , err
1326
+ }
1301
1327
revTreeConflictChecked = true
1302
1328
addNewerVersionsErr := doc .HLV .AddNewerVersions (newDocHLV )
1303
1329
if addNewerVersionsErr != nil {
@@ -1317,24 +1343,15 @@ func (db *DatabaseCollectionWithUser) PutExistingCurrentVersion(ctx context.Cont
1317
1343
// rev tree conflict check if we have rev tree history to check against + finds current rev index to allow us
1318
1344
// to add any new revision to rev tree below.
1319
1345
// Only check for rev tree conflicts if we haven't already checked above
1320
- if ! revTreeConflictChecked && len (revTreeHistory ) > 0 {
1346
+ if ! revTreeConflictChecked && len (revTreeHistory ) > 0 && ! revTreeISGRProperty {
1321
1347
parent , currentRevIndex , err = db .revTreeConflictCheck (ctx , revTreeHistory , doc , newDoc .Deleted )
1322
1348
if err != nil {
1323
1349
return nil , nil , false , nil , err
1324
1350
}
1325
- }
1326
- // Add all the new revisions to the rev tree:
1327
- for i := currentRevIndex - 1 ; i >= 0 ; i -- {
1328
- err := doc .History .addRevision (newDoc .ID ,
1329
- RevInfo {
1330
- ID : revTreeHistory [i ],
1331
- Parent : parent ,
1332
- Deleted : i == 0 && newDoc .Deleted })
1333
-
1351
+ err = doc .addNewerRevisionsToHistory (newDoc , currentRevIndex , parent , revTreeHistory )
1334
1352
if err != nil {
1335
1353
return nil , nil , false , nil , err
1336
1354
}
1337
- parent = revTreeHistory [i ]
1338
1355
}
1339
1356
1340
1357
// Process the attachments, replacing bodies with digests.
@@ -1344,16 +1361,23 @@ func (db *DatabaseCollectionWithUser) PutExistingCurrentVersion(ctx context.Cont
1344
1361
}
1345
1362
1346
1363
// generate rev id for new arriving doc
1347
- strippedBody , _ := stripInternalProperties (newDoc ._body )
1348
- encoding , err := base .JSONMarshalCanonical (strippedBody )
1349
- if err != nil {
1350
- return nil , nil , false , nil , err
1351
- }
1352
- newRev := CreateRevIDWithBytes (newGeneration , previousRevTreeID , encoding )
1353
-
1354
- if err := doc .History .addRevision (newDoc .ID , RevInfo {ID : newRev , Parent : previousRevTreeID , Deleted : newDoc .Deleted }); err != nil {
1355
- base .InfofCtx (ctx , base .KeyCRUD , "Failed to add revision ID: %s, for doc: %s, error: %v" , newRev , base .UD (newDoc .ID ), err )
1356
- return nil , nil , false , nil , base .ErrRevTreeAddRevFailure
1364
+ var newRev string
1365
+ if ! revTreeISGRProperty {
1366
+ // create a new revID for incoming write
1367
+ strippedBody , _ := stripInternalProperties (newDoc ._body )
1368
+ encoding , err := base .JSONMarshalCanonical (strippedBody )
1369
+ if err != nil {
1370
+ return nil , nil , false , nil , err
1371
+ }
1372
+ newRev = CreateRevIDWithBytes (newGeneration , previousRevTreeID , encoding )
1373
+ if err := doc .History .addRevision (newDoc .ID , RevInfo {ID : newRev , Parent : previousRevTreeID , Deleted : newDoc .Deleted }); err != nil {
1374
+ base .InfofCtx (ctx , base .KeyCRUD , "Failed to add revision ID: %s, for doc: %s, error: %v" , newRev , base .UD (newDoc .ID ), err )
1375
+ return nil , nil , false , nil , base .ErrRevTreeAddRevFailure
1376
+ }
1377
+ } else {
1378
+ // for ISGR, incoming writes current rev should be the most recent rev in history. This aligns the
1379
+ // rev history each of the replication
1380
+ newRev = previousRevTreeID
1357
1381
}
1358
1382
1359
1383
newDoc .RevID = newRev
@@ -3137,7 +3161,6 @@ func (db *DatabaseCollectionWithUser) CheckChangeVersion(ctx context.Context, do
3137
3161
if strings .HasPrefix (docid , "_design/" ) && db .user != nil {
3138
3162
return // Users can't upload design docs, so ignore them
3139
3163
}
3140
- // todo: CBG-4782 utilise known revs for rev tree property in ISGR by returning know rev tree id's in possible list
3141
3164
3142
3165
doc , err := db .GetDocSyncDataNoImport (ctx , docid , DocUnmarshalSync )
3143
3166
if err != nil {
@@ -3147,6 +3170,14 @@ func (db *DatabaseCollectionWithUser) CheckChangeVersion(ctx context.Context, do
3147
3170
missing = append (missing , rev )
3148
3171
return
3149
3172
}
3173
+ if doc .HLV == nil {
3174
+ // no hlv on local doc, mark as missing but send current rev as known rev (will be handled as legacy
3175
+ // rev document on changes response handler)
3176
+ base .DebugfCtx (ctx , base .KeyChanges , "Doc %s has no HLV, marking change version %s as missing" , base .UD (docid ), base .UD (rev ))
3177
+ missing = append (missing , rev )
3178
+ possible = append (possible , doc .CurrentRev )
3179
+ return
3180
+ }
3150
3181
// parse in coming version, if it's not known to local doc hlv then it is marked as missing, if it is and is a newer version
3151
3182
// then it is also marked as missing
3152
3183
cvValue , err := ParseVersion (rev )
@@ -3160,6 +3191,13 @@ func (db *DatabaseCollectionWithUser) CheckChangeVersion(ctx context.Context, do
3160
3191
// incoming version is dominated by local doc hlv, so it is not missing
3161
3192
return
3162
3193
}
3194
+
3195
+ // return the local current rev as known rev, this will mean if you have rev 1,2,3 and remote has rev 1,2,3,4,5 then
3196
+ // remote should only send rev 4,5 in rev tree property on the subsequent rev message for this document, we also need to
3197
+ // send cv as first element for delta sync purposes
3198
+ possible = append (possible , doc .HLV .GetCurrentVersionString ())
3199
+ possible = append (possible , doc .CurrentRev )
3200
+
3163
3201
missing = append (missing , rev )
3164
3202
return
3165
3203
}
@@ -3328,6 +3366,47 @@ func (db *DatabaseCollectionWithUser) CheckProposedVersion(ctx context.Context,
3328
3366
}
3329
3367
}
3330
3368
3369
+ func (doc * Document ) alignRevTreeHistory (ctx context.Context , newDoc * Document , revTreeHistory []string ) error {
3370
+ currentRevIndex := len (revTreeHistory )
3371
+ parent := ""
3372
+ for i , revid := range revTreeHistory {
3373
+ if doc .History .contains (revid ) {
3374
+ currentRevIndex = i
3375
+ parent = revid
3376
+ break
3377
+ }
3378
+ }
3379
+
3380
+ if parent != doc .CurrentRev {
3381
+ base .DebugfCtx (ctx , base .KeyCRUD , "incoming rev tree history has different history than local doc %s, aligning local doc history with incoming rev tree history" , base .UD (doc .ID ))
3382
+ // clean local history and make way for incoming history to replace it
3383
+ doc .History = make (RevTree )
3384
+ }
3385
+
3386
+ err := doc .addNewerRevisionsToHistory (newDoc , currentRevIndex , parent , revTreeHistory )
3387
+ if err != nil {
3388
+ return err
3389
+ }
3390
+ return nil
3391
+ }
3392
+
3393
+ func (doc * Document ) addNewerRevisionsToHistory (newDoc * Document , currentRevIndex int , parent string , docHistory []string ) error {
3394
+ for i := currentRevIndex - 1 ; i >= 0 ; i -- {
3395
+ err := doc .History .addRevision (newDoc .ID ,
3396
+ RevInfo {
3397
+ ID : docHistory [i ],
3398
+ Parent : parent ,
3399
+ Deleted : i == 0 && newDoc .Deleted })
3400
+
3401
+ if err != nil {
3402
+ return err
3403
+ }
3404
+ parent = docHistory [i ]
3405
+ }
3406
+ doc .CurrentRev = parent
3407
+ return nil
3408
+ }
3409
+
3331
3410
const (
3332
3411
xattrMacroCas = "cas" // SyncData.Cas
3333
3412
xattrMacroValueCrc32c = "value_crc32c" // SyncData.Crc32c
0 commit comments