Replicator does not always receive all document events when two database instances point to same physical database

Here is my situation. I have a workbook that is backed by a Couchbase database, which syncs the workbook’s contents (e.g. ink strokes) with the remote. I’ve implemented split screen functionality now, so the user can open two workbooks at once, side-by-side. When workbooks are different, this works just fine. When workbooks are the same, however, I’m running into this issue, and I want to determine whether there is something wrong with how I’m using Couchbase or if this is an issue that I should report.

When it’s the same workbook open on both sides, each has its own instance of the Database class pointing to the same physical database on the device. Each Database instance has a single push-and-pull replicator. However, when a remote change comes in from another device, occasionally not all DocumentReplication events are delivered to both replicator listeners (one for each Database instance).

For instance, let’s say 5 events are pulled in remotely. One Database instance and its replicator will get all 5 events delivered to its DocumentReplication listener, but the other one might get only 2 or 3. This does only happen occasionally, but it’s often enough that it is an issue.

I did look into whether Couchbase supports more than 1 Database instance pointing to the same physical database, and according to a couple of forum posts and a blog posts, it does. I’m not sure if there is something else I might be doing wrong, or if anyone else is familiar with this problem and might have some tips on how to fix it? Or is this an issue with Couchbase?

I’m using CouchbaseLite for Android, and I am using 2.7.0, but yesterday I upgraded to 2.8.0 to see if the problem resolved itself, but it did not.

Thanks for any help.

Using multiple database instances for the same physical database are supported and should work. Using a replicator on each database instance should also work but as each replicator works on its own thread, it is much possible that each replicator will not receive the same DocumentReplication event. For example, replicator A has pulled doc A’s change so replicator B doesn’t need to pull doc A’s change so there is no DocumentReplication notified for the replicator B. The question is that if after both replicator is done syncing (e.g. go to idle or stopped), the result of the sync is correct or not. Can you verify the sync result?

Also as the two databases instances are pointing to the same physical database, you can only run a single replicator against one of the two databases. When the replicator is done, each of the database will have the same view.

If you want to know if there are any changes to the database instance, a better option is to listen to DatabaseChange event or DocumentChange event on the database instance itself instead of listening to DocumentReplication event.

Yes, I can verify that the result of the sync is correct.

As multiple database instances are supported, each with its own replicator, pointing to the same physical database, I was expecting to get DocumentReplication events to both of the replicator’s listeners, but it appears as though that’s not guaranteed. Even though, in my experience, both replicator listeners in the app get all DocumentReplication events about 70 - 80% of the time.

The reason I’m not using the DocumentChange event is that I need to know whether the change was local or remote (I check the isPush() flag on DocumentReplication for this).

In any case, I have found a good solution for this that seems to be working well. Thanks for the info!

If I understand right, you’ve created two identical replications between the same local database file and the same server-side database URL. (The fact that it’s two distinct Database instances doesn’t matter.)

This isn’t supported; please don’t do it. (In version 1.x we explicitly checked for and prevented it, but for whatever reason 2.x doesn’t have the same checks. We should add them back in.) The main problem is that both replicators will be using the same local and remote storage for checkpoints, and thus conflicting with each other when they try to save them. This will also trigger a lot of tricky conditions where one replicator is in the middle of pushing or pulling a replication but finds out that the revision has already been created (by the other replicator,) and it’s possible you’re encountering a bug in one of them — they’re legal but normally rare, and difficult to test since the code is so heavily concurrent.

I recommend you modify your code to keep this from happening. For example you could have a global Map keyed by filesystem path that keeps track of which database files are being replicated, and avoid creating a replication when one already exists.

That’s correct. Whenever a workbook is opened, it creates the database instance that opens the physical database on disk and then sets up the push-and-pull replicator pointing to the remote URL. If the same database is opened again, the same steps are followed, resulting in what you described.

It looks like I will have to address this at some point then, although it doesn’t seem to be causing any other issues. As I mentioned in my first reply, I implemented a working solution to my original problem.

Thanks for the clarification!