This is explained a bit in a blog post[1]. Basically, this is because FaunaDB uses Calvin to do distributed transactions, which makes it hard to support OLAP-style SQL sessions. (If I understand the Calvin paper[2] correctly, this has to do with a combination of how it doesn't support "dependent" transactions, and how it does concurrency control.)
Yes, it has to do with the way Calvin handles transactions, which are required to declare their read and write sets before executing.
These kind of transactions are also called static, and are normally of the type "I have this read/write operation(s) against multiple keys, go and do it" vs dynamic transactions that might depend on read values from the db to figure out what to do next.
We allow you to make different writes depending on reads. The query language has loop and control flow structures, so you can push a lot of the logic to the database. You can read more about the query language here: https://fauna.com/documentation/queries
It should be executed in a single transaction.
But the query may be scheduled more than once.
According to the Calvin paper, there are two strategies here:
* Either, the write set of the query is considered to be {B,C}.
* Or the query if rewritten and scheduled several times,
the `if` operation beeing replaced by an assert operation,
until the assertion is indeed true, in which case the transaction proceeds using a smaller write set.
If not, the query is scheduled again after having been rewritten to match the current values.
In other words, if A equals 0 then the query is rewritten as `assert A == 0 then Write(B,1)`.
Otherwise the query is rewritten as `assert A != 0 then Write(C,2)`.
Months ago, I implemented a prototype after the Calvin paper and used the first strategy.
It may imply more contentions and even lock the whole dataset with queries like `Write(Read(A),a))`.
Sadly, such queries are not rare: updating a distributed index is the typical case.
Ah, yeah, I suspected it could be fixed with your first approach, but the second one also sounds plausible.
But if you go with the first option, then you can end up locking the entire database, as you pointed out with `write(read(A), _)`. Wouldn't your second option cause multiple transaction aborts until you find the rewrite that satisfies the assert? And in that case, the scheduler would need to know if the abort was actually caused by a faulty rewrite.
It would be interesting to know what Fauna does in these cases.
1: https://fauna.com/blog/distributed-acid-transaction-performa...
2: http://cs.yale.edu/homes/thomson/publications/calvin-sigmod1...