I am using couchbase lite 1.2.1 on iOS. Using pull replication I detect conflicts and want to resolve them such that the server revision is the one that wins. Is there a way to do this?
Delete the local revision (update it and set the isDeletion property on the new revision.)
How do I know which the local revision is?
When you observe database-changed notifications, the DatabaseChange object for a revision pulled from a server will have its source
property set to a non-null value.
We don’t have a persistent flag on a revision that says whether it was locally-created. That might be a good idea for the future, though.
I hadn’t noticed CBLDatabaseChangeNotification before. So instead of checking for conflicts when the pull stops, I can monitor that notification and resolve conflicts there. Seems like that could work. Thanks for the fast response.
I hit an issue working with this notification. If I handle the notification on the mainQueue I get periodic lockups on startup, if I handle it on the notification thread I get errors about working with the database on the main thread.
__weak DatabaseManager *weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:kCBLDatabaseChangeNotification
object:nil
queue:nil //or [NSOperationQueue mainQueue]
usingBlock:^(NSNotification * _Nonnull note) {
NSArray<CBLDatabaseChange *> *changes = note.userInfo[@"changes"];
[weakSelf databaseDidChange:changes];
}];
The warning when queue is nil:
14:27:20.050‖ WARNING: Exception caught in -[CBLDatabase doAsync:]:
***** THREAD-SAFETY VIOLATION: This database is being used on a thread it wasn't created on! Please see the concurrency guidelines in the Couchbase Lite documentation. *****
When using the mainQueue. Here are the two relevant threads that get deadlocked…
main thread:
frame #4: 0x000000018224cc50 CoreFoundationCFRunLoopRunSpecific + 384 frame #5: 0x0000000182c5ccfc Foundation
-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 308
frame #6: 0x00000001009c1e94 ConceptsMYWaitFor + 264 frame #7: 0x000000010099d34c Concepts
-[CBLDatabase waitFor:] + 64
frame #8: 0x00000001009a1464 Concepts`-[CBLLiveQuery waitForRows] + 144
other thread:
frame #0: 0x0000000181f07f24 libsystem_kernel.dylib__psynch_cvwait + 8 frame #1: 0x0000000181fd2ce8 libsystem_pthread.dylib
_pthread_cond_wait + 648
frame #2: 0x0000000182d268ec Foundation-[__NSOperationInternal _waitUntilFinished:] + 132 frame #3: 0x0000000182c5947c Foundation
-[__NSObserver _doit:] + 232
frame #4: 0x0000000182310dfc CoreFoundation__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20 frame #5: 0x000000018231061c CoreFoundation
_CFXRegistrationPost + 396
frame #6: 0x000000018231039c CoreFoundation___CFXNotificationPost_block_invoke + 60 frame #7: 0x0000000182379414 CoreFoundation
-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1532
frame #8: 0x000000018224e6c8 CoreFoundation_CFXNotificationPost + 368 frame #9: 0x00000001009d1a94 Concepts
__42-[CBLDatabase(Internal) postNotification:]_block_invoke + 64
frame #10: 0x000000010099cfac Concepts`catchInBlock + 28
The end solution was to dispatch_async in the notification handler. e.g.
_weak DatabaseManager *weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:kCBLDatabaseChangeNotification
object:nil
queue:nil
usingBlock:^(NSNotification * _Nonnull note) {
dispatch_async(dispatch_get_main_queue(), ^ {
NSArray<CBLDatabaseChange *> *changes = note.userInfo[@"changes"];
[weakSelf databaseDidChange:changes];
});
}];
Can you see any potential problems with doing this?
One thing that would be useful would be to report the database in the notification. I have to get this via a document lookup at the moment. (we have two CB databases in our app).
Also, as you say it would be really useful to track the source on the revision. Should I open an issue on github for that?
Don’t use object: nil
when registering — you’ll get notifications for every CBLDatabase, including ones on background threads (like the internal instance used by the replicator.) Only register for the specific CBLDatabase(s) you want to monitor.