mirror of
https://github.com/pingcap/tla-plus.git
synced 2025-03-30 18:20:05 +08:00
ConcurrentPercolator: remove the pre rollback (#23)
This commit is contained in:
parent
2b1c387bbb
commit
36aa05a586
@ -64,8 +64,7 @@ Range(m) ==
|
|||||||
{m[i] : i \in DOMAIN m}
|
{m[i] : i \in DOMAIN m}
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
\* Checks whether there is a lock of key $k$, whose $ts$ is less or equal than
|
\* Checks whether there is a lock of key $k$, whose $ts$ is less than or equal to $ts$.
|
||||||
\* $ts$.
|
|
||||||
hasLockLE(k, ts) ==
|
hasLockLE(k, ts) ==
|
||||||
\E l \in key_lock[k] : l.ts <= ts
|
\E l \in key_lock[k] : l.ts <= ts
|
||||||
|
|
||||||
@ -90,10 +89,24 @@ findWriteWithStartTS(k, ts) ==
|
|||||||
findWriteWithCommitTS(k, ts) ==
|
findWriteWithCommitTS(k, ts) ==
|
||||||
{w \in Range(key_write[k]) : (w.type = "write" /\ w.ts = ts)}
|
{w \in Range(key_write[k]) : (w.type = "write" /\ w.ts = ts)}
|
||||||
|
|
||||||
\* Returns TRUE if there is a rollback for key $k$ at timestamp $ts$.
|
\* Returns TRUE if there is a rollback for key $k$ that is not deleted logically at timestamp $ts$.
|
||||||
|
hasRollbackNotDeleted(k, ts) ==
|
||||||
|
{r \in Range(key_write[k]) : (r.type = "rollback" /\ r.is_deleted = FALSE /\ r.ts = ts )} # {}
|
||||||
|
|
||||||
|
\* Returns TRUE if there is a rollback for key $k$ at timestamp $ts$
|
||||||
hasRollback(k, ts) ==
|
hasRollback(k, ts) ==
|
||||||
{r \in Range(key_write[k]) : (r.type = "rollback" /\ r.ts = ts)} # {}
|
{r \in Range(key_write[k]) : (r.type = "rollback" /\ r.ts = ts)} # {}
|
||||||
|
|
||||||
|
\* Returns TRUE if the write is rollback with ts equal to $ts$
|
||||||
|
\* and this rollback is marked as deleted.
|
||||||
|
isRollbackWithDeleted(w, ts) ==
|
||||||
|
(w.type = "rollback" /\ w.ts = ts /\ w.is_deleted = TRUE)
|
||||||
|
|
||||||
|
\* Returns TRUE if there is a rollback at timestamp $ts$
|
||||||
|
\* and this rollback is marked as deleted.
|
||||||
|
hasRollbackWithDeleted(ws, ts) ==
|
||||||
|
{r \in Range(ws) : isRollbackWithDeleted(r, ts)} # {}
|
||||||
|
|
||||||
\* Updates $key_si$ for key $k$. If a new version of key $k$ is committed with
|
\* Updates $key_si$ for key $k$. If a new version of key $k$ is committed with
|
||||||
\* $commit_ts$ < last read timestamp, consider the snapshot isolation invariant
|
\* $commit_ts$ < last read timestamp, consider the snapshot isolation invariant
|
||||||
\* for key $k$ has been violated.
|
\* for key $k$ has been violated.
|
||||||
@ -104,6 +117,45 @@ checkSnapshotIsolation(k, commit_ts) ==
|
|||||||
ELSE
|
ELSE
|
||||||
UNCHANGED <<key_si>>
|
UNCHANGED <<key_si>>
|
||||||
|
|
||||||
|
\* Returns the writes with ts less than or equal to $ts$ and is not deleted logically
|
||||||
|
findWriteLessEqualTS(kw, ts) ==
|
||||||
|
{w \in Range(kw) : (w.ts <= ts /\ w.is_deleted = FALSE)}
|
||||||
|
|
||||||
|
\* Returns the write whose $ts$ is the max in all writes
|
||||||
|
getWriteWithMaxTS(w) == CHOOSE x \in w : \A y \in w : x.ts >= y.ts
|
||||||
|
|
||||||
|
\* Deletes element from $seq$ logically
|
||||||
|
logicalDeleteElement(seq, e)==
|
||||||
|
[i \in 1..Len(seq)|->IF seq[i] # e THEN seq[i] ELSE [ts |-> seq[i].ts, type |-> seq[i].type, is_deleted |-> TRUE]]
|
||||||
|
|
||||||
|
\* Removes the pre rollback, whose ts is less than or equal to $ts$.
|
||||||
|
collapsePreRollback(w, ts) ==
|
||||||
|
LET
|
||||||
|
writes == findWriteLessEqualTS(w, ts)
|
||||||
|
IN
|
||||||
|
IF writes # {}
|
||||||
|
THEN
|
||||||
|
LET
|
||||||
|
maxTsWrite == getWriteWithMaxTS(writes)
|
||||||
|
IN
|
||||||
|
IF maxTsWrite.type = "rollback"
|
||||||
|
THEN
|
||||||
|
logicalDeleteElement(w, maxTsWrite)
|
||||||
|
ELSE
|
||||||
|
w
|
||||||
|
ELSE
|
||||||
|
w
|
||||||
|
|
||||||
|
\* Writes rollback record to key write.
|
||||||
|
\* If the rollback with the ts equal to $ts$ exists and is marked as deleted,
|
||||||
|
\* which will be overwritten by the new rollback.
|
||||||
|
writeRollback(ws, ts) ==
|
||||||
|
IF hasRollbackWithDeleted(ws, ts)
|
||||||
|
THEN
|
||||||
|
[i \in 1..Len(ws)|->IF isRollbackWithDeleted(ws[i], ts) THEN ws[i] ELSE [ts |-> ws[i].ts, type |-> ws[i].type, is_deleted |-> FALSE]]
|
||||||
|
ELSE
|
||||||
|
Append(collapsePreRollback(ws, ts), [ts |-> ts, type |-> "rollback", is_deleted |-> FALSE])
|
||||||
|
|
||||||
\* Cleans up a stale lock and its data.
|
\* Cleans up a stale lock and its data.
|
||||||
\* If the lock is a secondary lock, and the assoicated primary lock is cleaned
|
\* If the lock is a secondary lock, and the assoicated primary lock is cleaned
|
||||||
\* up, we can clean up the lock and do,
|
\* up, we can clean up the lock and do,
|
||||||
@ -115,8 +167,7 @@ cleanupStaleLock(k, ts) ==
|
|||||||
eraseLock(key, l) ==
|
eraseLock(key, l) ==
|
||||||
/\ key_data' = [key_data EXCEPT ![key] = @ \ {[ts |-> l.ts]}]
|
/\ key_data' = [key_data EXCEPT ![key] = @ \ {[ts |-> l.ts]}]
|
||||||
/\ key_lock' = [key_lock EXCEPT ![key] = @ \ {l}]
|
/\ key_lock' = [key_lock EXCEPT ![key] = @ \ {l}]
|
||||||
/\ key_write' = [key_write EXCEPT ![key] =
|
/\ key_write' = [key_write EXCEPT ![key] = writeRollback(key_write[key], l.ts)]
|
||||||
Append(@, [ts |-> l.ts, type |-> "rollback"])]
|
|
||||||
IN
|
IN
|
||||||
\E l \in key_lock[k] :
|
\E l \in key_lock[k] :
|
||||||
/\ isStaleLock(l, ts)
|
/\ isStaleLock(l, ts)
|
||||||
@ -134,7 +185,7 @@ cleanupStaleLock(k, ts) ==
|
|||||||
\* the primary key is not committed, clean up the data.
|
\* the primary key is not committed, clean up the data.
|
||||||
\* Note we should always clean up the corresponding primary
|
\* Note we should always clean up the corresponding primary
|
||||||
\* lock first, then this secondary lock.
|
\* lock first, then this secondary lock.
|
||||||
IF hasRollback(l.primary, l.ts) = FALSE
|
IF hasRollbackNotDeleted(l.primary, l.ts) = FALSE
|
||||||
THEN
|
THEN
|
||||||
/\ eraseLock(l.primary, l)
|
/\ eraseLock(l.primary, l)
|
||||||
/\ UNCHANGED <<key_si>>
|
/\ UNCHANGED <<key_si>>
|
||||||
@ -218,7 +269,8 @@ commitPrimary(c) ==
|
|||||||
/\ key_write' = [key_write EXCEPT ![primary] =
|
/\ key_write' = [key_write EXCEPT ![primary] =
|
||||||
Append(@, [ts |-> commit_ts,
|
Append(@, [ts |-> commit_ts,
|
||||||
type |-> "write",
|
type |-> "write",
|
||||||
start_ts |-> start_ts])]
|
start_ts |-> start_ts,
|
||||||
|
is_deleted |-> FALSE])]
|
||||||
/\ key_lock' = [key_lock EXCEPT ![primary] = @ \ {[ts |-> start_ts,
|
/\ key_lock' = [key_lock EXCEPT ![primary] = @ \ {[ts |-> start_ts,
|
||||||
primary |-> primary]}]
|
primary |-> primary]}]
|
||||||
/\ checkSnapshotIsolation(primary, commit_ts)
|
/\ checkSnapshotIsolation(primary, commit_ts)
|
||||||
@ -330,8 +382,8 @@ KeyLockTypeInv ==
|
|||||||
key_lock \in [KEY -> SUBSET [ts : Nat, primary : KEY]]
|
key_lock \in [KEY -> SUBSET [ts : Nat, primary : KEY]]
|
||||||
|
|
||||||
KeyWriteTypeInv ==
|
KeyWriteTypeInv ==
|
||||||
key_write \in [KEY -> Seq([ts : Nat, type : {"write"}, start_ts : Nat] \union
|
key_write \in [KEY -> Seq([ts : Nat, type : {"write"}, start_ts : Nat, is_deleted: BOOLEAN] \union
|
||||||
[ts : Nat, type : {"rollback"}])
|
[ts : Nat, type : {"rollback"}, is_deleted: BOOLEAN])
|
||||||
]
|
]
|
||||||
|
|
||||||
KeyLastReadTsTypeInv ==
|
KeyLastReadTsTypeInv ==
|
||||||
@ -387,7 +439,7 @@ CommittedConsistency ==
|
|||||||
commit_ts == client_ts[c].commit_ts
|
commit_ts == client_ts[c].commit_ts
|
||||||
primary == client_key[c].primary
|
primary == client_key[c].primary
|
||||||
secondary == client_key[c].secondary
|
secondary == client_key[c].secondary
|
||||||
w == [ts |-> commit_ts, type |-> "write", start_ts |-> start_ts]
|
w == [ts |-> commit_ts, type |-> "write", start_ts |-> start_ts, is_deleted |-> FALSE]
|
||||||
IN
|
IN
|
||||||
client_state[c] = "committed" =>
|
client_state[c] = "committed" =>
|
||||||
\* The primary key lock must be cleaned up, and no any older lock.
|
\* The primary key lock must be cleaned up, and no any older lock.
|
||||||
|
Loading…
Reference in New Issue
Block a user