I thought I didn't know what it was when I heard of them, then realized that it's not a lock at all, it's just a row version column, with the basic rule don't overwrite without having seen what you're about to overwrite.
Same goes for `git push --force`, always use `git push --force-with-lease` instead.
Wait, how do you ensure that the lock version itself is safely written by two or more writers? Not to mention what happens if you read the version and in the time you decide to do a write someone else incremented the version.
It is a locking convention, achieving something locks are used for, but you can't point to one thing and say, there, that's the lock. Contrast with a database row lock where no other transaction can change that row or get a locked access to it until released.
e.g. if the version column is an incrementing number, then it relies on no client unilaterally incrementing the value on failure and retrying--not much of a 'lock'.
I agree. Optimistic locking is more akin to an atomic CAS operation than a lock. The usage of the API is the same; if the compare fails, fetch again and retry in a loop. (Incidentally, it doesn’t experience the ABA problem because nobody writes a lower lock_version unless they wait until the field overflows and wraps around… !).
Nobody would call CAS a lock. If your system only uses CAS, it should rightly be called “lock-free”.
The point to call Optimistic Locking by its other name Optimistic Concurrency Control (OCC) is a great one and I'll be doing that from now on.
In the spirit of trying to keep this complex subject free of misrepresentation... Compare-and-set (CAS, or alternatively compare-and-swap) is commonly used to implement lock-free algorithms.
A 'spin lock' where a thread uses only CAS in a tight loop and not carrying on until the lock is acquired is indeed a lock and not a kind of non-blocking or lock-free algorithm.
You can actually think of the version number in optimistic locking as a shared key combination. First party to use the key gets to pick the next combination, invalidating any other concurrent copies.
Performance and implementation characteristics differ but the end result is functionally the same as a pessimistic lock, which is why they're both called "locking" mechanisms.
The end result is functionally very different. If you were given a shared updatable value, and were told that the only API was non-blocking and you would have to retry in a loop until it succeeded, would you call it a lock? It’s straight up not a lock.
The functional difference is crucial here, the non-lock characteristics are what allows them to offer atomic updates via HTTP. They couldn’t have used pessimistic locking to do this, not only because it is is limited to a single db transaction, but because they can not trust API users or the network to ensure the rows ever get unlocked.
A lock does not offer a guarantee of completion but one of integrity. Any serious pessimistic lock granted will have a timeout associated with it (in case the owner dies, etc.), which might cause your operation to fail if it takes too long. Which would require a retry in the same way that you would retry an optimistic lock. Then again, it just depends on timing.
It's not a lock in the sense that that is succeeds or fails immediatelly.
It is a lock in the sense that it allows success only.
Pesimistic lock usually means "maybe wait then success". In complex locking spaghetti it may mean deadlock. It may also mean wait then timeout. It may also mean wait then timeout then I don't know what actually happened, maybe success, maybe not.
Same goes for `git push --force`, always use `git push --force-with-lease` instead.