Skip to content

Commit

Permalink
[draft] storage: test and document pushing intent across epochs
Browse files Browse the repository at this point in the history
I haven't looked at this code in a while, but while my assumption was
that if a ResolveIntent comes in at a newer epoch, we would keep the
existing intent and rewrite it to that epoch, but apparently we "just"
remove it.
This behavior might make sense in practice (now that our concurrency
control is cooperative), but it was not what I remembered, and plays
a prominent role in the correctness bug cockroachdb#69414.

Still need to figure out what to do with this. Comments definitely
refer to the behavior I remember. It's possible that we changed this
by accident. Will investigate more.

Release justification: testing improvement related to release blocker cockroachdb#69414.
Release note: None
  • Loading branch information
tbg committed Sep 8, 2021
1 parent e369d86 commit 437bdba
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 1 deletion.
20 changes: 19 additions & 1 deletion pkg/storage/mvcc_history_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,8 +548,26 @@ func (e *evalCtx) tryWrapForIntentPrinting(rw ReadWriter) ReadWriter {
return rw
}

func (e *evalCtx) getEpoch() enginepb.TxnEpoch {
const key = "epoch"
e.t.Helper()
if !e.hasArg(key) {
return 0
}
var epoch int
e.scanArg(key, &epoch)
return enginepb.TxnEpoch(epoch)
}

func cmdResolveIntent(e *evalCtx) error {
txn := e.getTxn(mandatory)
txn := e.getTxn(mandatory).Clone()
if epoch := e.getEpoch(); epoch > 0 {
txn.Epoch = epoch
}
if ts := e.getTs(nil /* txn */); ts != (hlc.Timestamp{}) {
txn.WriteTimestamp = ts
}

key := e.getKey()
status := e.getTxnStatus()
return e.resolveIntent(e.tryWrapForIntentPrinting(e.engine), key, txn, status)
Expand Down
49 changes: 49 additions & 0 deletions pkg/storage/testdata/mvcc_histories/push_from_old_epoch
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Show that intents are removed when pushed across an epoch change.

# Start txn A and lay down an intent at epoch 2.
run ok
with t=A k=k
txn_begin ts=100
txn_restart
txn_restart
put k=k v=v
----
>> at end:
txn: "A" meta={id=00000000 key="k" pri=0.00000000 epo=2 ts=100.000000000,0 min=0,0 seq=0} lock=true stat=PENDING rts=100.000000000,0 wto=false gul=0,0
meta: "k"/0,0 -> txn={id=00000000 key="k" pri=0.00000000 epo=2 ts=100.000000000,0 min=0,0 seq=0} ts=100.000000000,0 del=false klen=12 vlen=6
data: "k"/100.000000000,0 -> /BYTES/v

# A pusher who knows that this txn is now in epoch three pushes the intent.
# The result will be that the intent is removed. Note that we alternatively
# could also let the intent survive, but we currently do not do that.
run ok
with t=A k=k epoch=3 ts=101 status=PENDING
resolve_intent
----
>> at end:
<no data>

# Repeat the above scenario with a txn B, the only difference being that when
# we push the intent, we use a timestamp that is behind the txn's timestamp,
# meaning that it internally has a chance of hitting a different code path
# as we wouldn't actually move the intent forward in time if we decided to
# keep it.

run ok
with t=B k=k
txn_begin ts=100
txn_restart
txn_restart
put k=k v=v
----
>> at end:
txn: "B" meta={id=00000000 key="k" pri=0.00000000 epo=2 ts=100.000000000,0 min=0,0 seq=0} lock=true stat=PENDING rts=100.000000000,0 wto=false gul=0,0
meta: "k"/0,0 -> txn={id=00000000 key="k" pri=0.00000000 epo=2 ts=100.000000000,0 min=0,0 seq=0} ts=100.000000000,0 del=false klen=12 vlen=6
data: "k"/100.000000000,0 -> /BYTES/v

run ok
with t=B k=k epoch=3 ts=99 status=PENDING
resolve_intent
----
>> at end:
<no data>

0 comments on commit 437bdba

Please sign in to comment.