Skip to content

Manage concurrent edits of notes #56

Description

@korelstar

Currently, we have no proper handling of concurrent edits. Those can happen in many scenarios and it results in lost updates:

Scenario 1: Shared notes

  • User A shares a note to User B
  • both users open their notes app and begin to edit
  • when User B finishes after User A, all changes made by User A will be overwritten by User B without notice by User B (or User A)

Scenario 2: Mobile clients

  • the user makes changes using a client app on the mobile phone without network connection
  • later, the user edits the same note somewhere else, e.g. on a desktop computer using the web app
  • when the mobile device reconnects and synchronizes, one note overwrites the other without notice by the user

I would like to improve this situation and I thought about a strategy how to cope with this. We are experiencing a classical lost update problem, due to a write-write-conflict. Traditional databases use locking to prevent this. However, in our situation, we have a distributed system, where locking is not appropriate. Instead, I would propose to use optimistic concurrency control. This means, we allow always editing and try to resolve conflicts later on.

To do this, two steps are needed: 1.) Identify conflicts, and 2.) Resolve conflicts.

1. Identify conflicts
In order to check, if a note has been changed in the meanwhile (from getting the current state from the server to putting the changed data back to the server) we could use the ETags I proposed in #49 (in summary: it represents the state of the note by using a checksum over all attributes).
The client (mobile client or web app) has to save the current ETag for each note and update it on every synchronization (this is required for #49, too). When the note is edited, the client sends the HTTP header If-Match: "etag". The server (i.e. NotesController resp. NotesAPIController) checks if the ETag from the HTTP request header matches the current ETag from filesystem/database. If true, the note is changed and sent back to the client. If not, the server sends the HTTP response code 412 Precondition Failed and the current server state of the note in the body of the response. The client now sees that the note has changed in the meanwhile and resolves the write-write-conflict (see 2.)).
These changes are totally backwards-compatible and conform to the HTTP protocol.

2. Resolve conflicts:
The client now has data from local changes and remote changes and has to do something. This is harder than the first step and multiple reactions are possible.

a) Let the user decide: ask the user whether i) overwrite local changes, ii) overwrite remote changes, or iii) save local (or remote) changes as new note.
b) Let the user merge: provide an interface which allows for merging the files (you know it from your version control).
c) Try to merge automatically: merge all changes automatically, e.g. using the google-diff-match-patch (Demo, Code) library.

I think, user interaction has to be avoided, so I'm preferring c), but I don't know if this will always work.

However, I wanted to write down my thoughts on this so that everybody can participate on a discussion on this. The first step is easy to implement and must be done in this app (controller). The second step is much more comprehensive and requires changes on those clients (i.e. this app, Android app, iOS app) which should be concurrency-save.

Any comments are welcome :-)
How high do you would estimate the importance of this issue?
Does nextcloud/server (resp. its clients like nextcloud/android and desktop clients) deal with this issue?


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestRequests for complete new featuresfeature: APIRelated to the API for 3rd-party apps, i.e. Android or iOS

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions