This is good work, and the lock semantics and fencing token (epoch) make a lot of sense. I can't help but think that implementing java.util.concurrent.locks.Lock will turn out to be a liability. The problem here is that the code looks like a Java lock, but the semantics are entirely different with regards to failure. Specifically:
While we’re on this subject, the same logic applies even to the primary FencedLock.lock() call: at the very next line of code in your program, you may no longer be holding the lock.
That's not, in most programmer's experience, how locks work. This behavior is necessary (at some level) to deal with partial failures and stalls of clients, but means that if you use this like Lock your code will be very wrong.
Note the key message here: all external services must participate in the fencing-token protocol, with guaranteed linearizability, for the whole setup to uphold its invariants.
So this isn't really like a Java lock at all, and instead is a nice convenient way to build part of an epoch/view change implementation. That's useful, but in my mind the API they chose will reduce the likelihood that non-experts will use this correctly.
Comments
This is good work, and the lock semantics and fencing token (epoch) make a lot of sense. I can't help but think that implementing java.util.concurrent.locks.Lock will turn out to be a liability. The problem here is that the code looks like a Java lock, but the semantics are entirely different with regards to failure. Specifically:
That's not, in most programmer's experience, how locks work. This behavior is necessary (at some level) to deal with partial failures and stalls of clients, but means that if you use this like Lock your code will be very wrong.
So this isn't really like a Java lock at all, and instead is a nice convenient way to build part of an epoch/view change implementation. That's useful, but in my mind the API they chose will reduce the likelihood that non-experts will use this correctly.