Leases and fencing
Explain consensus, logical ordering, leases and fencing under stated failure and timing assumptions.
THE IDEA
Leases and fencing
A lease grants ownership for a limited time, but a client that is paused when it expires will wake up still believing it owns the lock. A fencing token fixes this: the lock service issues an increasing number with each grant, and the protected resource refuses any request whose token is lower than one it has already accepted. In the example the resource has seen token 8 from the new owner, so the old owner's delayed write with token 7 is rejected.
A lease gives time-bounded ownership. A fencing token (a number that increases with every grant, enforced by the protected resource) rejects a stale owner after a newer owner has acted, even if the old process still believes it owns the lease.
Predict first. Does a lock-expiry timer alone stop a paused old client from writing later?
Chapter context
Coordination lets multiple processes agree on selected shared decisions even though messages can be delayed or lost and participants can stop. Agreement is achieved by a protocol, not by adding a shared timestamp or an informal majority rule.
TRY IT YOURSELF
Part 1. Do it hands-on
Decide accept or reject by hand, then write the lock service and a fenced resource.
A lease gives time-bounded ownership. A fencing token (a number that increases with every grant, enforced by the protected resource) rejects a stale owner after a newer owner has acted, even if the old process still believes it owns the lease.
- To do: A resource has accepted fencing token 8 from the new lock owner. The old owner (token 7) wakes from a pause and sends a write. Highest token the resource remembers?
- To do: Does the resource accept the old owner's write bearing token 7? Type accept or reject
- To do: A write bearing token 9?
- To do: Does a lock-expiry timer alone stop a paused old client from writing later? Type yes or no
Part 2. Do it in code
- class LockService: acquire(client) → a NEW monotonically increasing fencing token (1, 2, 3, …) each time anyone acquires; the previous holder's lease is considered expired.
- class Resource with write(token, value): accept only if token >= the highest token seen so far; accepted writes set self.value and remember the token; return True/False. A resource WITHOUT fencing (class NaiveResource) accepts every write.
- scenario(resource_class): A acquires (token 1); A pauses; the lease expires; B acquires (token 2) and writes "b"; A resumes and writes "a" with its old token 1. Return the final value stored.
- is_stale(token, highest): token < highest.
Stuck, or something not working? You can come back to it any time.
CHECK YOUR UNDERSTANDING
Does a lock-expiry timer alone stop a paused old client from writing later?
Chapter reference: math, worked example & code
This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.
Math and notation
For a fixed n-member majority group, quorum size is . A 2f+1-member group can lose f members while retaining a majority, provided the remaining participants can communicate and the protocol's other assumptions hold. Fencing requires monotonically ordered tokens and enforcement at the resource.
Worked example
Five members require three votes, allowing two unavailable members while a communicating majority remains. Separately, a resource has already accepted token 8 from a new owner. An old owner's delayed operation bearing token 7 must be rejected, regardless of whether the old process still believes it owns the lease.
Reference code
The following example uses the Python standard library and does not call a remote service.
members=5
quorum=members//2+1
assert quorum == 3 and members-quorum == 2
highest=8
def accept(token):
global highest
if token < highest: return False
highest=token
return True
assert not accept(7)
assert accept(8)
assert accept(9)
Python examples are provided for study and local execution; this page does not execute Python.
Common mistakes
A timeout cannot establish a remote process's state. Quorums require full protocol rules. Fencing is ineffective if the resource accepts stale tokens or an attacker can invent authorized tokens.