github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/replica_evaluate_test.go (about) 1 // Copyright 2020 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 kvserver 12 13 import ( 14 "context" 15 "fmt" 16 "testing" 17 18 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/abortspan" 19 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/batcheval" 20 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/batcheval/result" 21 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/concurrency/lock" 22 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverbase" 23 "github.com/cockroachdb/cockroach/pkg/roachpb" 24 "github.com/cockroachdb/cockroach/pkg/storage" 25 "github.com/cockroachdb/cockroach/pkg/storage/enginepb" 26 "github.com/cockroachdb/cockroach/pkg/util/hlc" 27 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 28 "github.com/stretchr/testify/require" 29 ) 30 31 func TestEvaluateBatch(t *testing.T) { 32 defer leaktest.AfterTest(t)() 33 34 ts := hlc.Timestamp{WallTime: 1} 35 txn := roachpb.MakeTransaction("test", roachpb.Key("a"), 0, ts, 0) 36 37 tcs := []testCase{ 38 // 39 // Test suite for MaxRequestSpans. 40 // 41 { 42 // We should never evaluate empty batches, but here's what would happen 43 // if we did. 44 name: "all empty", 45 setup: func(t *testing.T, d *data) {}, 46 check: func(t *testing.T, r resp) { 47 require.Nil(t, r.pErr) 48 require.NotNil(t, r.br) 49 require.Empty(t, r.br.Responses) 50 }, 51 }, { 52 // Scanning without limit should return everything. 53 name: "scan without MaxSpanRequestKeys", 54 setup: func(t *testing.T, d *data) { 55 writeABCDEF(t, d) 56 req := scanArgsString("a", "z") 57 d.ba.Add(req) 58 }, 59 check: func(t *testing.T, r resp) { 60 verifyScanResult(t, r, []string{"a", "b", "c", "d", "e", "f"}) 61 verifyResumeSpans(t, r, "") 62 }, 63 }, { 64 // Ditto in reverse. 65 name: "reverse scan without MaxSpanRequestKeys", 66 setup: func(t *testing.T, d *data) { 67 writeABCDEF(t, d) 68 req := revScanArgsString("a", "z") 69 d.ba.Add(req) 70 }, 71 check: func(t *testing.T, r resp) { 72 verifyScanResult(t, r, []string{"f", "e", "d", "c", "b", "a"}) 73 verifyResumeSpans(t, r, "") 74 }, 75 }, { 76 // Scanning with "giant" limit should return everything. 77 name: "scan with giant MaxSpanRequestKeys", 78 setup: func(t *testing.T, d *data) { 79 writeABCDEF(t, d) 80 req := scanArgsString("a", "z") 81 d.ba.Add(req) 82 d.ba.MaxSpanRequestKeys = 100000 83 }, 84 check: func(t *testing.T, r resp) { 85 verifyScanResult(t, r, []string{"a", "b", "c", "d", "e", "f"}) 86 verifyResumeSpans(t, r, "") 87 }, 88 }, { 89 // Ditto in reverse. 90 name: "reverse scan with giant MaxSpanRequestKeys", 91 setup: func(t *testing.T, d *data) { 92 writeABCDEF(t, d) 93 req := revScanArgsString("a", "z") 94 d.ba.Add(req) 95 d.ba.MaxSpanRequestKeys = 100000 96 }, 97 check: func(t *testing.T, r resp) { 98 verifyScanResult(t, r, []string{"f", "e", "d", "c", "b", "a"}) 99 verifyResumeSpans(t, r, "") 100 }, 101 }, { 102 // Similar to above, just two scans. 103 name: "scans with giant MaxSpanRequestKeys", 104 setup: func(t *testing.T, d *data) { 105 writeABCDEF(t, d) 106 d.ba.Add(scanArgsString("a", "c")) 107 d.ba.Add(scanArgsString("d", "g")) 108 d.ba.MaxSpanRequestKeys = 100000 109 }, 110 check: func(t *testing.T, r resp) { 111 verifyScanResult(t, r, []string{"a", "b"}, []string{"d", "e", "f"}) 112 verifyResumeSpans(t, r, "", "") 113 }, 114 }, { 115 // Ditto in reverse. 116 name: "reverse scans with giant MaxSpanRequestKeys", 117 setup: func(t *testing.T, d *data) { 118 writeABCDEF(t, d) 119 d.ba.Add(revScanArgsString("d", "g")) 120 d.ba.Add(revScanArgsString("a", "c")) 121 d.ba.MaxSpanRequestKeys = 100000 122 }, 123 check: func(t *testing.T, r resp) { 124 verifyScanResult(t, r, []string{"f", "e", "d"}, []string{"b", "a"}) 125 verifyResumeSpans(t, r, "", "") 126 }, 127 }, { 128 // A batch limited to return only one key. Throw in a Get which is 129 // not subject to limitation and should thus have returned a value. 130 // However, the second scan comes up empty because there's no quota left. 131 // 132 // Note that there is currently a lot of undesirable behavior in the KV 133 // API for pretty much any batch that's not a nonoverlapping sorted run 134 // of only scans or only reverse scans. For example, in the example 135 // below, one would get a response for get(f) even though the resume 136 // span on the first scan is `[c,...)`. The higher layers of KV don't 137 // handle that correctly. Right now we just trust that nobody will 138 // send such requests. 139 name: "scans with MaxSpanRequestKeys=1", 140 setup: func(t *testing.T, d *data) { 141 writeABCDEF(t, d) 142 d.ba.Add(scanArgsString("a", "c")) 143 d.ba.Add(getArgsString("f")) 144 d.ba.Add(scanArgsString("d", "f")) 145 d.ba.MaxSpanRequestKeys = 1 146 }, 147 check: func(t *testing.T, r resp) { 148 verifyScanResult(t, r, []string{"a"}, []string{"f"}, nil) 149 verifyResumeSpans(t, r, "b-c", "", "d-f") 150 b, err := r.br.Responses[1].GetGet().Value.GetBytes() 151 require.NoError(t, err) 152 require.Equal(t, "value-f", string(b)) 153 }, 154 }, { 155 // Ditto in reverse. 156 name: "reverse scans with MaxSpanRequestKeys=1", 157 setup: func(t *testing.T, d *data) { 158 writeABCDEF(t, d) 159 d.ba.Add(revScanArgsString("d", "f")) 160 d.ba.Add(getArgsString("f")) 161 d.ba.Add(revScanArgsString("a", "c")) 162 d.ba.MaxSpanRequestKeys = 1 163 }, 164 check: func(t *testing.T, r resp) { 165 verifyScanResult(t, r, []string{"e"}, []string{"f"}, nil) 166 verifyResumeSpans(t, r, "d-d\x00", "", "a-c") 167 b, err := r.br.Responses[1].GetGet().Value.GetBytes() 168 require.NoError(t, err) 169 require.Equal(t, "value-f", string(b)) 170 }, 171 }, { 172 // Similar, but this time the request allows the second scan to 173 // return one (but not more) remaining key. Again there's a Get 174 // that isn't counted against the limit. 175 name: "scans with MaxSpanRequestKeys=3", 176 setup: func(t *testing.T, d *data) { 177 writeABCDEF(t, d) 178 d.ba.Add(scanArgsString("a", "c")) 179 d.ba.Add(getArgsString("e")) 180 d.ba.Add(scanArgsString("c", "e")) 181 d.ba.MaxSpanRequestKeys = 3 182 }, 183 check: func(t *testing.T, r resp) { 184 verifyScanResult(t, r, []string{"a", "b"}, []string{"e"}, []string{"c"}) 185 verifyResumeSpans(t, r, "", "", "d-e") 186 b, err := r.br.Responses[1].GetGet().Value.GetBytes() 187 require.NoError(t, err) 188 require.Equal(t, "value-e", string(b)) 189 }, 190 }, { 191 // Ditto in reverse. 192 name: "reverse scans with MaxSpanRequestKeys=3", 193 setup: func(t *testing.T, d *data) { 194 writeABCDEF(t, d) 195 d.ba.Add(revScanArgsString("c", "e")) 196 d.ba.Add(getArgsString("e")) 197 d.ba.Add(revScanArgsString("a", "c")) 198 d.ba.MaxSpanRequestKeys = 3 199 }, 200 check: func(t *testing.T, r resp) { 201 verifyScanResult(t, r, []string{"d", "c"}, []string{"e"}, []string{"b"}) 202 verifyResumeSpans(t, r, "", "", "a-a\x00") 203 b, err := r.br.Responses[1].GetGet().Value.GetBytes() 204 require.NoError(t, err) 205 require.Equal(t, "value-e", string(b)) 206 }, 207 }, 208 // 209 // Test suite for TargetBytes. 210 // 211 { 212 // Two scans and a target bytes limit that saturates during the 213 // first. 214 name: "scans with TargetBytes=1", 215 setup: func(t *testing.T, d *data) { 216 writeABCDEF(t, d) 217 d.ba.Add(scanArgsString("a", "c")) 218 d.ba.Add(getArgsString("e")) 219 d.ba.Add(scanArgsString("c", "e")) 220 d.ba.TargetBytes = 1 221 // Also set a nontrivial MaxSpanRequestKeys, just to make sure 222 // there's no weird interaction (like it overriding TargetBytes). 223 // The stricter one ought to win. 224 d.ba.MaxSpanRequestKeys = 3 225 }, 226 check: func(t *testing.T, r resp) { 227 verifyScanResult(t, r, []string{"a"}, []string{"e"}, nil) 228 verifyResumeSpans(t, r, "b-c", "", "c-e") 229 b, err := r.br.Responses[1].GetGet().Value.GetBytes() 230 require.NoError(t, err) 231 require.Equal(t, "value-e", string(b)) 232 }, 233 }, { 234 // Ditto in reverse. 235 name: "reverse scans with TargetBytes=1", 236 setup: func(t *testing.T, d *data) { 237 writeABCDEF(t, d) 238 d.ba.Add(revScanArgsString("c", "e")) 239 d.ba.Add(getArgsString("e")) 240 d.ba.Add(revScanArgsString("a", "c")) 241 d.ba.TargetBytes = 1 242 d.ba.MaxSpanRequestKeys = 3 243 }, 244 check: func(t *testing.T, r resp) { 245 verifyScanResult(t, r, []string{"d"}, []string{"e"}, nil) 246 verifyResumeSpans(t, r, "c-c\x00", "", "a-c") 247 b, err := r.br.Responses[1].GetGet().Value.GetBytes() 248 require.NoError(t, err) 249 require.Equal(t, "value-e", string(b)) 250 }, 251 }, 252 // 253 // Test suite for KeyLocking. 254 // 255 { 256 // Three scans that observe 3, 1, and 0 keys, respectively. An 257 // unreplicated lock should be acquired on each key that is scanned. 258 name: "scans with key locking", 259 setup: func(t *testing.T, d *data) { 260 writeABCDEF(t, d) 261 scanAD := scanArgsString("a", "d") 262 scanAD.KeyLocking = lock.Exclusive 263 d.ba.Add(scanAD) 264 scanEF := scanArgsString("e", "f") 265 scanEF.KeyLocking = lock.Exclusive 266 d.ba.Add(scanEF) 267 scanHJ := scanArgsString("h", "j") 268 scanHJ.KeyLocking = lock.Exclusive 269 d.ba.Add(scanHJ) 270 d.ba.Txn = &txn 271 }, 272 check: func(t *testing.T, r resp) { 273 verifyScanResult(t, r, []string{"a", "b", "c"}, []string{"e"}, nil) 274 verifyAcquiredLocks(t, r, lock.Unreplicated, "a", "b", "c", "e") 275 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 276 }, 277 }, 278 { 279 // Ditto in reverse. 280 name: "reverse scans with key locking", 281 setup: func(t *testing.T, d *data) { 282 writeABCDEF(t, d) 283 scanAD := revScanArgsString("a", "d") 284 scanAD.KeyLocking = lock.Exclusive 285 d.ba.Add(scanAD) 286 scanEF := revScanArgsString("e", "f") 287 scanEF.KeyLocking = lock.Exclusive 288 d.ba.Add(scanEF) 289 scanHJ := revScanArgsString("h", "j") 290 scanHJ.KeyLocking = lock.Exclusive 291 d.ba.Add(scanHJ) 292 d.ba.Txn = &txn 293 }, 294 check: func(t *testing.T, r resp) { 295 verifyScanResult(t, r, []string{"c", "b", "a"}, []string{"e"}, nil) 296 verifyAcquiredLocks(t, r, lock.Unreplicated, "c", "b", "a", "e") 297 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 298 }, 299 }, 300 { 301 // Three scans that observe 3, 1, and 0 keys, respectively. No 302 // transaction set, so no locks should be acquired. 303 name: "scans with key locking without txn", 304 setup: func(t *testing.T, d *data) { 305 writeABCDEF(t, d) 306 scanAD := scanArgsString("a", "d") 307 scanAD.KeyLocking = lock.Exclusive 308 d.ba.Add(scanAD) 309 scanEF := scanArgsString("e", "f") 310 scanEF.KeyLocking = lock.Exclusive 311 d.ba.Add(scanEF) 312 scanHJ := scanArgsString("h", "j") 313 scanHJ.KeyLocking = lock.Exclusive 314 d.ba.Add(scanHJ) 315 }, 316 check: func(t *testing.T, r resp) { 317 verifyScanResult(t, r, []string{"a", "b", "c"}, []string{"e"}, nil) 318 verifyAcquiredLocks(t, r, lock.Unreplicated, []string(nil)...) 319 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 320 }, 321 }, 322 { 323 // Ditto in reverse. 324 name: "reverse scans with key locking without txn", 325 setup: func(t *testing.T, d *data) { 326 writeABCDEF(t, d) 327 scanAD := revScanArgsString("a", "d") 328 scanAD.KeyLocking = lock.Exclusive 329 d.ba.Add(scanAD) 330 scanEF := revScanArgsString("e", "f") 331 scanEF.KeyLocking = lock.Exclusive 332 d.ba.Add(scanEF) 333 scanHJ := revScanArgsString("h", "j") 334 scanHJ.KeyLocking = lock.Exclusive 335 d.ba.Add(scanHJ) 336 }, 337 check: func(t *testing.T, r resp) { 338 verifyScanResult(t, r, []string{"c", "b", "a"}, []string{"e"}, nil) 339 verifyAcquiredLocks(t, r, lock.Unreplicated, []string(nil)...) 340 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 341 }, 342 }, 343 { 344 345 // Scanning with key locking and a MaxSpanRequestKeys limit should 346 // acquire an unreplicated lock on each key returned and no locks on 347 // keys past the limit. 348 name: "scan with key locking and MaxSpanRequestKeys=3", 349 setup: func(t *testing.T, d *data) { 350 writeABCDEF(t, d) 351 scanAE := scanArgsString("a", "e") 352 scanAE.KeyLocking = lock.Exclusive 353 d.ba.Add(scanAE) 354 d.ba.Txn = &txn 355 d.ba.MaxSpanRequestKeys = 3 356 }, 357 check: func(t *testing.T, r resp) { 358 verifyScanResult(t, r, []string{"a", "b", "c"}) 359 verifyResumeSpans(t, r, "d-e") 360 verifyAcquiredLocks(t, r, lock.Unreplicated, "a", "b", "c") 361 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 362 }, 363 }, 364 { 365 // Ditto in reverse. 366 name: "reverse scan with key locking and MaxSpanRequestKeys=3", 367 setup: func(t *testing.T, d *data) { 368 writeABCDEF(t, d) 369 scanAE := revScanArgsString("a", "e") 370 scanAE.KeyLocking = lock.Exclusive 371 d.ba.Add(scanAE) 372 d.ba.Txn = &txn 373 d.ba.MaxSpanRequestKeys = 3 374 }, 375 check: func(t *testing.T, r resp) { 376 verifyScanResult(t, r, []string{"d", "c", "b"}) 377 verifyResumeSpans(t, r, "a-a\x00") 378 verifyAcquiredLocks(t, r, lock.Unreplicated, "d", "c", "b") 379 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 380 }, 381 }, 382 { 383 384 // Scanning with key locking and a MaxSpanRequestKeys limit should 385 // acquire an unreplicated lock on each key returned and no locks on 386 // keys past the limit. One the batch's limit is exhausted, no more 387 // rows are scanner nor locks acquired. 388 name: "scans with key locking and MaxSpanRequestKeys=3", 389 setup: func(t *testing.T, d *data) { 390 writeABCDEF(t, d) 391 scanAE := scanArgsString("a", "e") 392 scanAE.KeyLocking = lock.Exclusive 393 d.ba.Add(scanAE) 394 scanHJ := scanArgsString("h", "j") 395 scanHJ.KeyLocking = lock.Exclusive 396 d.ba.Add(scanHJ) 397 d.ba.Txn = &txn 398 d.ba.MaxSpanRequestKeys = 3 399 }, 400 check: func(t *testing.T, r resp) { 401 verifyScanResult(t, r, []string{"a", "b", "c"}, nil) 402 verifyResumeSpans(t, r, "d-e", "h-j") 403 verifyAcquiredLocks(t, r, lock.Unreplicated, "a", "b", "c") 404 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 405 }, 406 }, 407 { 408 // Ditto in reverse. 409 name: "reverse scans with key locking and MaxSpanRequestKeys=3", 410 setup: func(t *testing.T, d *data) { 411 writeABCDEF(t, d) 412 scanAE := revScanArgsString("a", "e") 413 scanAE.KeyLocking = lock.Exclusive 414 d.ba.Add(scanAE) 415 scanHJ := scanArgsString("h", "j") 416 scanHJ.KeyLocking = lock.Exclusive 417 d.ba.Add(scanHJ) 418 d.ba.Txn = &txn 419 d.ba.MaxSpanRequestKeys = 3 420 }, 421 check: func(t *testing.T, r resp) { 422 verifyScanResult(t, r, []string{"d", "c", "b"}, nil) 423 verifyResumeSpans(t, r, "a-a\x00", "h-j") 424 verifyAcquiredLocks(t, r, lock.Unreplicated, "d", "c", "b") 425 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 426 }, 427 }, 428 { 429 // Scanning with key locking and a TargetBytes limit should acquire 430 // an unreplicated lock on each key returned and no locks on keys 431 // past the limit. 432 name: "scan with key locking and TargetBytes=1", 433 setup: func(t *testing.T, d *data) { 434 writeABCDEF(t, d) 435 scanAE := scanArgsString("a", "e") 436 scanAE.KeyLocking = lock.Exclusive 437 d.ba.Add(scanAE) 438 d.ba.Txn = &txn 439 d.ba.TargetBytes = 1 440 }, 441 check: func(t *testing.T, r resp) { 442 verifyScanResult(t, r, []string{"a"}) 443 verifyResumeSpans(t, r, "b-e") 444 verifyAcquiredLocks(t, r, lock.Unreplicated, "a") 445 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 446 }, 447 }, 448 { 449 // Ditto in reverse. 450 name: "reverse scan with key locking and TargetBytes=1", 451 setup: func(t *testing.T, d *data) { 452 writeABCDEF(t, d) 453 scanAE := revScanArgsString("a", "e") 454 scanAE.KeyLocking = lock.Exclusive 455 d.ba.Add(scanAE) 456 d.ba.Txn = &txn 457 d.ba.TargetBytes = 1 458 }, 459 check: func(t *testing.T, r resp) { 460 verifyScanResult(t, r, []string{"d"}) 461 verifyResumeSpans(t, r, "a-c\x00") 462 verifyAcquiredLocks(t, r, lock.Unreplicated, "d") 463 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 464 }, 465 }, 466 { 467 // Scanning with key locking and a TargetBytes limit should acquire 468 // an unreplicated lock on each key returned and no locks on keys 469 // past the limit. One the batch's limit is exhausted, no more rows 470 // are scanner nor locks acquired. 471 name: "scans with key locking and TargetBytes=1", 472 setup: func(t *testing.T, d *data) { 473 writeABCDEF(t, d) 474 scanAE := scanArgsString("a", "e") 475 scanAE.KeyLocking = lock.Exclusive 476 d.ba.Add(scanAE) 477 scanHJ := scanArgsString("h", "j") 478 scanHJ.KeyLocking = lock.Exclusive 479 d.ba.Add(scanHJ) 480 d.ba.Txn = &txn 481 d.ba.TargetBytes = 1 482 }, 483 check: func(t *testing.T, r resp) { 484 verifyScanResult(t, r, []string{"a"}, nil) 485 verifyResumeSpans(t, r, "b-e", "h-j") 486 verifyAcquiredLocks(t, r, lock.Unreplicated, "a") 487 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 488 }, 489 }, 490 { 491 // Ditto in reverse. 492 name: "reverse scans with key locking and TargetBytes=1", 493 setup: func(t *testing.T, d *data) { 494 writeABCDEF(t, d) 495 scanAE := revScanArgsString("a", "e") 496 scanAE.KeyLocking = lock.Exclusive 497 d.ba.Add(scanAE) 498 scanHJ := scanArgsString("h", "j") 499 scanHJ.KeyLocking = lock.Exclusive 500 d.ba.Add(scanHJ) 501 d.ba.Txn = &txn 502 d.ba.TargetBytes = 1 503 }, 504 check: func(t *testing.T, r resp) { 505 verifyScanResult(t, r, []string{"d"}, nil) 506 verifyResumeSpans(t, r, "a-c\x00", "h-j") 507 verifyAcquiredLocks(t, r, lock.Unreplicated, "d") 508 verifyAcquiredLocks(t, r, lock.Replicated, []string(nil)...) 509 }, 510 }, 511 // 512 // Test suite for ResolveIntentRange with and without limits. 513 // 514 { 515 // Three range intent resolutions that observe 3, 1, and 0 intent, 516 // respectively. All intents should be resolved. 517 name: "ranged intent resolution", 518 setup: func(t *testing.T, d *data) { 519 writeABCDEFIntents(t, d, &txn) 520 d.ba.Add(resolveIntentRangeArgsString("a", "d", txn.TxnMeta, roachpb.COMMITTED)) 521 d.ba.Add(resolveIntentRangeArgsString("e", "f", txn.TxnMeta, roachpb.COMMITTED)) 522 d.ba.Add(resolveIntentRangeArgsString("h", "j", txn.TxnMeta, roachpb.COMMITTED)) 523 }, 524 check: func(t *testing.T, r resp) { 525 verifyNumKeys(t, r, 3, 1, 0) 526 verifyResumeSpans(t, r, "", "", "") 527 }, 528 }, 529 { 530 // Resolving intents with a giant limit should resolve everything. 531 name: "ranged intent resolution with giant MaxSpanRequestKeys", 532 setup: func(t *testing.T, d *data) { 533 writeABCDEFIntents(t, d, &txn) 534 d.ba.Add(resolveIntentRangeArgsString("a", "d", txn.TxnMeta, roachpb.COMMITTED)) 535 d.ba.Add(resolveIntentRangeArgsString("e", "f", txn.TxnMeta, roachpb.COMMITTED)) 536 d.ba.Add(resolveIntentRangeArgsString("h", "j", txn.TxnMeta, roachpb.COMMITTED)) 537 d.ba.MaxSpanRequestKeys = 100000 538 }, 539 check: func(t *testing.T, r resp) { 540 verifyNumKeys(t, r, 3, 1, 0) 541 verifyResumeSpans(t, r, "", "", "") 542 }, 543 }, 544 { 545 // A batch limited to resolve only up to 3 keys should respect that 546 // limit. The limit is saturated by the first request in the batch. 547 name: "ranged intent resolution with MaxSpanRequestKeys=3", 548 setup: func(t *testing.T, d *data) { 549 writeABCDEFIntents(t, d, &txn) 550 d.ba.Add(resolveIntentRangeArgsString("a", "d", txn.TxnMeta, roachpb.COMMITTED)) 551 d.ba.Add(resolveIntentRangeArgsString("e", "f", txn.TxnMeta, roachpb.COMMITTED)) 552 d.ba.Add(resolveIntentRangeArgsString("h", "j", txn.TxnMeta, roachpb.COMMITTED)) 553 d.ba.MaxSpanRequestKeys = 3 554 }, 555 check: func(t *testing.T, r resp) { 556 verifyNumKeys(t, r, 3, 0, 0) 557 verifyResumeSpans(t, r, "c\x00-d", "e-f", "h-j") 558 }, 559 }, 560 } 561 562 for _, tc := range tcs { 563 t.Run(tc.name, func(t *testing.T) { 564 ctx := context.Background() 565 eng := storage.NewDefaultInMem() 566 defer eng.Close() 567 568 d := &data{ 569 idKey: kvserverbase.CmdIDKey("testing"), 570 eng: eng, 571 } 572 d.AbortSpan = abortspan.New(1) 573 d.ba.Header.Timestamp = ts 574 575 tc.setup(t, d) 576 577 var r resp 578 r.d = d 579 r.br, r.res, r.pErr = evaluateBatch( 580 ctx, 581 d.idKey, 582 d.eng, 583 d.MockEvalCtx.EvalContext(), 584 &d.ms, 585 &d.ba, 586 d.readOnly, 587 ) 588 589 tc.check(t, r) 590 }) 591 } 592 } 593 594 type data struct { 595 batcheval.MockEvalCtx 596 ba roachpb.BatchRequest 597 idKey kvserverbase.CmdIDKey 598 eng storage.Engine 599 ms enginepb.MVCCStats 600 readOnly bool 601 } 602 603 type resp struct { 604 d *data 605 br *roachpb.BatchResponse 606 res result.Result 607 pErr *roachpb.Error 608 } 609 610 type testCase struct { 611 name string 612 setup func(*testing.T, *data) 613 check func(*testing.T, resp) 614 } 615 616 func writeABCDEF(t *testing.T, d *data) { 617 writeABCDEFIntents(t, d, nil /* txn */) 618 } 619 620 func writeABCDEFIntents(t *testing.T, d *data, txn *roachpb.Transaction) { 621 for _, k := range []string{"a", "b", "c", "d", "e", "f"} { 622 require.NoError(t, storage.MVCCPut( 623 context.Background(), d.eng, nil /* ms */, roachpb.Key(k), d.ba.Timestamp, 624 roachpb.MakeValueFromString("value-"+k), txn)) 625 } 626 } 627 628 func verifyScanResult(t *testing.T, r resp, keysPerResp ...[]string) { 629 require.Nil(t, r.pErr) 630 require.NotNil(t, r.br) 631 require.Len(t, r.br.Responses, len(keysPerResp)) 632 for i, keys := range keysPerResp { 633 var isGet bool 634 scan := r.br.Responses[i].GetInner() 635 var rows []roachpb.KeyValue 636 switch req := scan.(type) { 637 case *roachpb.ScanResponse: 638 rows = req.Rows 639 case *roachpb.ReverseScanResponse: 640 rows = req.Rows 641 case *roachpb.GetResponse: 642 isGet = true 643 rows = []roachpb.KeyValue{{ 644 Key: r.d.ba.Requests[i].GetGet().Key, 645 Value: *req.Value, 646 }} 647 default: 648 } 649 650 if !isGet { 651 require.EqualValues(t, len(keys), scan.Header().NumKeys, "in response #%d", i+1) 652 } else { 653 require.Zero(t, scan.Header().NumKeys, "in response #%d", i+1) 654 } 655 var actKeys []string 656 for _, row := range rows { 657 actKeys = append(actKeys, string(row.Key)) 658 } 659 require.Equal(t, keys, actKeys, "in response #%i", i+1) 660 } 661 } 662 663 func verifyNumKeys(t *testing.T, r resp, keysPerResp ...int) { 664 require.Nil(t, r.pErr) 665 require.NotNil(t, r.br) 666 require.Len(t, r.br.Responses, len(keysPerResp)) 667 for i, keys := range keysPerResp { 668 actKeys := int(r.br.Responses[i].GetInner().Header().NumKeys) 669 require.Equal(t, keys, actKeys, "in response #%i", i+1) 670 } 671 } 672 673 func verifyResumeSpans(t *testing.T, r resp, resumeSpans ...string) { 674 for i, span := range resumeSpans { 675 rs := r.br.Responses[i].GetInner().Header().ResumeSpan 676 if span == "" { 677 require.Nil(t, rs) 678 } else { 679 require.NotNil(t, rs) 680 act := fmt.Sprintf("%s-%s", string(rs.Key), string(rs.EndKey)) 681 require.Equal(t, span, act, "#%d", i+1) 682 } 683 } 684 } 685 686 func verifyAcquiredLocks(t *testing.T, r resp, dur lock.Durability, lockedKeys ...string) { 687 var foundLocked []string 688 for _, l := range r.res.Local.AcquiredLocks { 689 if l.Durability == dur { 690 foundLocked = append(foundLocked, string(l.Key)) 691 } 692 } 693 require.Equal(t, lockedKeys, foundLocked) 694 }