diff --git a/pkg/storage/mvcc.go b/pkg/storage/mvcc.go index a35cfd9331df..77d0c6bcaca8 100644 --- a/pkg/storage/mvcc.go +++ b/pkg/storage/mvcc.go @@ -4574,6 +4574,7 @@ func MVCCResolveWriteIntent( if err := ltIter.ValueProto(&buf.meta); err != nil { return false, 0, nil, errors.Wrap(err, "unmarshaling lock table value") } + var strOk bool if str == lock.Intent { // Intent resolution requires an MVCC iterator to look up the MVCC // version associated with the intent. Create one. @@ -4588,21 +4589,21 @@ func MVCCResolveWriteIntent( } defer iter.Close() } - ok, err = mvccResolveWriteIntent(ctx, rw, iter, ms, intent, &buf.meta, buf) + strOk, err = mvccResolveWriteIntent(ctx, rw, iter, ms, intent, &buf.meta, buf) } else { - // TODO(nvanbenschoten): implement. - _ = str + strOk, err = mvccReleaseLockInternal(ctx, rw, ms, intent, str, &buf.meta, buf) } if err != nil { return false, 0, nil, err } + ok = ok || strOk } numBytes = int64(rw.BufferedSize() - beforeBytes) return ok, numBytes, nil, nil } // With the separated lock table, we are employing a performance optimization: -// when an intent metadata is removed, we preferably want to do so using a +// when a lock's metadata value is removed, we preferably want to do so using a // SingleDel (as opposed to a Del). This is only safe if the previous operations // on the metadata key allow it. Due to practical limitations, at the time of // writing the condition we need is that the pebble history of the key consists @@ -4613,7 +4614,7 @@ func MVCCResolveWriteIntent( // It is difficult to track the history of engine writes to a key precisely, in // particular when values are ever aborted. So we apply the optimization only to // the main case in which it is useful, namely that of a transaction committing -// its intent that it never re-wrote in the initial epoch (i.e. no chance of it +// its lock that it never re-wrote in the initial epoch (i.e. no chance of it // ever being removed before as part of being pushed). Note that when a txn // refreshes, it stays in the original epoch, and the intents are moved, which // does *not* cause a write to the MVCC metadata key (for which the history has @@ -4630,7 +4631,7 @@ func MVCCResolveWriteIntent( // INSERT INTO kv VALUES(1, 2); // COMMIT; // -// This would first remove the intent (1,1) during the ROLLBACK using a Del (the +// This would first remove the lock (1,1) during the ROLLBACK using a Del (the // anomaly below would occur the same if a SingleDel were used here), and thus // without an additional condition the INSERT (1,2) would be eligible for // committing via a SingleDel. This has to be avoided as well, since the @@ -4651,7 +4652,7 @@ func MVCCResolveWriteIntent( // ↓ // - Set // -// which means that a previously deleted intent metadata would erroneously +// which means that a previously deleted lock metadata would erroneously // become visible again. So on top of restricting SingleDel to the COMMIT case, // we also restrict it to the case of having no ignored sequence number ranges // (i.e. no nested txn was rolled back before the commit). @@ -4676,22 +4677,22 @@ func (h singleDelOptimizationHelper) v() bool { return *h._didNotUpdateMeta } -// onCommitIntent returns true if the SingleDel optimization is available -// for committing an intent. -func (h singleDelOptimizationHelper) onCommitIntent() bool { - // We're committing the intent at epoch zero, the meta tracking says we didn't - // rewrite the intent, and we also didn't previously remove the metadata for +// onCommitLock returns true if the SingleDel optimization is available +// for committing a lock/intent. +func (h singleDelOptimizationHelper) onCommitLock() bool { + // We're committing the lock at epoch zero, the meta tracking says we didn't + // rewrite the lock, and we also didn't previously remove the metadata for // this key as part of a voluntary rollback of a nested txn. So we are safe to // use a SingleDel here. return h.v() && !h._hasIgnoredSeqs && h._epoch == 0 } -// onAbortIntent returns true if the SingleDel optimization is available -// for removing an intent. It is always false. -// Note that "removing an intent" can occur if we know that the epoch +// onAbortLock returns true if the SingleDel optimization is available +// for removing a lock/intent. It is always false. +// Note that "removing a lock" can occur if we know that the epoch // changed, or when a savepoint is rolled back. It does not imply that // the transaction aborted. -func (h singleDelOptimizationHelper) onAbortIntent() bool { +func (h singleDelOptimizationHelper) onAbortLock() bool { return false } @@ -4708,7 +4709,7 @@ func mvccResolveWriteIntent( writer Writer, iter MVCCIterator, ms *enginepb.MVCCStats, - // TODO(nvanbenschoten): rename this field to "resolution". + // TODO(nvanbenschoten): rename this field to "update". intent roachpb.LockUpdate, meta *enginepb.MVCCMetadata, buf *putBuffer, @@ -4967,7 +4968,7 @@ func mvccResolveWriteIntent( writer, metaKey, lock.Intent, newMeta, true /* alreadyExists */) } else { metaKeySize, metaValSize, err = buf.clearLockMeta( - writer, metaKey, lock.Intent, canSingleDelHelper.onCommitIntent(), meta.Txn.ID, ClearOptions{ + writer, metaKey, lock.Intent, canSingleDelHelper.onCommitLock(), meta.Txn.ID, ClearOptions{ ValueSizeKnown: true, ValueSize: uint32(origMetaValSize), }) @@ -5079,7 +5080,7 @@ func mvccResolveWriteIntent( if !ok { // If there is no other version, we should just clean up the key entirely. _, _, err := buf.clearLockMeta( - writer, metaKey, lock.Intent, canSingleDelHelper.onAbortIntent(), meta.Txn.ID, ClearOptions{ + writer, metaKey, lock.Intent, canSingleDelHelper.onAbortLock(), meta.Txn.ID, ClearOptions{ ValueSizeKnown: true, ValueSize: uint32(origMetaValSize), }) @@ -5101,7 +5102,7 @@ func mvccResolveWriteIntent( ValBytes: int64(nextValueLen), } metaKeySize, metaValSize, err := buf.clearLockMeta( - writer, metaKey, lock.Intent, canSingleDelHelper.onAbortIntent(), meta.Txn.ID, ClearOptions{ + writer, metaKey, lock.Intent, canSingleDelHelper.onAbortLock(), meta.Txn.ID, ClearOptions{ ValueSizeKnown: true, ValueSize: uint32(origMetaValSize), }) @@ -5240,6 +5241,7 @@ func MVCCResolveWriteIntentRange( intent.EndKey = nil var lastResolvedKey roachpb.Key + var lastResolvedKeyOk bool for valid, err := ltIter.SeekEngineKeyGE(EngineKey{Key: ltStart}); ; valid, err = ltIter.NextEngineKey() { if err != nil { return 0, 0, nil, 0, errors.Wrap(err, "seeking lock table") @@ -5247,21 +5249,7 @@ func MVCCResolveWriteIntentRange( // No more intents in the given range. break } - keysExceeded = opts.MaxKeys > 0 && numKeys == opts.MaxKeys - bytesExceeded = opts.TargetBytes > 0 && numBytes >= opts.TargetBytes - if keysExceeded || bytesExceeded { - if keysExceeded { - resumeReason = kvpb.RESUME_KEY_LIMIT - } else if bytesExceeded { - resumeReason = kvpb.RESUME_BYTE_LIMIT - } - // We could also compute a tighter nextKey here if we wanted to. - // TODO(nvanbenschoten): this resumeSpan won't be correct if there - // are multiple locks on the same key. What if only of the locks for - // a key are removed? Fix this by resolving zero or all locks on a - // given key. - return numKeys, numBytes, &roachpb.Span{Key: lastResolvedKey.Next(), EndKey: intentEndKey}, resumeReason, nil - } + ltEngineKey, err := ltIter.EngineKey() if err != nil { return 0, 0, nil, 0, errors.Wrap(err, "retrieving lock table key") @@ -5270,29 +5258,58 @@ func MVCCResolveWriteIntentRange( if err != nil { return 0, 0, nil, 0, errors.Wrap(err, "decoding lock table key") } + sameLockedKey := lastResolvedKey.Equal(ltKey.Key) + if !sameLockedKey { + // If this is not the same locked key as the last iteration, check + // whether we've exceeded the max keys or bytes limit. We don't check in + // between locks with different strengths on the same key because we + // can't encode a resume span that would be correct in that case. A + // transaction can only hold up to 3 locks on any given key, so this + // will never lead to us significantly overshooting the TargetBytes + // limit. We also only count each unique locked key once towards the + // MaxKeys limit, so this will never lead to us overshooting the MaxKeys + // limit at all. + keysExceeded = opts.MaxKeys > 0 && numKeys == opts.MaxKeys + bytesExceeded = opts.TargetBytes > 0 && numBytes >= opts.TargetBytes + if keysExceeded || bytesExceeded { + if keysExceeded { + resumeReason = kvpb.RESUME_KEY_LIMIT + } else if bytesExceeded { + resumeReason = kvpb.RESUME_BYTE_LIMIT + } + // We could also compute a tighter nextKey here if we wanted to. + resumeSpan := &roachpb.Span{Key: lastResolvedKey.Next(), EndKey: intentEndKey} + return numKeys, numBytes, resumeSpan, resumeReason, nil + } + + // Copy the underlying bytes of the unsafe key. This is needed for + // stability of the key to check for sameLockedKey and to construct + // a resume span on subsequent iteration. + lastResolvedKey = append(lastResolvedKey[:0], ltKey.Key...) + lastResolvedKeyOk = false + } if ltKey.TxnUUID != intent.Txn.ID { return 0, 0, nil, 0, errors.AssertionFailedf( "unexpected txnID %v != %v while scanning lock table", ltKey.TxnUUID, intent.Txn.ID) } + intent.Key = ltKey.Key if err := ltIter.ValueProto(&buf.meta); err != nil { return 0, 0, nil, 0, errors.Wrap(err, "unmarshaling lock table value") } - // Copy the underlying bytes of the unsafe key. This is needed for - // stability of the key to construct a resume span on subsequent - // iteration. - intent.Key = ltKey.Key - lastResolvedKey = append(lastResolvedKey[:0], intent.Key...) beforeBytes := rw.BufferedSize() var ok bool if ltKey.Strength == lock.Intent { ok, err = mvccResolveWriteIntent(ctx, rw, mvccIter, ms, intent, &buf.meta, buf) } else { - // TODO(nvanbenschoten): implement. - _ = ltKey.Strength + ok, err = mvccReleaseLockInternal(ctx, rw, ms, intent, ltKey.Strength, &buf.meta, buf) } if err != nil { log.Warningf(ctx, "failed to resolve intent for key %q: %+v", lastResolvedKey, err) - } else if ok { + } + if ok && !lastResolvedKeyOk { + // We only count the first successfully resolved lock/intent on a + // given key towards the returned key count and key limit. + lastResolvedKeyOk = true numKeys++ } numBytes += int64(rw.BufferedSize() - beforeBytes) @@ -5458,6 +5475,57 @@ func validateLockAcquisition(txn *roachpb.Transaction, str lock.Strength) error return nil } +// mvccReleaseLockInternal releases a lock at the specified key and strength and +// by the specified transaction. The function accepts the instructions for how +// to release the lock (encoded in the LockUpdate), and the current value of the +// lock (meta). +func mvccReleaseLockInternal( + ctx context.Context, + writer Writer, + ms *enginepb.MVCCStats, + update roachpb.LockUpdate, + str lock.Strength, + meta *enginepb.MVCCMetadata, + buf *putBuffer, +) (bool, error) { + finalized := update.Status.IsFinalized() + rolledBack := meta.Txn.Epoch < update.Txn.Epoch || + (meta.Txn.Epoch == update.Txn.Epoch && enginepb.TxnSeqIsIgnored(meta.Txn.Sequence, update.IgnoredSeqNums)) + release := finalized || rolledBack + if !release { + return false, nil + } + + canSingleDelHelper := singleDelOptimizationHelper{ + _didNotUpdateMeta: meta.TxnDidNotUpdateMeta, + _hasIgnoredSeqs: len(update.IgnoredSeqNums) > 0, + _epoch: update.Txn.Epoch, + } + var txnDidNotUpdateMeta bool + if update.Status == roachpb.COMMITTED && !rolledBack { + txnDidNotUpdateMeta = canSingleDelHelper.onCommitLock() + } else { + txnDidNotUpdateMeta = canSingleDelHelper.onAbortLock() + } + + metaKey := MakeMVCCMetadataKey(update.Key) + origMetaKeySize := int64(metaKey.EncodedSize()) + origMetaValSize := int64(meta.Size()) + keyBytes, valBytes, err := buf.clearLockMeta(writer, metaKey, str, txnDidNotUpdateMeta, meta.Txn.ID, ClearOptions{ + ValueSizeKnown: true, + ValueSize: uint32(meta.Size()), + }) + if err != nil { + return false, err + } + + // TODO(nvanbenschoten): handle MVCCStats update after addressing #109645. + _, _, _, _, _ = ms, origMetaKeySize, origMetaValSize, keyBytes, valBytes + + return true, nil + +} + // MVCCGarbageCollect creates an iterator on the ReadWriter. In parallel // it iterates through the keys listed for garbage collection by the // keys slice. The iterator is seeked in turn to each listed diff --git a/pkg/storage/mvcc_history_test.go b/pkg/storage/mvcc_history_test.go index a1ec2c66b902..b98435d536db 100644 --- a/pkg/storage/mvcc_history_test.go +++ b/pkg/storage/mvcc_history_test.go @@ -379,6 +379,10 @@ func TestMVCCHistories(t *testing.T) { if err != nil { return errors.Wrapf(err, "decoding LockTable key: %v", eKey) } + if ltKey.Strength == lock.Intent { + // Ignore intents, which are reported by reportDataEntries. + continue + } // Unmarshal. v, err := iter.UnsafeValue() if err != nil { @@ -601,11 +605,11 @@ func TestMVCCHistories(t *testing.T) { } cmd := e.getCmd() - txnChange = txnChange || cmd.typ == typTxnUpdate - dataChange = dataChange || cmd.typ == typDataUpdate - locksChange = locksChange || cmd.typ == typLocksUpdate + txnChange = txnChange || cmd.typ&typTxnUpdate != 0 + dataChange = dataChange || cmd.typ&typDataUpdate != 0 + locksChange = locksChange || cmd.typ&typLocksUpdate != 0 - if trace || (stats && cmd.typ == typDataUpdate) { + if trace || (stats && cmd.typ&typDataUpdate != 0) { // If tracing is also requested by the datadriven input, // we'll trace the statement in the actual results too. buf.Printf(">> %s", d.Cmd) @@ -638,10 +642,10 @@ func TestMVCCHistories(t *testing.T) { // If tracing is enabled, we report the intermediate results // after each individual step in the script. // This may modify foundErr too. - reportResults(cmd.typ == typTxnUpdate, cmd.typ == typDataUpdate, cmd.typ == typLocksUpdate) + reportResults(cmd.typ&typTxnUpdate != 0, cmd.typ&typDataUpdate != 0, cmd.typ&typLocksUpdate != 0) } - if stats && cmd.typ == typDataUpdate { + if stats && cmd.typ&typDataUpdate != 0 { // If stats are enabled, emit evaluated stats returned by the // command, and compare them with the real computed stats diff. var msEngineDiff enginepb.MVCCStats @@ -753,7 +757,7 @@ type cmd struct { type cmdType int const ( - typReadOnly cmdType = iota + typReadOnly cmdType = 1 << iota typTxnUpdate typDataUpdate typLocksUpdate @@ -770,8 +774,8 @@ var commands = map[string]cmd{ "txn_step": {typTxnUpdate, cmdTxnStep}, "txn_update": {typTxnUpdate, cmdTxnUpdate}, - "resolve_intent": {typDataUpdate, cmdResolveIntent}, - "resolve_intent_range": {typDataUpdate, cmdResolveIntentRange}, + "resolve_intent": {typDataUpdate | typLocksUpdate, cmdResolveIntent}, + "resolve_intent_range": {typDataUpdate | typLocksUpdate, cmdResolveIntentRange}, "check_intent": {typReadOnly, cmdCheckIntent}, "add_unreplicated_lock": {typLocksUpdate, cmdAddUnreplicatedLock}, "check_for_acquire_lock": {typReadOnly, cmdCheckForAcquireLock}, diff --git a/pkg/storage/testdata/mvcc_histories/replicated_locks b/pkg/storage/testdata/mvcc_histories/replicated_locks index 3f7a3093f03a..090182341ffb 100644 --- a/pkg/storage/testdata/mvcc_histories/replicated_locks +++ b/pkg/storage/testdata/mvcc_histories/replicated_locks @@ -241,7 +241,6 @@ lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false -lock (Replicated): "k4"/Intent -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=10.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true run error check_for_acquire_lock t=B k=k4 str=shared @@ -257,7 +256,6 @@ lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false -lock (Replicated): "k4"/Intent -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=10.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true error: (*kvpb.LockConflictError:) conflicting locks on "k4" # The intent history is considered when determining whether a reacquisition is @@ -288,7 +286,6 @@ lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false -lock (Replicated): "k4"/Intent -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false run with t=A @@ -302,7 +299,6 @@ lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false -lock (Replicated): "k4"/Intent -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false run with t=A @@ -316,7 +312,6 @@ lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false -lock (Replicated): "k4"/Intent -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true # Replicated locks are ignored by non-locking scans by any transaction. Note @@ -512,3 +507,259 @@ data: "k3"/10.000000000,0 -> / data: "k3"/5.000000000,0 -> /BYTES/v3 meta: "k4"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false data: "k4"/10.000000000,0 -> /BYTES/v4_prime + +# Release locks. + +# Reset ignored sequence numbers for now. +run ok +txn_ignore_seqs t=A seqs +---- +>> at end: +txn: "A" meta={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} lock=true stat=PENDING rts=10.000000000,0 wto=false gul=0,0 + +# Pending resolution without epoch bump or savepoint rollback is a no-op. +run ok +resolve_intent t=A k=k1 status=PENDING +---- +resolve_intent: "k1" -> resolved key = false +>> at end: +data: "k1"/5.000000000,0 -> /BYTES/v1 +meta: "k2"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v2}} mergeTs= txnDidNotUpdateMeta=false +data: "k2"/10.000000000,0 -> / +data: "k2"/5.000000000,0 -> /BYTES/v2 +meta: "k3"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v3}} mergeTs= txnDidNotUpdateMeta=false +data: "k3"/10.000000000,0 -> / +data: "k3"/5.000000000,0 -> /BYTES/v3 +meta: "k4"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false +data: "k4"/10.000000000,0 -> /BYTES/v4_prime +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Committed resolution releases the lock. +run ok +resolve_intent t=A k=k1 status=COMMITTED +---- +resolve_intent: "k1" -> resolved key = true +>> at end: +data: "k1"/5.000000000,0 -> /BYTES/v1 +meta: "k2"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v2}} mergeTs= txnDidNotUpdateMeta=false +data: "k2"/10.000000000,0 -> / +data: "k2"/5.000000000,0 -> /BYTES/v2 +meta: "k3"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v3}} mergeTs= txnDidNotUpdateMeta=false +data: "k3"/10.000000000,0 -> / +data: "k3"/5.000000000,0 -> /BYTES/v3 +meta: "k4"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false +data: "k4"/10.000000000,0 -> /BYTES/v4_prime +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Re-acquire the lock. +run ok +acquire_lock t=A k=k1 str=shared +---- +>> at end: +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Aborted resolution releases the lock. +run ok +resolve_intent t=A k=k1 status=ABORTED +---- +resolve_intent: "k1" -> resolved key = true +>> at end: +data: "k1"/5.000000000,0 -> /BYTES/v1 +meta: "k2"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v2}} mergeTs= txnDidNotUpdateMeta=false +data: "k2"/10.000000000,0 -> / +data: "k2"/5.000000000,0 -> /BYTES/v2 +meta: "k3"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v3}} mergeTs= txnDidNotUpdateMeta=false +data: "k3"/10.000000000,0 -> / +data: "k3"/5.000000000,0 -> /BYTES/v3 +meta: "k4"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false +data: "k4"/10.000000000,0 -> /BYTES/v4_prime +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Re-acquire the lock. +run ok +acquire_lock t=A k=k1 str=shared +---- +>> at end: +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Pending resolution with newer epoch releases the lock. +run ok +with t=A + txn_restart + resolve_intent k=k1 status=PENDING +---- +resolve_intent: "k1" -> resolved key = true +>> at end: +txn: "A" meta={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=2 ts=10.000000000,0 min=0,0 seq=0} lock=true stat=PENDING rts=10.000000000,0 wto=false gul=0,0 +data: "k1"/5.000000000,0 -> /BYTES/v1 +meta: "k2"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v2}} mergeTs= txnDidNotUpdateMeta=false +data: "k2"/10.000000000,0 -> / +data: "k2"/5.000000000,0 -> /BYTES/v2 +meta: "k3"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v3}} mergeTs= txnDidNotUpdateMeta=false +data: "k3"/10.000000000,0 -> / +data: "k3"/5.000000000,0 -> /BYTES/v3 +meta: "k4"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false +data: "k4"/10.000000000,0 -> /BYTES/v4_prime +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Re-acquire the lock at the new epoch. +run ok +acquire_lock t=A k=k1 str=shared +---- +>> at end: +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=2 ts=10.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Pending resolution with older epoch is a no-op, regardless of savepoint +# rollback. +run ok +with t=A + txn_restart epoch=1 + resolve_intent k=k1 status=PENDING +---- +resolve_intent: "k1" -> resolved key = false +>> at end: +txn: "A" meta={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=0} lock=true stat=PENDING rts=10.000000000,0 wto=false gul=0,0 +data: "k1"/5.000000000,0 -> /BYTES/v1 +meta: "k2"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v2}} mergeTs= txnDidNotUpdateMeta=false +data: "k2"/10.000000000,0 -> / +data: "k2"/5.000000000,0 -> /BYTES/v2 +meta: "k3"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v3}} mergeTs= txnDidNotUpdateMeta=false +data: "k3"/10.000000000,0 -> / +data: "k3"/5.000000000,0 -> /BYTES/v3 +meta: "k4"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false +data: "k4"/10.000000000,0 -> /BYTES/v4_prime +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=2 ts=10.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +run ok +with t=A + txn_ignore_seqs seqs=0-0 + resolve_intent k=k1 status=PENDING +---- +resolve_intent: "k1" -> resolved key = false +>> at end: +txn: "A" meta={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=0} lock=true stat=PENDING rts=10.000000000,0 wto=false gul=0,0 isn=1 +data: "k1"/5.000000000,0 -> /BYTES/v1 +meta: "k2"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v2}} mergeTs= txnDidNotUpdateMeta=false +data: "k2"/10.000000000,0 -> / +data: "k2"/5.000000000,0 -> /BYTES/v2 +meta: "k3"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v3}} mergeTs= txnDidNotUpdateMeta=false +data: "k3"/10.000000000,0 -> / +data: "k3"/5.000000000,0 -> /BYTES/v3 +meta: "k4"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false +data: "k4"/10.000000000,0 -> /BYTES/v4_prime +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=2 ts=10.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Pending resolution of the lock in the same epoch without a savepoint rollback +# is a no-op. +run ok +with t=A + txn_restart epoch=2 + resolve_intent k=k1 status=PENDING +---- +resolve_intent: "k1" -> resolved key = false +>> at end: +txn: "A" meta={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=2 ts=10.000000000,0 min=0,0 seq=0} lock=true stat=PENDING rts=10.000000000,0 wto=false gul=0,0 +data: "k1"/5.000000000,0 -> /BYTES/v1 +meta: "k2"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v2}} mergeTs= txnDidNotUpdateMeta=false +data: "k2"/10.000000000,0 -> / +data: "k2"/5.000000000,0 -> /BYTES/v2 +meta: "k3"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v3}} mergeTs= txnDidNotUpdateMeta=false +data: "k3"/10.000000000,0 -> / +data: "k3"/5.000000000,0 -> /BYTES/v3 +meta: "k4"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false +data: "k4"/10.000000000,0 -> /BYTES/v4_prime +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k1"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=2 ts=10.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Pending resolution of the lock in the same epoch with savepoint rollback +# releases the lock. +run ok +with t=A + txn_ignore_seqs seqs=0-0 + resolve_intent k=k1 status=PENDING +---- +resolve_intent: "k1" -> resolved key = true +>> at end: +txn: "A" meta={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=2 ts=10.000000000,0 min=0,0 seq=0} lock=true stat=PENDING rts=10.000000000,0 wto=false gul=0,0 isn=1 +data: "k1"/5.000000000,0 -> /BYTES/v1 +meta: "k2"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v2}} mergeTs= txnDidNotUpdateMeta=false +data: "k2"/10.000000000,0 -> / +data: "k2"/5.000000000,0 -> /BYTES/v2 +meta: "k3"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=4} ts=10.000000000,0 del=true klen=12 vlen=0 ih={{3 /BYTES/v3}} mergeTs= txnDidNotUpdateMeta=false +data: "k3"/10.000000000,0 -> / +data: "k3"/5.000000000,0 -> /BYTES/v3 +meta: "k4"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=2} ts=10.000000000,0 del=false klen=12 vlen=13 ih={{1 /BYTES/v4}} mergeTs= txnDidNotUpdateMeta=false +data: "k4"/10.000000000,0 -> /BYTES/v4_prime +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "k2"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k2"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k3"/Exclusive -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=1} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=false +lock (Replicated): "k4"/Shared -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=1 ts=10.000000000,0 min=0,0 seq=3} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Ranged resolution behaves like single-key resolution. +# As always, it also resolves intents in the range. +run ok +resolve_intent_range t=A k=k2 end=k5 status=COMMITTED +---- +resolve_intent_range: "k2"-"k5" -> resolved 3 key(s) +>> at end: +data: "k1"/5.000000000,0 -> /BYTES/v1 +data: "k2"/5.000000000,0 -> /BYTES/v2 +data: "k3"/5.000000000,0 -> /BYTES/v3 +lock (Replicated): "k1"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=11.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +# Aborted resolution for other transaction releases the lock. +run ok +resolve_intent t=B k=k1 status=ABORTED +---- +resolve_intent: "k1" -> resolved key = true +>> at end: +data: "k1"/5.000000000,0 -> /BYTES/v1 +data: "k2"/5.000000000,0 -> /BYTES/v2 +data: "k3"/5.000000000,0 -> /BYTES/v3 diff --git a/pkg/storage/testdata/mvcc_histories/resolve_intent_pagination b/pkg/storage/testdata/mvcc_histories/resolve_intent_pagination index b4a46ff05a44..93f65399321a 100644 --- a/pkg/storage/testdata/mvcc_histories/resolve_intent_pagination +++ b/pkg/storage/testdata/mvcc_histories/resolve_intent_pagination @@ -136,3 +136,68 @@ data: "dddddddddddddddddddddddddddddddddddddddddddddddddd"/1.000000000,0 -> /BYT data: "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"/1.000000000,0 -> /BYTES/e meta: "f"/0,0 -> txn={id=00000001 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=1.000000000,0 del=false klen=12 vlen=6 mergeTs= txnDidNotUpdateMeta=true data: "f"/1.000000000,0 -> /BYTES/f + + +# Test MaxKeys and TargetBytes for resolve intent range with replicated locks. + +run ok +clear_range k=a end=z +---- +>> at end: + + +# Put some test data with locks. +run ok +with t=B + txn_begin ts=1 + acquire_lock k=a str=shared + put k=a v=a + acquire_lock k=b str=shared + acquire_lock k=b str=exclusive + put k=b v=b + acquire_lock k=c str=shared +---- +>> at end: +txn: "B" meta={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} lock=true stat=PENDING rts=1.000000000,0 wto=false gul=0,0 +meta: "a"/0,0 -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=1.000000000,0 del=false klen=12 vlen=6 mergeTs= txnDidNotUpdateMeta=true +data: "a"/1.000000000,0 -> /BYTES/a +meta: "b"/0,0 -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=1.000000000,0 del=false klen=12 vlen=6 mergeTs= txnDidNotUpdateMeta=true +data: "b"/1.000000000,0 -> /BYTES/b +lock (Replicated): "a"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "b"/Exclusive -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "b"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "c"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +run ok +resolve_intent_range t=B k=a end=z status=COMMITTED maxKeys=1 batched +---- +resolve_intent_range: "a"-"z" -> resolved 1 key(s), 56 bytes +resolve_intent_range: resume span ["a\x00","z") RESUME_KEY_LIMIT +resolve_intent_range: batch after write is non-empty +>> at end: +data: "a"/1.000000000,0 -> /BYTES/a +meta: "b"/0,0 -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=1.000000000,0 del=false klen=12 vlen=6 mergeTs= txnDidNotUpdateMeta=true +data: "b"/1.000000000,0 -> /BYTES/b +lock (Replicated): "b"/Exclusive -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "b"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true +lock (Replicated): "c"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +run ok +resolve_intent_range t=B k=a end=z status=COMMITTED targetBytes=1 batched +---- +resolve_intent_range: "a"-"z" -> resolved 1 key(s), 84 bytes +resolve_intent_range: resume span ["b\x00","z") RESUME_BYTE_LIMIT +resolve_intent_range: batch after write is non-empty +>> at end: +data: "a"/1.000000000,0 -> /BYTES/a +data: "b"/1.000000000,0 -> /BYTES/b +lock (Replicated): "c"/Shared -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=1.000000000,0 min=0,0 seq=0} ts=0,0 del=false klen=0 vlen=0 mergeTs= txnDidNotUpdateMeta=true + +run ok +resolve_intent_range t=B k=a end=z status=COMMITTED maxKeys=1 batched +---- +resolve_intent_range: "a"-"z" -> resolved 1 key(s), 28 bytes +resolve_intent_range: batch after write is non-empty +>> at end: +data: "a"/1.000000000,0 -> /BYTES/a +data: "b"/1.000000000,0 -> /BYTES/b diff --git a/pkg/storage/testdata/mvcc_histories/skip_locked b/pkg/storage/testdata/mvcc_histories/skip_locked index 60ddf7b1af7a..7119e9782ed3 100644 --- a/pkg/storage/testdata/mvcc_histories/skip_locked +++ b/pkg/storage/testdata/mvcc_histories/skip_locked @@ -39,8 +39,6 @@ meta: "k3"/0,0 -> txn={id=00000003 key=/Min iso=Serializable pri=0.00000000 epo= data: "k3"/14.000000000,0 -> /BYTES/v4 data: "k4"/15.000000000,0 -> /BYTES/v5 data: "k5"/17.000000000,0 -> /BYTES/v6 -lock (Replicated): "k2"/Intent -> txn={id=00000002 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=13.000000000,0 min=0,0 seq=0} ts=13.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true -lock (Replicated): "k3"/Intent -> txn={id=00000003 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=14.000000000,0 min=0,0 seq=0} ts=14.000000000,0 del=false klen=12 vlen=7 mergeTs= txnDidNotUpdateMeta=true lock (Unreplicated): k4/Exclusive -> id=00000005 key=/Min iso=Serializable pri=0.00000000 epo=0 ts=16.000000000,0 min=0,0 seq=0 # Test cases: