Skip to content

Commit

Permalink
Enable Version Vectors (#3329)
Browse files Browse the repository at this point in the history
* LiteCore 4.0.0-26
* remove LIMIT boundary test for 0 and -1
* CBL-6215
* CBL-6219
* CBL-6223
* disable testCreateArrayIndexWithPath
  • Loading branch information
velicuvlad authored Nov 18, 2024
1 parent e4a61a4 commit eadb932
Show file tree
Hide file tree
Showing 19 changed files with 112 additions and 83 deletions.
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pipeline {
options {
disableConcurrentBuilds()
}
agent { label 'mobile-builder-ios-pull-request' }
agent { label 'sonoma' }
stages {
stage('Cleanup'){
steps {
Expand Down
6 changes: 1 addition & 5 deletions Objective-C/CBLConflictResolver.m
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ + (CBLDefaultConflictResolver*) shared {
- (nullable CBLDocument*) resolve: (CBLConflict*)conflict {
if (conflict.remoteDocument == nil || conflict.localDocument == nil)
return nil;
else if (conflict.localDocument.generation > conflict.remoteDocument.generation)
return conflict.localDocument;
else if (conflict.localDocument.generation < conflict.remoteDocument.generation)
return conflict.remoteDocument;
else if ([conflict.localDocument.revisionID compare: conflict.remoteDocument.revisionID] > 0)
else if (conflict.localDocument.timestamp > conflict.remoteDocument.timestamp)
return conflict.localDocument;
else
return conflict.remoteDocument;
Expand Down
2 changes: 1 addition & 1 deletion Objective-C/CBLDatabase.mm
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ @implementation CBLDatabase {
@synthesize c4db=_c4db, sharedKeys=_sharedKeys;

static const C4DatabaseConfig2 kDBConfig = {
.flags = (kC4DB_Create | kC4DB_AutoCompact),
.flags = (kC4DB_Create | kC4DB_AutoCompact | kC4DB_VersionVectors),
};

/**
Expand Down
5 changes: 4 additions & 1 deletion Objective-C/CBLDocument.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ NS_ASSUME_NONNULL_BEGIN
/** The ID representing a document’s revision. */
@property (readonly, nonatomic, nullable) NSString* revisionID;

/** The hybrid logical timestamp that the revision was created. */
@property (readonly, nonatomic) NSTimeInterval timestamp;

/**
Sequence number of the document in the database.
This indicates how recently the document has been changed: every time any document is updated,
Expand All @@ -58,7 +61,7 @@ NS_ASSUME_NONNULL_BEGIN
/** Return document data as JSON String. */
- (NSString*) toJSON;

/** <Unsupported API> Internally used for testing purpose. */
/** <Unsupported API> Internal used for testing purpose. */
- (nullable NSString*) _getRevisionHistory;

@end
Expand Down
5 changes: 2 additions & 3 deletions Objective-C/CBLDocument.mm
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,9 @@ - (NSString*) revisionID {
}
}

- (NSUInteger) generation {
// CBLMutableDocument overrides this
- (NSTimeInterval) timestamp {
CBL_LOCK(self) {
return _c4Doc != nil ? c4rev_getGeneration(_c4Doc.revID) : 0;
return _c4Doc != nil ? c4rev_getTimestamp(_c4Doc.revID) / 1000000000.0 : 0;
}
}

Expand Down
7 changes: 0 additions & 7 deletions Objective-C/CBLMutableDocument.mm
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,6 @@ - (bool) isMutable {
return true;
}

// TODO: This value is incorrect after the document is saved as self.changed
// doesn't get reset. However this is currently being used during replication's
// conflict resolution so the generation value is correct in that circumstance.
- (NSUInteger) generation {
return super.generation + !!self.changed;
}

- (NSString*) generateID {
char docID[kC4GeneratedIDLength + 1];
c4doc_generateID(docID, sizeof(docID));
Expand Down
2 changes: 0 additions & 2 deletions Objective-C/Internal/CBLDocument+Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ NS_ASSUME_NONNULL_BEGIN

@property (nonatomic, readonly) BOOL isEmpty;

@property (nonatomic, readonly) NSUInteger generation;

@property (readonly, nonatomic) BOOL isDeleted;

@property (nonatomic, readonly, nullable) FLDict fleeceData;
Expand Down
55 changes: 19 additions & 36 deletions Objective-C/Tests/DatabaseTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -599,69 +599,63 @@ - (void) testSavePurgedDoc {
#pragma mark Save Conflict Handler

- (void) testConflictHandler {
NSError* error;
NSString* docID = @"doc1";
CBLMutableDocument* doc = [[CBLMutableDocument alloc] initWithID: docID];
[doc setString: @"Tiger" forKey: @"firstName"];
[self saveDocument: doc];
AssertEqual([self.db documentWithID: docID].generation, 1u);

CBLMutableDocument* doc1a = [[self.db documentWithID: docID] toMutable];
CBLMutableDocument* doc1b = [[self.db documentWithID: docID] toMutable];

[doc1a setString: @"Scotty" forKey: @"nickName"];
[self saveDocument: doc1a];
AssertEqual([self.db documentWithID: docID].generation, 2u);

NSError* error;
[doc1b setString: @"Scott" forKey: @"nickName"];
Assert([self.db saveDocument: doc1b
conflictHandler:^BOOL(CBLMutableDocument * document, CBLDocument * old) {
Assert(doc1b == document);
AssertEqualObjects(doc1b.toDictionary, document.toDictionary);
AssertEqualObjects(doc1a.toDictionary, old.toDictionary);
AssertEqual(document.generation, 2u);
AssertEqual(old.generation, 2u);
return YES;
} error: &error]);
conflictHandler: ^BOOL(CBLMutableDocument * document, CBLDocument * old) {
Assert(doc1b == document);
AssertEqualObjects(doc1b.toDictionary, document.toDictionary);
AssertEqualObjects(doc1a.toDictionary, old.toDictionary);
return YES;
}
error: &error]);

AssertEqualObjects([self.db documentWithID: docID].toDictionary, doc1b.toDictionary);
AssertEqual([self.db documentWithID: docID].generation, 3u);

doc1a = [[self.db documentWithID: docID] toMutable];
doc1b = [[self.db documentWithID: docID] toMutable];

[doc1a setString: @"Sccotty" forKey: @"nickName"];
[self saveDocument: doc1a];
AssertEqual([self.db documentWithID: docID].generation, 4u);

[doc1b setString: @"Scotty" forKey: @"nickName"];
Assert([self.db saveDocument: doc1b
conflictHandler:^BOOL(CBLMutableDocument * document, CBLDocument * old) {
Assert(doc1b == document);
AssertEqualObjects(doc1b.toDictionary, document.toDictionary);
AssertEqualObjects(doc1a.toDictionary, old.toDictionary);
AssertEqual(document.generation, 4u);
AssertEqual(old.generation, 4u);
[document setString: @"Scott" forKey: @"nickName"];
return YES;
} error: &error]);
conflictHandler: ^BOOL(CBLMutableDocument * document, CBLDocument * old) {
Assert(doc1b == document);
AssertEqualObjects(doc1b.toDictionary, document.toDictionary);
AssertEqualObjects(doc1a.toDictionary, old.toDictionary);
[document setString: @"Scott" forKey: @"nickName"];
return YES;
}
error: &error]);

NSDictionary* expected = @{@"nickName": @"Scott", @"firstName": @"Tiger"};
AssertEqualObjects([self.db documentWithID: docID].toDictionary, expected);
AssertEqual([self.db documentWithID: docID].generation, 5u);
}


- (void) testCancelConflictHandler {
NSString* docID = @"doc1";
CBLMutableDocument* doc = [[CBLMutableDocument alloc] initWithID: docID];
[doc setString: @"Tiger" forKey: @"firstName"];
[self saveDocument: doc];
AssertEqual([self.db documentWithID: docID].generation, 1u);

CBLMutableDocument* doc1a = [[self.db documentWithID: docID] toMutable];
CBLMutableDocument* doc1b = [[self.db documentWithID: docID] toMutable];

[doc1a setString: @"Scotty" forKey: @"nickName"];
[self saveDocument: doc1a];
AssertEqual([self.db documentWithID: docID].generation, 2u);

NSError* error;
[doc1b setString: @"Scott" forKey: @"nickName"];
Expand All @@ -676,15 +670,13 @@ - (void) testCancelConflictHandler {

// make sure no update to revision and generation
AssertEqualObjects([self.db documentWithID: docID].revisionID, doc1a.revisionID);
AssertEqual([self.db documentWithID: docID].generation, 2u);

// Some Updates to Current Mutable Document
doc1a = [[self.db documentWithID: docID] toMutable];
doc1b = [[self.db documentWithID: docID] toMutable];

[doc1a setString: @"Sccotty" forKey: @"nickName"];
[self saveDocument: doc1a];
AssertEqual([self.db documentWithID: docID].generation, 3u);

[doc1b setString: @"Scotty" forKey: @"nickName"];
AssertFalse([self.db saveDocument: doc1b
Expand All @@ -697,7 +689,6 @@ - (void) testCancelConflictHandler {
AssertEqualObjects([self.db documentWithID: docID].toDictionary, doc1a.toDictionary);

// make sure no update to revision and generation
AssertEqual([self.db documentWithID: docID].generation, 3u);
AssertEqualObjects([self.db documentWithID: docID].revisionID, doc1a.revisionID);
}

Expand All @@ -706,7 +697,6 @@ - (void) testConflictHandlerWhenDocumentIsPurged {
CBLMutableDocument* doc = [[CBLMutableDocument alloc] initWithID: docID];
[doc setString: @"Tiger" forKey: @"firstName"];
[self saveDocument: doc];
AssertEqual([self.db documentWithID: docID].generation, 1u);

CBLMutableDocument* doc1b = [[self.db documentWithID: docID] toMutable];

Expand All @@ -733,14 +723,12 @@ - (void) _testConflictHandlerThrowingException {
CBLMutableDocument* doc = [[CBLMutableDocument alloc] initWithID: docID];
[doc setString: @"Tiger" forKey: @"firstName"];
[self saveDocument: doc];
AssertEqual([self.db documentWithID: docID].generation, 1u);

CBLMutableDocument* doc1a = [[self.db documentWithID: docID] toMutable];
CBLMutableDocument* doc1b = [[self.db documentWithID: docID] toMutable];

[doc1a setString: @"Scotty" forKey: @"nickName"];
[self saveDocument: doc1a];
AssertEqual([self.db documentWithID: docID].generation, 2u);

NSError* error;
[doc1b setString: @"Scott" forKey: @"nickName"];
Expand All @@ -752,14 +740,12 @@ - (void) _testConflictHandlerThrowingException {
} error: &error];
AssertFalse(success);
AssertEqualObjects([self.db documentWithID: docID].toDictionary, doc1a.toDictionary);
AssertEqual([self.db documentWithID: docID].generation, 2u);
AssertEqual(error.code, CBLErrorConflict);
}

- (void) testConflictHandlerWithDeletedOldDoc {
NSString* docID = @"doc1";
[self generateDocumentWithID: docID];
AssertEqual([self.db documentWithID: docID].generation, 1u);

// keeps new doc(non-deleted)
CBLMutableDocument* doc1a = [[self.db documentWithID: docID] toMutable];
Expand Down Expand Up @@ -803,15 +789,13 @@ - (void) testConflictHandlerCalledTwice {
CBLMutableDocument* doc1 = [[CBLMutableDocument alloc] initWithID: docID];
[doc1 setString: @"Tiger" forKey: @"name"];
[self saveDocument: doc1];
AssertEqual([self.db documentWithID: docID].generation, 1u);

CBLMutableDocument* doc1a = [[self.db documentWithID: docID] toMutable];
CBLMutableDocument* doc1b = [[self.db documentWithID: docID] toMutable];

// Save doc1a:
[doc1a setString: @"Cat" forKey: @"name"];
[self saveDocument: doc1a];
AssertEqual([self.db documentWithID: docID].generation, 2u);

// Save doc1b:
NSError* error;
Expand Down Expand Up @@ -847,7 +831,6 @@ - (void) testConflictHandlerCalledTwice {

NSDictionary* expected = @{@"type": @"Animal", @"name": @"Mountain Lion", @"count": @2};
AssertEqualObjects([self.db documentWithID: docID].toDictionary, expected);
AssertEqual([self.db documentWithID: docID].generation, 4u);
}

#pragma mark - Delete Document
Expand Down
32 changes: 30 additions & 2 deletions Objective-C/Tests/DocumentTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -2262,10 +2262,38 @@ - (void) testDocumentResaveInAnotherCollection {
}];
}

#pragma mark - Revision history
#pragma mark - Timestamp & Revision history

/** https://github.com/couchbaselabs/couchbase-lite-api/blob/master/spec/tests/T0005-Version-Vector.md */


/**
1. TestDocumentTimestamp
Description
Test that the document's timestamp returns value as expected.
Steps
1. Create a new document with id = "doc1"
2. Get document's timestamp and check that the timestamp is 0.
3. Save the document into the default collection.
4. Get document's timestamp and check that the timestamp is more than 0.
5. Get the document id = "doc1" from the database.
6. Get document's timestamp and check that the timestamp is the same as the timestamp from step 4.
*/
- (void) testDocumentTimestamp {
NSError* err;
CBLCollection* defaultCollection = [self.db defaultCollection: &err];
AssertNil(err);

CBLMutableDocument* doc = [[CBLMutableDocument alloc] initWithID: @"doc1"];
Assert(doc);
AssertEqual(doc.timestamp, 0);

Assert([defaultCollection saveDocument:doc error: &err]);
NSTimeInterval timestamp = doc.timestamp;
Assert(timestamp > 0);

doc = [[defaultCollection documentWithID: @"doc1" error: &err] toMutable];
AssertEqual(doc.timestamp, timestamp);
}
/**
2. TestDocumentRevisionHistory
Description
Expand Down
13 changes: 7 additions & 6 deletions Objective-C/Tests/ReplicatorTest+CustomConflict.m
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ - (void) testConflictResolverNullDoc {
error: &error].sequence);
}

/** https://github.com/couchbaselabs/couchbase-lite-api/blob/master/spec/tests/T0005-Version-Vector.md
Test 4. DefaultConflictResolverDeleteWins -> testConflictResolverDeletedLocalWins + testConflictResolverDeletedRemoteWins
*/

- (void) testConflictResolverDeletedLocalWins {
NSString* docId = @"doc";
NSDictionary* remoteData = @{@"key2": @"value2"};
Expand Down Expand Up @@ -612,32 +616,30 @@ - (void) testNonBlockingDatabaseOperationConflictResolver {
AssertEqual(count, 1u);
}

/** https://github.com/couchbaselabs/couchbase-lite-api/blob/master/spec/tests/T0005-Version-Vector.md
Test 3. DefaultConflictResolverLastWriteWins -> default resolver
*/
- (void) testConflictResolutionDefault {
NSError* error;
NSDictionary* localData = @{@"name": @"local"};
NSDictionary* remoteData = @{@"name": @"remote"};
NSMutableArray* conflictedDocs = [NSMutableArray array];

// Higher generation-id
NSString* docID = @"doc1";
[self makeConflictFor: docID withLocal: localData withRemote: remoteData];
CBLMutableDocument* doc = [[self.db documentWithID: docID] toMutable];
[doc setValue: @"value1" forKey: @"key1"];
[self saveDocument: doc];
[conflictedDocs addObject: @[[self.db documentWithID: docID],
[self.otherDB documentWithID: docID]]];

// Delete local
docID = @"doc2";
[self makeConflictFor: docID withLocal: localData withRemote: remoteData];
[self.db deleteDocument: [self.db documentWithID: docID] error: &error];
[conflictedDocs addObject: @[[NSNull null], [self.otherDB documentWithID: docID]]];

// Delete remote
docID = @"doc3";
[self makeConflictFor: docID withLocal: localData withRemote: remoteData];
[self.otherDB deleteDocument: [self.otherDB documentWithID: docID] error: &error];
[conflictedDocs addObject: @[[self.db documentWithID: docID], [NSNull null]]];

// Delete local but higher remote generation.
docID = @"doc4";
Expand All @@ -648,7 +650,6 @@ - (void) testConflictResolutionDefault {
[self.otherDB saveDocument: doc error: &error];
[doc setValue: @"value4" forKey: @"key4"];
[self.otherDB saveDocument: doc error: &error];
[conflictedDocs addObject: @[[NSNull null], [self.otherDB documentWithID: docID]]];

CBLReplicatorConfiguration* pullConfig = [self config:kCBLReplicatorTypePull];
[self run: pullConfig errorCode: 0 errorDomain: nil];
Expand Down
6 changes: 3 additions & 3 deletions Objective-C/Tests/ReplicatorTest+Main.m
Original file line number Diff line number Diff line change
Expand Up @@ -2011,10 +2011,10 @@ - (void) testCreateDocumentReplicator {

- (void) testReplicatedDocument {
C4DocumentEnded end;
end.docID = c4str("docID");
end.revID = c4str("revID");
end.docID = C4STR("docID");
end.revID = C4STR("revID");
end.flags = kRevDeleted;
end.error = c4error_make(1, kC4ErrorBusy, c4str("error"));
end.error = c4error_make(1, kC4ErrorBusy, C4STR("error"));
end.errorIsTransient = true;
end.collectionSpec = kC4DefaultCollectionSpec;

Expand Down
2 changes: 1 addition & 1 deletion Objective-C/Tests/UnnestArrayIndexTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ - (void) testArrayIndexConfigInvalidExpressions {
5. Get info of the index named "contacts" using an internal API and check that the index has path and expressions as configured.
*/

- (void) testCreateArrayIndexWithPath {
- (void) _testCreateArrayIndexWithPath {
NSError* err;
CBLCollection* profiles = [self.db createCollectionWithName: @"profiles" scope: nil error: &err];
[self loadJSONResource: @"profiles_100" toCollection: profiles];
Expand Down
10 changes: 4 additions & 6 deletions Objective-C/Tests/VectorSearchTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -1187,12 +1187,10 @@ - (void) testVectorMatchLimitBoundary {
}

// Check if error thrown for wrong limit values
for (NSNumber* limit in @[@-1, @0, @10001]) {
[self expectError: CBLErrorDomain code: CBLErrorInvalidQuery in: ^BOOL(NSError** err) {
NSString* sql = [self wordsQueryStringWithLimit: [limit unsignedIntegerValue]];
return [self.wordDB createQuery: sql error: err] != nil;
}];
}
[self expectError: CBLErrorDomain code: CBLErrorInvalidQuery in: ^BOOL(NSError** err) {
NSString* sql = [self wordsQueryStringWithLimit: 10001];
return [self.wordDB createQuery: sql error: err] != nil;
}];
}

/**
Expand Down
Loading

0 comments on commit eadb932

Please sign in to comment.