github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/tscache/cache_test.go (about) 1 // Copyright 2017 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 tscache 12 13 import ( 14 "bytes" 15 "context" 16 "fmt" 17 "math/rand" 18 "reflect" 19 "runtime" 20 "testing" 21 "time" 22 23 "github.com/cockroachdb/cockroach/pkg/roachpb" 24 "github.com/cockroachdb/cockroach/pkg/testutils" 25 "github.com/cockroachdb/cockroach/pkg/util" 26 "github.com/cockroachdb/cockroach/pkg/util/hlc" 27 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 28 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 29 "github.com/cockroachdb/cockroach/pkg/util/uuid" 30 "github.com/cockroachdb/errors" 31 "golang.org/x/sync/errgroup" 32 ) 33 34 var cacheImplConstrs = []func(clock *hlc.Clock) Cache{ 35 func(clock *hlc.Clock) Cache { return newTreeImpl(clock) }, 36 func(clock *hlc.Clock) Cache { return newSklImpl(clock) }, 37 } 38 39 func forEachCacheImpl( 40 t *testing.T, fn func(t *testing.T, tc Cache, clock *hlc.Clock, manual *hlc.ManualClock), 41 ) { 42 for _, constr := range cacheImplConstrs { 43 const baseTS = 100 44 manual := hlc.NewManualClock(baseTS) 45 clock := hlc.NewClock(manual.UnixNano, time.Nanosecond) 46 47 tc := constr(clock) 48 tcName := reflect.TypeOf(tc).Elem().Name() 49 t.Run(tcName, func(t *testing.T) { 50 fn(t, tc, clock, manual) 51 }) 52 } 53 } 54 55 func TestTimestampCache(t *testing.T) { 56 defer leaktest.AfterTest(t)() 57 58 forEachCacheImpl(t, func(t *testing.T, tc Cache, clock *hlc.Clock, manual *hlc.ManualClock) { 59 baseTS := manual.UnixNano() 60 61 // First simulate a read of just "a" at time 50. 62 tc.Add(roachpb.Key("a"), nil, hlc.Timestamp{WallTime: 50}, noTxnID) 63 // Verify GetMax returns the lowWater mark. 64 if rTS, rTxnID := tc.GetMax(roachpb.Key("a"), nil); rTS.WallTime != baseTS || rTxnID != noTxnID { 65 t.Errorf("expected baseTS for key \"a\"; txnID=%s", rTxnID) 66 } 67 if rTS, rTxnID := tc.GetMax(roachpb.Key("notincache"), nil); rTS.WallTime != baseTS || rTxnID != noTxnID { 68 t.Errorf("expected baseTS for key \"notincache\"; txnID=%s", rTxnID) 69 } 70 71 // Advance the clock and verify same low water mark. 72 manual.Increment(100) 73 if rTS, rTxnID := tc.GetMax(roachpb.Key("a"), nil); rTS.WallTime != baseTS || rTxnID != noTxnID { 74 t.Errorf("expected baseTS for key \"a\"; txnID=%s", rTxnID) 75 } 76 if rTS, rTxnID := tc.GetMax(roachpb.Key("notincache"), nil); rTS.WallTime != baseTS || rTxnID != noTxnID { 77 t.Errorf("expected baseTS for key \"notincache\"; txnID=%s", rTxnID) 78 } 79 80 // Sim a read of "b"-"c" at a time above the low-water mark. 81 ts := clock.Now() 82 tc.Add(roachpb.Key("b"), roachpb.Key("c"), ts, noTxnID) 83 84 // Verify all permutations of direct and range access. 85 if rTS, rTxnID := tc.GetMax(roachpb.Key("b"), nil); rTS != ts || rTxnID != noTxnID { 86 t.Errorf("expected current time for key \"b\"; got %s; txnID=%s", rTS, rTxnID) 87 } 88 if rTS, rTxnID := tc.GetMax(roachpb.Key("bb"), nil); rTS != ts || rTxnID != noTxnID { 89 t.Errorf("expected current time for key \"bb\"; txnID=%s", rTxnID) 90 } 91 if rTS, rTxnID := tc.GetMax(roachpb.Key("c"), nil); rTS.WallTime != baseTS || rTxnID != noTxnID { 92 t.Errorf("expected baseTS for key \"c\"; txnID=%s", rTxnID) 93 } 94 if rTS, rTxnID := tc.GetMax(roachpb.Key("b"), roachpb.Key("c")); rTS != ts || rTxnID != noTxnID { 95 t.Errorf("expected current time for key \"b\"-\"c\"; txnID=%s", rTxnID) 96 } 97 if rTS, rTxnID := tc.GetMax(roachpb.Key("bb"), roachpb.Key("bz")); rTS != ts || rTxnID != noTxnID { 98 t.Errorf("expected current time for key \"bb\"-\"bz\"; txnID=%s", rTxnID) 99 } 100 if rTS, rTxnID := tc.GetMax(roachpb.Key("a"), roachpb.Key("b")); rTS.WallTime != baseTS || rTxnID != noTxnID { 101 t.Errorf("expected baseTS for key \"a\"-\"b\"; txnID=%s", rTxnID) 102 } 103 if rTS, rTxnID := tc.GetMax(roachpb.Key("a"), roachpb.Key("bb")); rTS != ts || rTxnID != noTxnID { 104 t.Errorf("expected current time for key \"a\"-\"bb\"; txnID=%s", rTxnID) 105 } 106 if rTS, rTxnID := tc.GetMax(roachpb.Key("a"), roachpb.Key("d")); rTS != ts || rTxnID != noTxnID { 107 t.Errorf("expected current time for key \"a\"-\"d\"; txnID=%s", rTxnID) 108 } 109 if rTS, rTxnID := tc.GetMax(roachpb.Key("bz"), roachpb.Key("c")); rTS != ts || rTxnID != noTxnID { 110 t.Errorf("expected current time for key \"bz\"-\"c\"; txnID=%s", rTxnID) 111 } 112 if rTS, rTxnID := tc.GetMax(roachpb.Key("bz"), roachpb.Key("d")); rTS != ts || rTxnID != noTxnID { 113 t.Errorf("expected current time for key \"bz\"-\"d\"; txnID=%s", rTxnID) 114 } 115 if rTS, rTxnID := tc.GetMax(roachpb.Key("c"), roachpb.Key("d")); rTS.WallTime != baseTS || rTxnID != noTxnID { 116 t.Errorf("expected baseTS for key \"c\"-\"d\"; txnID=%s", rTxnID) 117 } 118 }) 119 } 120 121 type txnState struct { 122 ts hlc.Timestamp 123 id uuid.UUID 124 } 125 126 type layeredIntervalTestCase struct { 127 spans []roachpb.Span 128 validator func(t *testing.T, tc Cache, txns []txnState) 129 } 130 131 // assertTS is a helper function for layeredIntervalTestCase 132 // validators. It queries the timestamp cache for the given keys and 133 // reports a test error if it doesn't match the given timestamp and 134 // transaction ID. 135 func assertTS( 136 t *testing.T, tc Cache, start, end roachpb.Key, expectedTS hlc.Timestamp, expectedTxnID uuid.UUID, 137 ) { 138 var keys string 139 if len(end) == 0 { 140 keys = fmt.Sprintf("%q", start) 141 } else { 142 keys = fmt.Sprintf("%q-%q", start, end) 143 } 144 ts, txnID := tc.GetMax(start, end) 145 if ts != expectedTS { 146 t.Errorf("expected %s to have timestamp %v, found %v", keys, expectedTS, ts) 147 } 148 if txnID != expectedTxnID { 149 t.Errorf("expected %s to have txn id %s, but found %s", keys, expectedTxnID.Short(), txnID.Short()) 150 } 151 } 152 153 // zeroIfSimul returns a zero UUID if this test involves multiple transactions 154 // with the same timestamp (i.e. the timestamps in txns are identical but the 155 // transaction ids are not), and the given txnID if they are not. This is 156 // because timestampCache.GetMax must not return a transaction ID when two 157 // different transactions have the same timestamp. 158 func zeroIfSimul(txns []txnState, txnID uuid.UUID) uuid.UUID { 159 if txns[0].ts == txns[1].ts && txns[0].id != txns[1].id { 160 return noTxnID 161 } 162 return txnID 163 } 164 165 // layeredIntervalTestCase1 tests the left partial overlap and old containing 166 // new cases for adding intervals to the interval cache when tested in order, 167 // and tests the cases' inverses when tested in reverse. 168 var layeredIntervalTestCase1 = layeredIntervalTestCase{ 169 spans: []roachpb.Span{ 170 // No overlap forwards. 171 // Right partial overlap backwards. 172 {Key: roachpb.Key("a"), EndKey: roachpb.Key("bb")}, 173 // Left partial overlap forwards. 174 // New contains old backwards. 175 {Key: roachpb.Key("b"), EndKey: roachpb.Key("e")}, 176 // Old contains new forwards. 177 // No overlap backwards. 178 {Key: roachpb.Key("c")}, 179 }, 180 validator: func(t *testing.T, tc Cache, txns []txnState) { 181 abbTx, beTx, cTx := txns[0], txns[1], txns[2] 182 183 assertTS(t, tc, roachpb.Key("a"), nil, abbTx.ts, abbTx.id) 184 assertTS(t, tc, roachpb.Key("b"), nil, beTx.ts, zeroIfSimul(txns, beTx.id)) 185 assertTS(t, tc, roachpb.Key("c"), nil, cTx.ts, zeroIfSimul(txns, cTx.id)) 186 assertTS(t, tc, roachpb.Key("d"), nil, beTx.ts, beTx.id) 187 assertTS(t, tc, roachpb.Key("a"), roachpb.Key("b"), abbTx.ts, abbTx.id) 188 assertTS(t, tc, roachpb.Key("a"), roachpb.Key("c"), beTx.ts, zeroIfSimul(txns, beTx.id)) 189 assertTS(t, tc, roachpb.Key("a"), roachpb.Key("d"), cTx.ts, zeroIfSimul(txns, cTx.id)) 190 assertTS(t, tc, roachpb.Key("b"), roachpb.Key("d"), cTx.ts, zeroIfSimul(txns, cTx.id)) 191 assertTS(t, tc, roachpb.Key("c"), roachpb.Key("d"), cTx.ts, zeroIfSimul(txns, cTx.id)) 192 assertTS(t, tc, roachpb.Key("c0"), roachpb.Key("d"), beTx.ts, beTx.id) 193 }, 194 } 195 196 // layeredIntervalTestCase2 tests the right partial overlap and new containing 197 // old cases for adding intervals to the interval cache when tested in order, 198 // and tests the cases' inverses when tested in reverse. 199 var layeredIntervalTestCase2 = layeredIntervalTestCase{ 200 spans: []roachpb.Span{ 201 // No overlap forwards. 202 // Old contains new backwards. 203 {Key: roachpb.Key("d"), EndKey: roachpb.Key("f")}, 204 // New contains old forwards. 205 // Left partial overlap backwards. 206 {Key: roachpb.Key("b"), EndKey: roachpb.Key("f")}, 207 // Right partial overlap forwards. 208 // No overlap backwards. 209 {Key: roachpb.Key("a"), EndKey: roachpb.Key("c")}, 210 }, 211 validator: func(t *testing.T, tc Cache, txns []txnState) { 212 _, bfTx, acTx := txns[0], txns[1], txns[2] 213 214 assertTS(t, tc, roachpb.Key("a"), nil, acTx.ts, acTx.id) 215 assertTS(t, tc, roachpb.Key("b"), nil, acTx.ts, zeroIfSimul(txns, acTx.id)) 216 assertTS(t, tc, roachpb.Key("c"), nil, bfTx.ts, bfTx.id) 217 assertTS(t, tc, roachpb.Key("d"), nil, bfTx.ts, zeroIfSimul(txns, bfTx.id)) 218 assertTS(t, tc, roachpb.Key("a"), roachpb.Key("c"), acTx.ts, zeroIfSimul(txns, acTx.id)) 219 assertTS(t, tc, roachpb.Key("b"), roachpb.Key("d"), acTx.ts, zeroIfSimul(txns, acTx.id)) 220 assertTS(t, tc, roachpb.Key("c"), roachpb.Key("d"), bfTx.ts, bfTx.id) 221 assertTS(t, tc, roachpb.Key("c0"), roachpb.Key("d"), bfTx.ts, bfTx.id) 222 }, 223 } 224 225 // layeredIntervalTestCase3 tests a right partial overlap with a shared end 226 // for adding intervals to the interval cache when tested in order, and 227 // tests a left partial overlap with a shared end when tested in reverse. 228 var layeredIntervalTestCase3 = layeredIntervalTestCase{ 229 spans: []roachpb.Span{ 230 // No overlap forwards. 231 // Right partial overlap backwards. 232 {Key: roachpb.Key("a"), EndKey: roachpb.Key("c")}, 233 // Left partial overlap forwards. 234 // No overlap backwards. 235 {Key: roachpb.Key("b"), EndKey: roachpb.Key("c")}, 236 }, 237 validator: func(t *testing.T, tc Cache, txns []txnState) { 238 acTx, bcTx := txns[0], txns[1] 239 240 assertTS(t, tc, roachpb.Key("a"), nil, acTx.ts, acTx.id) 241 assertTS(t, tc, roachpb.Key("b"), nil, bcTx.ts, zeroIfSimul(txns, bcTx.id)) 242 assertTS(t, tc, roachpb.Key("c"), nil, tc.getLowWater(), noTxnID) 243 assertTS(t, tc, roachpb.Key("a"), roachpb.Key("c"), bcTx.ts, zeroIfSimul(txns, bcTx.id)) 244 assertTS(t, tc, roachpb.Key("a"), roachpb.Key("b"), acTx.ts, acTx.id) 245 assertTS(t, tc, roachpb.Key("b"), roachpb.Key("c"), bcTx.ts, zeroIfSimul(txns, bcTx.id)) 246 }, 247 } 248 249 // layeredIntervalTestCase4 tests a left partial overlap with a shared start 250 // for adding intervals to the interval cache when tested in order, and 251 // tests a right partial overlap with a shared start when tested in reverse. 252 var layeredIntervalTestCase4 = layeredIntervalTestCase{ 253 spans: []roachpb.Span{ 254 // No overlap forwards. 255 // Left partial overlap backwards. 256 {Key: roachpb.Key("a"), EndKey: roachpb.Key("c")}, 257 // Right partial overlap forwards. 258 // No overlap backwards. 259 {Key: roachpb.Key("a"), EndKey: roachpb.Key("b")}, 260 }, 261 validator: func(t *testing.T, tc Cache, txns []txnState) { 262 acTx, abTx := txns[0], txns[1] 263 264 assertTS(t, tc, roachpb.Key("a"), nil, abTx.ts, zeroIfSimul(txns, abTx.id)) 265 assertTS(t, tc, roachpb.Key("b"), nil, acTx.ts, acTx.id) 266 assertTS(t, tc, roachpb.Key("c"), nil, tc.getLowWater(), noTxnID) 267 assertTS(t, tc, roachpb.Key("a"), roachpb.Key("c"), abTx.ts, zeroIfSimul(txns, abTx.id)) 268 assertTS(t, tc, roachpb.Key("a"), roachpb.Key("b"), abTx.ts, zeroIfSimul(txns, abTx.id)) 269 assertTS(t, tc, roachpb.Key("b"), roachpb.Key("c"), acTx.ts, acTx.id) 270 }, 271 } 272 273 var layeredIntervalTestCase5 = layeredIntervalTestCase{ 274 spans: []roachpb.Span{ 275 // Two identical spans 276 {Key: roachpb.Key("a"), EndKey: roachpb.Key("b")}, 277 {Key: roachpb.Key("a"), EndKey: roachpb.Key("b")}, 278 }, 279 validator: func(t *testing.T, tc Cache, txns []txnState) { 280 assertTS(t, tc, roachpb.Key("a"), nil, txns[1].ts, zeroIfSimul(txns, txns[1].id)) 281 }, 282 } 283 284 // TestTimestampCacheLayeredIntervals verifies the maximum timestamp 285 // is chosen if previous entries have ranges which are layered over 286 // each other. 287 // 288 // The test uses the layeredIntervalTestCase struct to allow reordering 289 // of interval insertions while keeping each interval's timestamp fixed. 290 // This can be used to verify that only the provided timestamp is used to 291 // determine layering, and that the interval insertion order is irrelevant. 292 func TestTimestampCacheLayeredIntervals(t *testing.T) { 293 defer leaktest.AfterTest(t)() 294 295 forEachCacheImpl(t, func(t *testing.T, tc Cache, clock *hlc.Clock, manual *hlc.ManualClock) { 296 // Run each test case in several configurations. 297 for _, testCase := range []layeredIntervalTestCase{ 298 layeredIntervalTestCase1, 299 layeredIntervalTestCase2, 300 layeredIntervalTestCase3, 301 layeredIntervalTestCase4, 302 layeredIntervalTestCase5, 303 } { 304 t.Run("", func(t *testing.T) { 305 // In simultaneous runs, each span in the test case is given the same 306 // time. Otherwise each gets a distinct timestamp (in the order of 307 // definition). 308 testutils.RunTrueAndFalse(t, "simultaneous", func(t *testing.T, simultaneous bool) { 309 // In reverse runs, spans are inserted into the timestamp cache out 310 // of order (so spans with higher timestamps are inserted before 311 // those with lower timestamps). In simultaneous+reverse runs, 312 // timestamps are all the same, but running in both directions is 313 // still necessary to exercise all branches in the code. 314 testutils.RunTrueAndFalse(t, "reverse", func(t *testing.T, reverse bool) { 315 // In sameTxn runs, all spans are inserted as a part of the same 316 // transaction; otherwise each is a separate transaction. 317 testutils.RunTrueAndFalse(t, "sameTxn", func(t *testing.T, sameTxn bool) { 318 defer func() { 319 tc.clear(clock.Now()) 320 }() 321 322 txns := make([]txnState, len(testCase.spans)) 323 if sameTxn { 324 id := uuid.MakeV4() 325 for i := range testCase.spans { 326 txns[i].id = id 327 } 328 } else { 329 for i := range testCase.spans { 330 txns[i].id = uuid.MakeV4() 331 } 332 } 333 334 tc.clear(clock.Now()) 335 if simultaneous { 336 now := clock.Now() 337 for i := range txns { 338 txns[i].ts = now 339 } 340 } else { 341 manual.Increment(1) 342 for i := range txns { 343 txns[i].ts = clock.Now() 344 } 345 } 346 347 if reverse { 348 for i := len(testCase.spans) - 1; i >= 0; i-- { 349 tc.Add(testCase.spans[i].Key, testCase.spans[i].EndKey, txns[i].ts, txns[i].id) 350 } 351 } else { 352 for i := range testCase.spans { 353 tc.Add(testCase.spans[i].Key, testCase.spans[i].EndKey, txns[i].ts, txns[i].id) 354 } 355 } 356 testCase.validator(t, tc, txns) 357 }) 358 }) 359 }) 360 }) 361 } 362 }) 363 } 364 365 func TestTimestampCacheClear(t *testing.T) { 366 defer leaktest.AfterTest(t)() 367 368 forEachCacheImpl(t, func(t *testing.T, tc Cache, clock *hlc.Clock, manual *hlc.ManualClock) { 369 key := roachpb.Key("a") 370 371 ts := clock.Now() 372 tc.Add(key, nil, ts, noTxnID) 373 374 manual.Increment(5000000) 375 376 expTS := clock.Now() 377 // Clear the cache, which will reset the low water mark to 378 // the current time. 379 tc.clear(expTS) 380 381 // Fetching any keys should give current time. 382 if rTS, rTxnID := tc.GetMax(key, nil); rTxnID != noTxnID { 383 t.Errorf("%s unexpectedly associated to txn %s", key, rTxnID) 384 } else if rTS != expTS { 385 t.Errorf("expected %s, got %s", rTS, expTS) 386 } 387 }) 388 } 389 390 // TestTimestampCacheEqualTimestamp verifies that in the event of two 391 // non-overlapping transactions with equal timestamps, the returned 392 // timestamp is not owned by either one. 393 func TestTimestampCacheEqualTimestamps(t *testing.T) { 394 defer leaktest.AfterTest(t)() 395 396 forEachCacheImpl(t, func(t *testing.T, tc Cache, clock *hlc.Clock, manual *hlc.ManualClock) { 397 txn1 := uuid.MakeV4() 398 txn2 := uuid.MakeV4() 399 400 // Add two non-overlapping transactions at the same timestamp. 401 ts1 := clock.Now() 402 tc.Add(roachpb.Key("a"), roachpb.Key("b"), ts1, txn1) 403 tc.Add(roachpb.Key("b"), roachpb.Key("c"), ts1, txn2) 404 405 // When querying either side separately, the transaction ID is returned. 406 if ts, txn := tc.GetMax(roachpb.Key("a"), roachpb.Key("b")); ts != ts1 { 407 t.Errorf("expected 'a'-'b' to have timestamp %s, but found %s", ts1, ts) 408 } else if txn != txn1 { 409 t.Errorf("expected 'a'-'b' to have txn id %s, but found %s", txn1, txn) 410 } 411 if ts, txn := tc.GetMax(roachpb.Key("b"), roachpb.Key("c")); ts != ts1 { 412 t.Errorf("expected 'b'-'c' to have timestamp %s, but found %s", ts1, ts) 413 } else if txn != txn2 { 414 t.Errorf("expected 'b'-'c' to have txn id %s, but found %s", txn2, txn) 415 } 416 417 // Querying a span that overlaps both returns a nil txn ID; neither 418 // can proceed here. 419 if ts, txn := tc.GetMax(roachpb.Key("a"), roachpb.Key("c")); ts != ts1 { 420 t.Errorf("expected 'a'-'c' to have timestamp %s, but found %s", ts1, ts) 421 } else if txn != (noTxnID) { 422 t.Errorf("expected 'a'-'c' to have zero txn id, but found %s", txn) 423 } 424 }) 425 } 426 427 // TestTimestampCacheLargeKeys verifies that the timestamp cache implementations 428 // can support arbitrarily large keys lengths. This is important because we don't 429 // place a hard limit on this anywhere else. 430 func TestTimestampCacheLargeKeys(t *testing.T) { 431 defer leaktest.AfterTest(t)() 432 433 forEachCacheImpl(t, func(t *testing.T, tc Cache, clock *hlc.Clock, manual *hlc.ManualClock) { 434 keyStart := roachpb.Key(make([]byte, 5*maximumSklPageSize)) 435 keyEnd := keyStart.Next() 436 ts1 := clock.Now() 437 txn1 := uuid.MakeV4() 438 439 tc.Add(keyStart, keyEnd, ts1, txn1) 440 if ts, txn := tc.GetMax(keyStart, keyEnd); ts != ts1 { 441 t.Errorf("expected key range to have timestamp %s, but found %s", ts1, ts) 442 } else if txn != txn1 { 443 t.Errorf("expected key range to have txn id %s, but found %s", txn1, txn) 444 } 445 }) 446 } 447 448 // TestTimestampCacheImplsIdentical verifies that all timestamp cache 449 // implementations return the same results for the same inputs, even under 450 // concurrent load. 451 func TestTimestampCacheImplsIdentical(t *testing.T) { 452 defer leaktest.AfterTest(t)() 453 defer util.EnableRacePreemptionPoints()() 454 455 // Run one subtest using a real clock to generate timestamps and one subtest 456 // using a fake clock to generate timestamps. The former is good for 457 // simulating real conditions while the latter is good for testing timestamp 458 // collisions. 459 testutils.RunTrueAndFalse(t, "useClock", func(t *testing.T, useClock bool) { 460 clock := hlc.NewClock(hlc.UnixNano, time.Nanosecond) 461 caches := make([]Cache, len(cacheImplConstrs)) 462 start := clock.Now() 463 for i, constr := range cacheImplConstrs { 464 tc := constr(clock) 465 tc.clear(start) // set low water mark 466 caches[i] = tc 467 } 468 469 // Context cancellations are used to shutdown goroutines and prevent 470 // deadlocks once any test failures are found. errgroup.WithContext will 471 // cancel the context either when any goroutine returns an error or when 472 // all goroutines finish and Wait returns. 473 doneWG, ctx := errgroup.WithContext(context.Background()) 474 475 // We run a goroutine for each slot. Goroutines insert new value over 476 // random intervals, but verify that the value in their slot always 477 // ratchets. 478 slots := 4 * runtime.NumCPU() 479 if util.RaceEnabled { 480 // We add in a lot of preemption points when race detection 481 // is enabled, so things will already be very slow. Reduce 482 // the concurrency to that we don't time out. 483 slots /= 2 484 } 485 486 // semC and retC force all goroutines to work in lockstep, first adding 487 // intervals to all caches together, then reading from all caches 488 // together. 489 semC, retC := make(chan struct{}), make(chan struct{}) 490 go func() { 491 populate := func() { 492 for i := 0; i < slots; i++ { 493 select { 494 case semC <- struct{}{}: 495 case <-ctx.Done(): 496 return 497 } 498 } 499 } 500 populate() 501 502 left := slots 503 for { 504 select { 505 case <-retC: 506 left-- 507 if left == 0 { 508 // Reset left count and populate. 509 left = slots 510 populate() 511 } 512 case <-ctx.Done(): 513 return 514 } 515 } 516 }() 517 518 for i := 0; i < slots; i++ { 519 i := i 520 doneWG.Go(func() error { 521 rng := rand.New(rand.NewSource(timeutil.Now().UnixNano())) 522 slotKey := []byte(fmt.Sprintf("%05d", i)) 523 txnID := uuid.MakeV4() 524 maxVal := cacheValue{} 525 526 rounds := 1000 527 if util.RaceEnabled { 528 // Reduce the number of rounds for race builds. 529 rounds /= 2 530 } 531 for j := 0; j < rounds; j++ { 532 // This is a lot of log output so only un-comment to debug. 533 // t.Logf("goroutine %d at iter %d", i, j) 534 535 // Wait for all goroutines to synchronize. 536 select { 537 case <-semC: 538 case <-ctx.Done(): 539 return nil 540 } 541 542 // Add the same random range to each cache. 543 from, middle, to := randRange(rng, slots+1) 544 if bytes.Equal(from, to) { 545 to = nil 546 } 547 548 ts := start.Add(int64(j), 100) 549 if useClock { 550 ts = clock.Now() 551 } 552 553 newVal := cacheValue{ts: ts, txnID: txnID} 554 for _, tc := range caches { 555 // This is a lot of log output so only un-comment to debug. 556 // t.Logf("adding (%T) [%s,%s) = %s", tc, string(from), string(to), newVal) 557 tc.Add(from, to, ts, txnID) 558 } 559 560 // Return semaphore. 561 select { 562 case retC <- struct{}{}: 563 case <-ctx.Done(): 564 return nil 565 } 566 567 // Wait for all goroutines to synchronize. 568 select { 569 case <-semC: 570 case <-ctx.Done(): 571 return nil 572 } 573 574 // Check the value for the newly added interval. Should be 575 // equal across all caches and be a ratcheted version of the 576 // interval added above. 577 var err error 578 if _, err = identicalAndRatcheted(caches, from, to, newVal); err != nil { 579 return errors.Wrapf(err, "interval=[%s,%s)", string(from), string(to)) 580 } 581 582 // Check the value for the start key of the newly added 583 // interval. Should be equal across all caches and be a 584 // ratcheted version of the interval added above. 585 if _, err = identicalAndRatcheted(caches, from, nil, newVal); err != nil { 586 return errors.Wrapf(err, "startKey=%s", string(from)) 587 } 588 589 // Check the value right after the start key of the newly 590 // added interval, if possible. Should be equal across all 591 // caches and be a ratcheted version of the interval added 592 // above. 593 if middle != nil { 594 if _, err = identicalAndRatcheted(caches, middle, nil, newVal); err != nil { 595 return errors.Wrapf(err, "middleKey=%s", string(middle)) 596 } 597 } 598 599 // Check the value for the goroutine's slot. Should be equal 600 // across all caches and be a ratcheted version of the 601 // maximum value we've seen in the slot. 602 if maxVal, err = identicalAndRatcheted(caches, slotKey, nil, maxVal); err != nil { 603 return errors.Wrapf(err, "slotKey=%s", string(slotKey)) 604 } 605 606 // Return semaphore. 607 select { 608 case retC <- struct{}{}: 609 case <-ctx.Done(): 610 return nil 611 } 612 } 613 return nil 614 }) 615 } 616 if err := doneWG.Wait(); err != nil { 617 t.Fatal(err) 618 } 619 }) 620 } 621 622 // identicalAndRatcheted asserts that all caches have identical values for the 623 // specified range and that the value is a ratcheted version of previous value. 624 // It returns an error if the assertion fails and the value found if it doesn't. 625 func identicalAndRatcheted( 626 caches []Cache, from, to roachpb.Key, prevVal cacheValue, 627 ) (cacheValue, error) { 628 var vals []cacheValue 629 for _, tc := range caches { 630 keyTS, keyTxnID := tc.GetMax(from, to) 631 vals = append(vals, cacheValue{ts: keyTS, txnID: keyTxnID}) 632 } 633 634 // Assert same values for each cache. 635 firstVal := vals[0] 636 firstCache := caches[0] 637 for i := 1; i < len(caches); i++ { 638 if !reflect.DeepEqual(firstVal, vals[i]) { 639 return firstVal, errors.Errorf("expected %s (%T) and %s (%T) to be equal", 640 firstVal, firstCache, vals[i], caches[i]) 641 } 642 } 643 644 // Assert that the value is a ratcheted version of prevVal. 645 // See assertRatchet. 646 if _, ratchet := ratchetValue(firstVal, prevVal); ratchet { 647 return firstVal, errors.Errorf("ratchet inversion from %s to %s", prevVal, firstVal) 648 } 649 650 return firstVal, nil 651 } 652 653 func BenchmarkTimestampCacheInsertion(b *testing.B) { 654 manual := hlc.NewManualClock(123) 655 clock := hlc.NewClock(manual.UnixNano, time.Nanosecond) 656 tc := New(clock) 657 658 for i := 0; i < b.N; i++ { 659 cdTS := clock.Now() 660 tc.Add(roachpb.Key("c"), roachpb.Key("d"), cdTS, noTxnID) 661 662 beTS := clock.Now() 663 tc.Add(roachpb.Key("b"), roachpb.Key("e"), beTS, noTxnID) 664 665 adTS := clock.Now() 666 tc.Add(roachpb.Key("a"), roachpb.Key("d"), adTS, noTxnID) 667 668 cfTS := clock.Now() 669 tc.Add(roachpb.Key("c"), roachpb.Key("f"), cfTS, noTxnID) 670 } 671 }