Search code examples
realm

Does Realm support SELECT FOR UPDATE style read locking


I've spent a fair amount of time looking into the Realm database mechanics and I can't figure out if Realm is using row level read locks under the hood for data selected during write transactions.

As a basic example, imagine the following "queue" logic

assume the queue has an arbitrary number of jobs (we'll say 5 jobs)

 async getNextJob() {

    let nextJob = null;

    this.realm.write(() => {

      let jobs = this.realm.objects('Job')
        .filtered('active == FALSE')
        .sorted([['priority', true], ['created', false]]);

      if (jobs.length) {
        nextJob = jobs[0];
        nextJob.active = true;
      }

    });

    return nextJob;

  }

If I call getNextJob() 2 times concurrently, if row level read blocking isn't occurring, there's a chance that nextJob will return the same job object when we query for jobs.

Furthermore, if I have outside logic that relies on up-to-date data in read logic (ie job.active == false when it actually is true at current time) I need the read to block until update transactions complete. MVCC reads getting stale data do not work in this situation.

If read locks are being set in write transactions, I could make sure I'm always reading the latest data like so

let active = null;
this.realm.write(() => {

  const job = this.realm.pseudoQueryToGetJobByPrimaryKey();
  active = job.active;

});

// Assuming the above write transaction blocked the read until 
// any concurrent updates touching the same job committed
// the value for active can be trusted at this point in time.
if (active === false) {
  // code to start job here
}

So basically, TL;DR does Realm support SELECT FOR UPDATE?

Postgresql

https://www.postgresql.org/docs/9.1/static/explicit-locking.html

MySql

https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html


Solution

  • So basically, TL;DR does Realm support SELECT FOR UPDATE?

    Well if I understand the question correctly, the answer is slightly trickier than that.

    If there is no Realm Object Server involved, then realm.write(() => disallows any other writes at the same time, and updates the Realm to its latest version when the transaction is opened.

    If there is Realm Object Server involved, then I think this still stands locally, but the Realm Sync manages the updates from remote, in which case the conflict resolution rules apply for remote data changes.