Sync and Collisions/Conflicts

Hi, I’m evaluating remoteStorage. Is there any documentation on how to resolve conflicts? Is there a conflict resolution mechanism built into remoteStorage?

I’m looking for an alternative like CouchDB/PouchDB.

Thanks!

Mike

Hi Mike,

remoteStorage as a protocol doesn’t have a concept of conflicts, as the data manipulation interface is just a very simple REST API. remoteStorage.js (the reference client implementation) however does implement this via the change events that a BaseClient emits. The event object will have its origin property set to conflict in case the local change conflicts with a newer change on the remote.

See http://remotestorage.io/doc/code/files/baseclient-js.html#RemoteStorage.BaseClient.change for documentation, although I just realized that this part of the docs is quite confusing (so I also created https://github.com/remotestorage/remotestorage.js/issues/785).

Hope this helps.

Hey, thanks for the reply. Yes, I didn’t notice that before.

What do you think of this? https://github.com/forbesmyester/SyncIt It’s a subversion-like conflict resolution system.

Might make a good mash-up.

Thanks!

Mike

Cool, didn’t know that one. Thanks!

I personally think it would make a lot of sense to use a common sync library at some point. For that, the library needs some concept of backend adapters, though, because server implementations will vary for different projects and architectures.

This one seems to handle conflicts the same way we do. The README contains:

What does it do?

  • Supplying the App with all data required to handle version conflicts when they occur.

Our conflict event does basically that. You will have the old and new values/objects, and based on your app’s needs, you can decide how to handle the resolution. For some apps you might want to ask the user, some may want to merge automatically, and how data is merged exactly should depend on the use case anyway.

Maybe we could have an option that allows you to say “meh, I don’t care” with a decent default that covers some common use cases. Not sure what that could look like.

If there are multiple clients, how does the conflict resolution work?

Server => S1

ClientA => S1 -> S2a

ClientB => S1 -> S2b

ClientC => S1 -> S2c

Sync’d back to client, how are S2a, S2b, and S2c resolved? And how is the resolution passed back the other clients? as S3?

I’m not sure I’m asking the right questions, but I’m trying to make a workflow app where people collaborate on a bunch of small documents off-line. So I need to get this right. Thanks!

Welcome to the forum! Cool! Thanks for the interest, sorry I missed your question on IRC yesterday - I check IRC once every two or three hours when I’m online, and therefore I wasn’t quick enough to answer you, sorry.

Thanks also for the link to SyncIt, I also hadn’t heard of it but it looks cool, I opened an issue on gh:unhosted/website for adding it to https://unhosted.org/tools/.

Re how our library handles sync, the documentation is unfortunately in a place that’s not being linked to yet: https://github.com/remotestorage/remotestorage.js/blob/master/doc/data-format.md#keeprevert-conflict-resolution I commented on the githb issue as well.

the way we handle conflicts is a bit different from what you might expect. it is not fully distributed versioning like in couchdb. It is a hub-and-spokes architecture, where the server is in the center and always wins.

On the level of client-server communication, clients try to push their changes as conditional PUT requests (with an If-Match header), and if this precondition fails then the client knows that there was a conflict between what they tried to push and what is currently on the server. the client can then choose to either try again with the new ETag, or accept defeat. this part is the same as for couchdb.

On the level of a remoteStorage module calling the storeObject or storeFile function of the remoteStorage baseClient, such a request always succeeds. This is what is important to realize, and is what is different from what you might expect.

the reason for this is asynchronous synchronization: changes are not pushed out immediately. they are applied locally first (this always succeeds, of course, unless the disk is full or something), and then a separate sync process checks every 10 seconds whether there are any unpushed outgoing changes, or any unpulled incoming changes (it checks that with a GET with an If-None-Match header to the root path, to see if the ETag of the root folder changed). If during this sync process an outgoing change (which was already accepted locally) is rejected by the server (because of the If-Match header), then a change event is triggered, which looks just like an incoming change, except that it is marked with origin: conflict.

I’ll reply to your specific example on the github issue.

I gave SyncIt an initial review, nothing too in depth, posted my comments in the github issue here: https://github.com/remotestorage/remotestorage.js/issues/787#issuecomment-58749871