github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/rangefeed/resolved_timestamp_test.go (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package rangefeed
    12  
    13  import (
    14  	"testing"
    15  
    16  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    17  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    18  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    19  	"github.com/cockroachdb/cockroach/pkg/util/uuid"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  func TestUnresolvedIntentQueue(t *testing.T) {
    24  	defer leaktest.AfterTest(t)()
    25  	uiq := makeUnresolvedIntentQueue()
    26  
    27  	// Test empty queue.
    28  	require.Equal(t, 0, uiq.Len())
    29  	require.Nil(t, uiq.Oldest())
    30  	require.Nil(t, uiq.Before(hlc.MinTimestamp))
    31  	require.Nil(t, uiq.Before(hlc.MaxTimestamp))
    32  
    33  	// Increment a non-existent txn.
    34  	txn1 := uuid.MakeV4()
    35  	txn1Key := roachpb.Key("key1")
    36  	txn1TS := hlc.Timestamp{WallTime: 1}
    37  	txn1MinTS := hlc.Timestamp{WallTime: 0, Logical: 4}
    38  	adv := uiq.IncRef(txn1, txn1Key, txn1MinTS, txn1TS)
    39  	require.False(t, adv)
    40  	require.Equal(t, 1, uiq.Len())
    41  	require.Equal(t, txn1, uiq.Oldest().txnID)
    42  	require.Equal(t, txn1Key, uiq.Oldest().txnKey)
    43  	require.Equal(t, txn1MinTS, uiq.Oldest().txnMinTimestamp)
    44  	require.Equal(t, txn1TS, uiq.Oldest().timestamp)
    45  	require.Equal(t, 1, uiq.Oldest().refCount)
    46  	require.Equal(t, 0, len(uiq.Before(hlc.Timestamp{WallTime: 0})))
    47  	require.Equal(t, 0, len(uiq.Before(hlc.Timestamp{WallTime: 1})))
    48  	require.Equal(t, 1, len(uiq.Before(hlc.Timestamp{WallTime: 2})))
    49  	require.NotPanics(t, func() { uiq.assertOnlyPositiveRefCounts() })
    50  
    51  	// Decrement a non-existent txn.
    52  	txn2 := uuid.MakeV4()
    53  	txn2TS := hlc.Timestamp{WallTime: 3}
    54  	adv = uiq.DecrRef(txn2, txn2TS)
    55  	require.False(t, adv)
    56  	require.Equal(t, 2, uiq.Len())
    57  	require.Equal(t, txn1, uiq.Oldest().txnID)
    58  	require.Equal(t, 0, len(uiq.Before(hlc.Timestamp{WallTime: 1})))
    59  	require.Equal(t, 1, len(uiq.Before(hlc.Timestamp{WallTime: 3})))
    60  	require.Equal(t, 2, len(uiq.Before(hlc.Timestamp{WallTime: 5})))
    61  	require.Panics(t, func() { uiq.assertOnlyPositiveRefCounts() })
    62  
    63  	// Update a non-existent txn.
    64  	txn3 := uuid.MakeV4()
    65  	adv = uiq.UpdateTS(txn3, hlc.Timestamp{WallTime: 5})
    66  	require.False(t, adv)
    67  	require.Equal(t, 2, uiq.Len())
    68  
    69  	// Delete a non-existent txn.
    70  	txn4 := uuid.MakeV4()
    71  	adv = uiq.Del(txn4)
    72  	require.False(t, adv)
    73  	require.Equal(t, 2, uiq.Len())
    74  
    75  	// Update txn1 with a smaller timestamp.
    76  	adv = uiq.UpdateTS(txn1, hlc.Timestamp{WallTime: 0})
    77  	require.False(t, adv)
    78  	require.Equal(t, 2, uiq.Len())
    79  	require.Equal(t, txn1, uiq.Oldest().txnID)
    80  	require.Equal(t, txn1TS, uiq.Oldest().timestamp)
    81  
    82  	// Update txn1 with an equal timestamp.
    83  	adv = uiq.UpdateTS(txn1, hlc.Timestamp{WallTime: 1})
    84  	require.False(t, adv)
    85  	require.Equal(t, 2, uiq.Len())
    86  	require.Equal(t, txn1, uiq.Oldest().txnID)
    87  	require.Equal(t, txn1TS, uiq.Oldest().timestamp)
    88  
    89  	// Update txn1 with a larger timestamp. Should advance.
    90  	newTxn1TS := hlc.Timestamp{WallTime: 2}
    91  	adv = uiq.UpdateTS(txn1, newTxn1TS)
    92  	require.True(t, adv)
    93  	require.Equal(t, 2, uiq.Len())
    94  	require.Equal(t, txn1, uiq.Oldest().txnID)
    95  	require.Equal(t, newTxn1TS, uiq.Oldest().timestamp)
    96  	require.Equal(t, 0, len(uiq.Before(hlc.Timestamp{WallTime: 2})))
    97  	require.Equal(t, 1, len(uiq.Before(hlc.Timestamp{WallTime: 3})))
    98  	require.Equal(t, 2, len(uiq.Before(hlc.Timestamp{WallTime: 4})))
    99  
   100  	// Update txn1 with a much larger timestamp. txn2 new oldest.
   101  	newTxn1TS = hlc.Timestamp{WallTime: 4}
   102  	adv = uiq.UpdateTS(txn1, newTxn1TS)
   103  	require.True(t, adv)
   104  	require.Equal(t, 2, uiq.Len())
   105  	require.Equal(t, txn2, uiq.Oldest().txnID)
   106  	require.Equal(t, txn2TS, uiq.Oldest().timestamp)
   107  	// Negative ref count ok. Indicates a re-ordering of events, which is
   108  	// expected during the catch up scan and supported by the queue.
   109  	require.Equal(t, -1, uiq.Oldest().refCount)
   110  	require.Equal(t, 0, len(uiq.Before(hlc.Timestamp{WallTime: 2})))
   111  	require.Equal(t, 0, len(uiq.Before(hlc.Timestamp{WallTime: 3})))
   112  	require.Equal(t, 1, len(uiq.Before(hlc.Timestamp{WallTime: 4})))
   113  	require.Equal(t, 2, len(uiq.Before(hlc.Timestamp{WallTime: 5})))
   114  
   115  	// Increase txn1's ref count while increasing timestamp.
   116  	newTxn1TS = hlc.Timestamp{WallTime: 5}
   117  	adv = uiq.IncRef(txn1, txn1Key, txn1MinTS, newTxn1TS)
   118  	require.False(t, adv)
   119  	require.Equal(t, 2, uiq.Len())
   120  	require.Equal(t, 2, uiq.txns[txn1].refCount)
   121  	require.Equal(t, newTxn1TS, uiq.txns[txn1].timestamp)
   122  
   123  	// Decrease txn1's ref count while increasing timestamp.
   124  	newTxn1TS = hlc.Timestamp{WallTime: 6}
   125  	adv = uiq.DecrRef(txn1, newTxn1TS)
   126  	require.False(t, adv)
   127  	require.Equal(t, 2, uiq.Len())
   128  	require.Equal(t, 1, uiq.txns[txn1].refCount)
   129  	require.Equal(t, newTxn1TS, uiq.txns[txn1].timestamp)
   130  
   131  	// Add new txn at much higher timestamp. Immediately delete.
   132  	txn5 := uuid.MakeV4()
   133  	txn5TS := hlc.Timestamp{WallTime: 10}
   134  	adv = uiq.IncRef(txn5, nil, txn5TS, txn5TS)
   135  	require.False(t, adv)
   136  	require.Equal(t, 3, uiq.Len())
   137  	require.Equal(t, txn2, uiq.Oldest().txnID)
   138  	adv = uiq.Del(txn5)
   139  	require.False(t, adv)
   140  	require.Equal(t, 2, uiq.Len())
   141  
   142  	// Increase txn2's ref count, which results in deletion. txn1 new oldest.
   143  	adv = uiq.IncRef(txn2, nil, txn2TS, txn2TS)
   144  	require.True(t, adv)
   145  	require.Equal(t, 1, uiq.Len())
   146  	require.Equal(t, txn1, uiq.Oldest().txnID)
   147  	require.Equal(t, newTxn1TS, uiq.Oldest().timestamp)
   148  	require.NotPanics(t, func() { uiq.assertOnlyPositiveRefCounts() })
   149  
   150  	// Decrease txn1's ref count. Should be empty again.
   151  	adv = uiq.DecrRef(txn1, hlc.Timestamp{})
   152  	require.True(t, adv)
   153  	require.Equal(t, 0, uiq.Len())
   154  
   155  	// Add new txn. Immediately decrement ref count. Should be empty again.
   156  	txn6 := uuid.MakeV4()
   157  	txn6TS := hlc.Timestamp{WallTime: 20}
   158  	adv = uiq.IncRef(txn6, nil, txn6TS, txn6TS)
   159  	require.False(t, adv)
   160  	require.Equal(t, 1, uiq.Len())
   161  	require.Equal(t, txn6, uiq.Oldest().txnID)
   162  	adv = uiq.DecrRef(txn6, hlc.Timestamp{})
   163  	require.True(t, adv)
   164  	require.Equal(t, 0, uiq.Len())
   165  
   166  	// Instruct the queue to disallow negative ref counts.
   167  	uiq.AllowNegRefCount(false)
   168  
   169  	// Decrease txn1's ref count. Should ignore because ref count
   170  	// would go negative.
   171  	adv = uiq.DecrRef(txn1, hlc.Timestamp{})
   172  	require.False(t, adv)
   173  	require.Equal(t, 0, uiq.Len())
   174  }
   175  
   176  func TestResolvedTimestamp(t *testing.T) {
   177  	defer leaktest.AfterTest(t)()
   178  	rts := makeResolvedTimestamp()
   179  	rts.Init()
   180  
   181  	// Test empty resolved timestamp.
   182  	require.Equal(t, hlc.Timestamp{}, rts.Get())
   183  
   184  	// Add an intent. No closed timestamp so no resolved timestamp.
   185  	txn1 := uuid.MakeV4()
   186  	fwd := rts.ConsumeLogicalOp(writeIntentOp(txn1, hlc.Timestamp{WallTime: 10}))
   187  	require.False(t, fwd)
   188  	require.Equal(t, hlc.Timestamp{}, rts.Get())
   189  
   190  	// Add another intent. No closed timestamp so no resolved timestamp.
   191  	txn2 := uuid.MakeV4()
   192  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn2, hlc.Timestamp{WallTime: 12}))
   193  	require.False(t, fwd)
   194  	require.Equal(t, hlc.Timestamp{}, rts.Get())
   195  
   196  	// Set a closed timestamp. Resolved timestamp advances.
   197  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 5})
   198  	require.True(t, fwd)
   199  	require.Equal(t, hlc.Timestamp{WallTime: 5}, rts.Get())
   200  
   201  	// Write intent at earlier timestamp. Assertion failure.
   202  	require.Panics(t, func() {
   203  		rts.ConsumeLogicalOp(writeIntentOp(uuid.MakeV4(), hlc.Timestamp{WallTime: 3}))
   204  	})
   205  
   206  	// Write value at earlier timestamp. Assertion failure.
   207  	require.Panics(t, func() {
   208  		rts.ConsumeLogicalOp(writeValueOp(hlc.Timestamp{WallTime: 4}))
   209  	})
   210  
   211  	// Write value at later timestamp. No effect on resolved timestamp.
   212  	fwd = rts.ConsumeLogicalOp(writeValueOp(hlc.Timestamp{WallTime: 6}))
   213  	require.False(t, fwd)
   214  	require.Equal(t, hlc.Timestamp{WallTime: 5}, rts.Get())
   215  
   216  	// Forward closed timestamp. Resolved timestamp advances to the timestamp of
   217  	// the earliest intent.
   218  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 15})
   219  	require.True(t, fwd)
   220  	require.Equal(t, hlc.Timestamp{WallTime: 9}, rts.Get())
   221  
   222  	// Update the timestamp of txn2. No effect on the resolved timestamp.
   223  	fwd = rts.ConsumeLogicalOp(updateIntentOp(txn2, hlc.Timestamp{WallTime: 18}))
   224  	require.False(t, fwd)
   225  	require.Equal(t, hlc.Timestamp{WallTime: 9}, rts.Get())
   226  
   227  	// Update the timestamp of txn1. Resolved timestamp moves forward.
   228  	fwd = rts.ConsumeLogicalOp(updateIntentOp(txn1, hlc.Timestamp{WallTime: 20}))
   229  	require.True(t, fwd)
   230  	require.Equal(t, hlc.Timestamp{WallTime: 15}, rts.Get())
   231  
   232  	// Forward closed timestamp to same time as earliest intent.
   233  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 18})
   234  	require.True(t, fwd)
   235  	require.Equal(t, hlc.Timestamp{WallTime: 17}, rts.Get())
   236  
   237  	// Write intent for earliest txn at same timestamp. No change.
   238  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn2, hlc.Timestamp{WallTime: 18}))
   239  	require.False(t, fwd)
   240  	require.Equal(t, hlc.Timestamp{WallTime: 17}, rts.Get())
   241  
   242  	// Write intent for earliest txn at later timestamp. Resolved
   243  	// timestamp moves forward.
   244  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn2, hlc.Timestamp{WallTime: 25}))
   245  	require.True(t, fwd)
   246  	require.Equal(t, hlc.Timestamp{WallTime: 18}, rts.Get())
   247  
   248  	// Forward closed timestamp. Resolved timestamp moves to earliest intent.
   249  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 30})
   250  	require.True(t, fwd)
   251  	require.Equal(t, hlc.Timestamp{WallTime: 19}, rts.Get())
   252  
   253  	// First transaction aborted. Resolved timestamp moves to next earliest
   254  	// intent.
   255  	fwd = rts.ConsumeLogicalOp(abortTxnOp(txn1))
   256  	require.True(t, fwd)
   257  	require.Equal(t, hlc.Timestamp{WallTime: 24}, rts.Get())
   258  	fwd = rts.ConsumeLogicalOp(abortIntentOp(txn1))
   259  	require.False(t, fwd)
   260  	require.Equal(t, hlc.Timestamp{WallTime: 24}, rts.Get())
   261  
   262  	// Third transaction at higher timestamp. No effect.
   263  	txn3 := uuid.MakeV4()
   264  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn3, hlc.Timestamp{WallTime: 30}))
   265  	require.False(t, fwd)
   266  	require.Equal(t, hlc.Timestamp{WallTime: 24}, rts.Get())
   267  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn3, hlc.Timestamp{WallTime: 31}))
   268  	require.False(t, fwd)
   269  	require.Equal(t, hlc.Timestamp{WallTime: 24}, rts.Get())
   270  
   271  	// Third transaction aborted. No effect.
   272  	fwd = rts.ConsumeLogicalOp(abortTxnOp(txn3))
   273  	require.False(t, fwd)
   274  	require.Equal(t, hlc.Timestamp{WallTime: 24}, rts.Get())
   275  	fwd = rts.ConsumeLogicalOp(abortIntentOp(txn3))
   276  	require.False(t, fwd)
   277  	require.Equal(t, hlc.Timestamp{WallTime: 24}, rts.Get())
   278  	fwd = rts.ConsumeLogicalOp(abortIntentOp(txn3))
   279  	require.False(t, fwd)
   280  	require.Equal(t, hlc.Timestamp{WallTime: 24}, rts.Get())
   281  
   282  	// Fourth transaction at higher timestamp. No effect.
   283  	txn4 := uuid.MakeV4()
   284  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn4, hlc.Timestamp{WallTime: 45}))
   285  	require.False(t, fwd)
   286  	require.Equal(t, hlc.Timestamp{WallTime: 24}, rts.Get())
   287  
   288  	// Fourth transaction committed. No effect.
   289  	fwd = rts.ConsumeLogicalOp(commitIntentOp(txn4, hlc.Timestamp{WallTime: 45}))
   290  	require.False(t, fwd)
   291  	require.Equal(t, hlc.Timestamp{WallTime: 24}, rts.Get())
   292  
   293  	// Second transaction observes one intent being resolved at timestamp
   294  	// above closed time. Resolved timestamp moves to closed timestamp.
   295  	fwd = rts.ConsumeLogicalOp(commitIntentOp(txn2, hlc.Timestamp{WallTime: 35}))
   296  	require.True(t, fwd)
   297  	require.Equal(t, hlc.Timestamp{WallTime: 30}, rts.Get())
   298  
   299  	// Forward closed timestamp. Resolved timestamp moves to earliest intent.
   300  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 40})
   301  	require.True(t, fwd)
   302  	require.Equal(t, hlc.Timestamp{WallTime: 34}, rts.Get())
   303  
   304  	// Second transaction observes another intent being resolved at timestamp
   305  	// below closed time. Still one intent left.
   306  	fwd = rts.ConsumeLogicalOp(commitIntentOp(txn2, hlc.Timestamp{WallTime: 35}))
   307  	require.False(t, fwd)
   308  	require.Equal(t, hlc.Timestamp{WallTime: 34}, rts.Get())
   309  
   310  	// Second transaction observes final intent being resolved at timestamp
   311  	// below closed time. Resolved timestamp moves to closed timestamp.
   312  	fwd = rts.ConsumeLogicalOp(commitIntentOp(txn2, hlc.Timestamp{WallTime: 35}))
   313  	require.True(t, fwd)
   314  	require.Equal(t, hlc.Timestamp{WallTime: 40}, rts.Get())
   315  
   316  	// Fifth transaction at higher timestamp. No effect.
   317  	txn5 := uuid.MakeV4()
   318  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn5, hlc.Timestamp{WallTime: 45}))
   319  	require.False(t, fwd)
   320  	require.Equal(t, hlc.Timestamp{WallTime: 40}, rts.Get())
   321  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn5, hlc.Timestamp{WallTime: 46}))
   322  	require.False(t, fwd)
   323  	require.Equal(t, hlc.Timestamp{WallTime: 40}, rts.Get())
   324  
   325  	// Forward closed timestamp. Resolved timestamp moves to earliest intent.
   326  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 50})
   327  	require.True(t, fwd)
   328  	require.Equal(t, hlc.Timestamp{WallTime: 45}, rts.Get())
   329  
   330  	// Fifth transaction bumps epoch and re-writes one of its intents. Resolved
   331  	// timestamp moves to the new transaction timestamp.
   332  	fwd = rts.ConsumeLogicalOp(updateIntentOp(txn5, hlc.Timestamp{WallTime: 47}))
   333  	require.True(t, fwd)
   334  	require.Equal(t, hlc.Timestamp{WallTime: 46}, rts.Get())
   335  
   336  	// Fifth transaction committed, but only one of its intents was written in
   337  	// its final epoch. Resolved timestamp moves forward after observing the
   338  	// first intent committing at a higher timestamp and moves to the closed
   339  	// timestamp after observing the second intent aborting.
   340  	fwd = rts.ConsumeLogicalOp(commitIntentOp(txn5, hlc.Timestamp{WallTime: 49}))
   341  	require.True(t, fwd)
   342  	require.Equal(t, hlc.Timestamp{WallTime: 48}, rts.Get())
   343  	fwd = rts.ConsumeLogicalOp(abortIntentOp(txn5))
   344  	require.True(t, fwd)
   345  	require.Equal(t, hlc.Timestamp{WallTime: 50}, rts.Get())
   346  }
   347  
   348  func TestResolvedTimestampNoClosedTimestamp(t *testing.T) {
   349  	defer leaktest.AfterTest(t)()
   350  	rts := makeResolvedTimestamp()
   351  	rts.Init()
   352  
   353  	// Add a value. No closed timestamp so no resolved timestamp.
   354  	fwd := rts.ConsumeLogicalOp(writeValueOp(hlc.Timestamp{WallTime: 1}))
   355  	require.False(t, fwd)
   356  	require.Equal(t, hlc.Timestamp{}, rts.Get())
   357  
   358  	// Add an intent. No closed timestamp so no resolved timestamp.
   359  	txn1 := uuid.MakeV4()
   360  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn1, hlc.Timestamp{WallTime: 1}))
   361  	require.False(t, fwd)
   362  	require.Equal(t, hlc.Timestamp{}, rts.Get())
   363  
   364  	// Update intent. No closed timestamp so no resolved timestamp.
   365  	fwd = rts.ConsumeLogicalOp(updateIntentOp(txn1, hlc.Timestamp{WallTime: 2}))
   366  	require.False(t, fwd)
   367  	require.Equal(t, hlc.Timestamp{}, rts.Get())
   368  
   369  	// Add another intent. No closed timestamp so no resolved timestamp.
   370  	txn2 := uuid.MakeV4()
   371  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn2, hlc.Timestamp{WallTime: 3}))
   372  	require.False(t, fwd)
   373  	require.Equal(t, hlc.Timestamp{}, rts.Get())
   374  
   375  	// Abort the first intent. No closed timestamp so no resolved timestamp.
   376  	fwd = rts.ConsumeLogicalOp(abortIntentOp(txn1))
   377  	require.False(t, fwd)
   378  	require.Equal(t, hlc.Timestamp{}, rts.Get())
   379  
   380  	// Commit the second intent. No closed timestamp so no resolved timestamp.
   381  	fwd = rts.ConsumeLogicalOp(commitIntentOp(txn2, hlc.Timestamp{WallTime: 3}))
   382  	require.False(t, fwd)
   383  	require.Equal(t, hlc.Timestamp{}, rts.Get())
   384  }
   385  
   386  func TestResolvedTimestampNoIntents(t *testing.T) {
   387  	defer leaktest.AfterTest(t)()
   388  	rts := makeResolvedTimestamp()
   389  	rts.Init()
   390  
   391  	// Set a closed timestamp. Resolved timestamp advances.
   392  	fwd := rts.ForwardClosedTS(hlc.Timestamp{WallTime: 1})
   393  	require.True(t, fwd)
   394  	require.Equal(t, hlc.Timestamp{WallTime: 1}, rts.Get())
   395  
   396  	// Forward closed timestamp. Resolved timestamp advances.
   397  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 3})
   398  	require.True(t, fwd)
   399  	require.Equal(t, hlc.Timestamp{WallTime: 3}, rts.Get())
   400  
   401  	// Smaller closed timestamp. Resolved timestamp does not advance.
   402  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 2})
   403  	require.False(t, fwd)
   404  	require.Equal(t, hlc.Timestamp{WallTime: 3}, rts.Get())
   405  
   406  	// Equal closed timestamp. Resolved timestamp does not advance.
   407  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 3})
   408  	require.False(t, fwd)
   409  	require.Equal(t, hlc.Timestamp{WallTime: 3}, rts.Get())
   410  
   411  	// Forward closed timestamp. Resolved timestamp advances.
   412  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 4})
   413  	require.True(t, fwd)
   414  	require.Equal(t, hlc.Timestamp{WallTime: 4}, rts.Get())
   415  }
   416  
   417  func TestResolvedTimestampInit(t *testing.T) {
   418  	defer leaktest.AfterTest(t)()
   419  
   420  	t.Run("CT Before Init", func(t *testing.T) {
   421  		rts := makeResolvedTimestamp()
   422  
   423  		// Set a closed timestamp. Not initialized so no resolved timestamp.
   424  		fwd := rts.ForwardClosedTS(hlc.Timestamp{WallTime: 5})
   425  		require.False(t, fwd)
   426  		require.Equal(t, hlc.Timestamp{}, rts.Get())
   427  
   428  		// Init. Resolved timestamp moves to closed timestamp.
   429  		fwd = rts.Init()
   430  		require.True(t, fwd)
   431  		require.Equal(t, hlc.Timestamp{WallTime: 5}, rts.Get())
   432  	})
   433  	t.Run("No CT Before Init", func(t *testing.T) {
   434  		rts := makeResolvedTimestamp()
   435  
   436  		// Add an intent. Not initialized so no resolved timestamp.
   437  		txn1 := uuid.MakeV4()
   438  		fwd := rts.ConsumeLogicalOp(writeIntentOp(txn1, hlc.Timestamp{WallTime: 3}))
   439  		require.False(t, fwd)
   440  		require.Equal(t, hlc.Timestamp{}, rts.Get())
   441  
   442  		// Init. Resolved timestamp undefined.
   443  		fwd = rts.Init()
   444  		require.False(t, fwd)
   445  		require.Equal(t, hlc.Timestamp{}, rts.Get())
   446  	})
   447  	t.Run("Write Before Init", func(t *testing.T) {
   448  		rts := makeResolvedTimestamp()
   449  
   450  		// Add an intent. Not initialized so no resolved timestamp.
   451  		txn1 := uuid.MakeV4()
   452  		fwd := rts.ConsumeLogicalOp(writeIntentOp(txn1, hlc.Timestamp{WallTime: 3}))
   453  		require.False(t, fwd)
   454  		require.Equal(t, hlc.Timestamp{}, rts.Get())
   455  
   456  		// Set a closed timestamp. Not initialized so no resolved timestamp.
   457  		fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 5})
   458  		require.False(t, fwd)
   459  		require.Equal(t, hlc.Timestamp{}, rts.Get())
   460  
   461  		// Init. Resolved timestamp moves below first unresolved intent.
   462  		fwd = rts.Init()
   463  		require.True(t, fwd)
   464  		require.Equal(t, hlc.Timestamp{WallTime: 2}, rts.Get())
   465  	})
   466  	t.Run("Abort + Write Before Init", func(t *testing.T) {
   467  		rts := makeResolvedTimestamp()
   468  
   469  		// Abort an intent. Not initialized so no resolved timestamp.
   470  		txn1 := uuid.MakeV4()
   471  		fwd := rts.ConsumeLogicalOp(abortIntentOp(txn1))
   472  		require.False(t, fwd)
   473  		require.Equal(t, hlc.Timestamp{}, rts.Get())
   474  
   475  		// Abort that intent's transaction. Not initialized so no-op.
   476  		fwd = rts.ConsumeLogicalOp(abortTxnOp(txn1))
   477  		require.False(t, fwd)
   478  		require.Equal(t, hlc.Timestamp{}, rts.Get())
   479  
   480  		// Later, write an intent for the same transaction. This should cancel
   481  		// out with the out-of-order intent abort operation. If this abort hadn't
   482  		// allowed the unresolvedTxn's ref count to drop below 0, this would
   483  		// have created a reference that would never be cleaned up.
   484  		fwd = rts.ConsumeLogicalOp(writeIntentOp(txn1, hlc.Timestamp{WallTime: 3}))
   485  		require.False(t, fwd)
   486  		require.Equal(t, hlc.Timestamp{}, rts.Get())
   487  
   488  		// Set a closed timestamp. Not initialized so no resolved timestamp.
   489  		fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 5})
   490  		require.False(t, fwd)
   491  		require.Equal(t, hlc.Timestamp{}, rts.Get())
   492  
   493  		// Init. Resolved timestamp moves to closed timestamp.
   494  		fwd = rts.Init()
   495  		require.True(t, fwd)
   496  		require.Equal(t, hlc.Timestamp{WallTime: 5}, rts.Get())
   497  	})
   498  	t.Run("Abort Before Init, No Write", func(t *testing.T) {
   499  		rts := makeResolvedTimestamp()
   500  
   501  		// Abort an intent. Not initialized so no resolved timestamp.
   502  		txn1 := uuid.MakeV4()
   503  		fwd := rts.ConsumeLogicalOp(abortIntentOp(txn1))
   504  		require.False(t, fwd)
   505  		require.Equal(t, hlc.Timestamp{}, rts.Get())
   506  
   507  		// Init. Negative txn ref count causes panic. Init should not have
   508  		// been called because an intent must not have been accounted for.
   509  		require.Panics(t, func() { rts.Init() })
   510  	})
   511  }
   512  
   513  func TestResolvedTimestampTxnAborted(t *testing.T) {
   514  	defer leaktest.AfterTest(t)()
   515  	rts := makeResolvedTimestamp()
   516  	rts.Init()
   517  
   518  	// Set a closed timestamp. Resolved timestamp advances.
   519  	fwd := rts.ForwardClosedTS(hlc.Timestamp{WallTime: 5})
   520  	require.True(t, fwd)
   521  	require.Equal(t, hlc.Timestamp{WallTime: 5}, rts.Get())
   522  
   523  	// Add an intent for a new transaction.
   524  	txn1 := uuid.MakeV4()
   525  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn1, hlc.Timestamp{WallTime: 10}))
   526  	require.False(t, fwd)
   527  	require.Equal(t, hlc.Timestamp{WallTime: 5}, rts.Get())
   528  
   529  	// Set a new closed timestamp. Resolved timestamp advances.
   530  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 15})
   531  	require.True(t, fwd)
   532  	require.Equal(t, hlc.Timestamp{WallTime: 9}, rts.Get())
   533  
   534  	// Abort txn1 after a periodic txn push. Resolved timestamp advances.
   535  	fwd = rts.ConsumeLogicalOp(abortTxnOp(txn1))
   536  	require.True(t, fwd)
   537  	require.Equal(t, hlc.Timestamp{WallTime: 15}, rts.Get())
   538  
   539  	// Update one of txn1's intents. Should be ignored.
   540  	fwd = rts.ConsumeLogicalOp(updateIntentOp(txn1, hlc.Timestamp{WallTime: 20}))
   541  	require.False(t, fwd)
   542  	require.Equal(t, hlc.Timestamp{WallTime: 15}, rts.Get())
   543  
   544  	// Abort one of txn1's intents. Should be ignored.
   545  	fwd = rts.ConsumeLogicalOp(abortIntentOp(txn1))
   546  	require.False(t, fwd)
   547  	require.Equal(t, hlc.Timestamp{WallTime: 15}, rts.Get())
   548  
   549  	// Write another intent as txn1. Should add txn1 back into queue.
   550  	// This will eventually require another txn push to evict.
   551  	fwd = rts.ConsumeLogicalOp(writeIntentOp(txn1, hlc.Timestamp{WallTime: 20}))
   552  	require.False(t, fwd)
   553  	require.Equal(t, hlc.Timestamp{WallTime: 15}, rts.Get())
   554  
   555  	// Set a new closed timestamp. Resolved timestamp advances, but only up to
   556  	// the timestamp of txn1's intent, which we fail remember is uncommittable.
   557  	fwd = rts.ForwardClosedTS(hlc.Timestamp{WallTime: 25})
   558  	require.True(t, fwd)
   559  	require.Equal(t, hlc.Timestamp{WallTime: 19}, rts.Get())
   560  
   561  	// Abort txn1 again after another periodic push. Resolved timestamp advances.
   562  	fwd = rts.ConsumeLogicalOp(abortTxnOp(txn1))
   563  	require.True(t, fwd)
   564  	require.Equal(t, hlc.Timestamp{WallTime: 25}, rts.Get())
   565  }