New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider replacing vector clocks with naive timestamp-based conflict resolution #2784
Comments
Another benefit is that we wouldn't have to think about conflict states in all the code that reads from the vector clocks. |
We could introduce a pseudotype for vector clock conflicts. (I thought that's what the plan was.) You can read this pseudotype to get the values in conflict, but if you try to use it in a ReQL expression it produces an error. |
That would work. But I think that the users' lives would be much simpler if we got rid of vector clocks completely. |
Well, "much simpler" is the wrong word. A typical user will rarely encounter vector clock conflicts. But I think they will be quite inconvenient when they do occur; the user will probably see them as a hassle. This will be especially true with the new ReQL admin API, because we'll encourage people to use scripts to configure their cluster. Vector clock conflicts are important if two humans make different changes at the same time, and also it's rare for human admins to create a vector clock conflict; but with automated configuration tools, the risk of a coincidence is higher, and the probability that the conflict is actually worth bothering the user about is lower. |
Another problem with vector clocks is that there's no good way to handle a vector clock conflict on the |
On further thought, the proposal to have the system raise an error if the user tries to read a vector clock conflict is hard to implement. Currently, we implement writes as a function that maps the old value to the new value; we would have to distinguish between writes that use the old value and writes that don't. It seems to me that naive timestamp-based resolution is significantly easier to implement than either of the vector-clock solutions. |
This proposal has been approved. We'll implement it as part of the ReQL admin changes. |
I'm a little bit scared of this, but I guess it's probably fine. |
I think it's fine for a couple of reasons:
I think timestamp-based resolution would result in a dramatically better user experience when the edge cases do happen. It's probably not ideal for large deployments, but for the moment there are much bigger issues in those scenarios anyway. By the time we fix those, we'll probably also add a consensus algorithm so this problem will go away. |
Implementation is in CR 1994. |
Merged into |
In #2663, we decided that the new ReQL administrative API should handle vector clock conflicts as follows: Reading from a conflicted value produces an error. Writing to a conflicted value resolves the conflict.
However, I'm not sure that this is actually the best solution. The problem is that we have no good way to return a document that is partially in error. Imagine this situation: A user accidentally causes a vector clock conflict on a table's
database
field. Now they can't access the table's metadata at all; they get an error telling them to "overwrite the document". But maybe they've forgotten what they had the config set to. Even though the valid config is still stored on the server, the user can't access it; they have to reconstruct it. The user experience is similarly bad if they do a range scan over therethinkdb.table_config
artificial table. The table with the metadata conflict will not appear; instead, they will get a message saying that there was an error.We should consider replacing vector clocks with a structure consisting of
(timestamp, uuid, value)
, wheretimestamp
is atime_t
. The semilattice join is defined by comparing first by timestamp, then by UUID. When the user writes to a field, the server will settimestamp
to the larger of the server's currenttime()
and the old timestamp plus one, and it will setuuid
to its machine ID. (Or peer ID. Or a newly generated UUID. It doesn't matter.)Normally, this works transparently, just like vector clocks. If the user issues two updates almost simultaneously, one will be chosen arbitrarily. If the user writes the same field on both sides of a netsplit, whichever write happens later (by wall-clock time) will be chosen, as long as the servers' clocks are sane. If the servers' clocks are insane, then everything still works properly, except that if the user writes the same field on both sides of a netsplit the winner will be arbitrary. The user never sees a conflict; the system always picks a value for the field.
This issue is probably not important.
The text was updated successfully, but these errors were encountered: