(no title)
j-berman | 5 years ago
This is what clients do initially, until the database grows in size. Every time the transaction log increases 50 KB, the client takes a snapshot of the database's state at a particular point in time, compresses and encrypts it, and uploads this state to the server. We call this a "bundle". This way when clients reopen a database, they load from the bundle first, and then apply any new transactions that come after it. Rather than needing to query for the history of all transactions and decrypting them individually and reapplying.
>Hot do concurrent modification get resolved (several clients try to modify the shared stage at the same time)?
The server assigns each transaction a distinct sequence number via an atomic operation. So clients always apply transactions with the same distinct sequence number, in sequential order. The client relies on this to enforce uniqueness and versioning. Only the lowest sequence number itemId gets applied to a database if 2 clients insert with the same itemId at the same time, and similarly, only the lowest sequence number version of an item gets updated or deleted if 2 clients update or delete the same item at the same time.
With regards to bundling, it's a bit more complicated and there are layers to our approach in safely handling it under high concurrency. When a client uploads a bundle, the database records what sequence number the bundling took place at so clients can use it to retrieve the latest bundle. And the server retains copies of bundles at prior sequence numbers. This way if two clients attempt to open a database right around the moment a bundling process completes (client 1 receives a bundle at lower sequence number, and client 2 receives a bundle at a higher sequence number), both clients receive the same set of transactions regardless. The server sends all transactions in the log after the bundle sequence number, so client 1 just needs to decrypt and apply more individual transactions to rebuild the state compared to client 2.
Some may find this interesting too -- we specifically test for safe concurrent behavior across 2 clients using a makeshift testing framework that opens 2 browsers at the same time and does some neat tests: https://github.com/smallbets/userbase/tree/master/test
If you clone the repo and run `npm run test:concurrency`, it will run those tests and output test results to the consoles of the 2 browsers.
No comments yet.