@@ -283,6 +283,10 @@ type ClientOperationConfig struct {
283283 // FlushLockTable is an operation that moves unreplicated locks in the
284284 // in-memory lock table into the
285285 FlushLockTable int
286+
287+ // MutateBatchHeader mutates elements of the batch Header that may influence
288+ // batch evaluation. Only relevant for BatchOperations.
289+ MutateBatchHeader int
286290}
287291
288292// BatchOperationConfig configures the relative probability of generating a
@@ -433,6 +437,7 @@ func newAllOperationsConfig() GeneratorConfig {
433437 AddSSTable : 1 ,
434438 Barrier : 1 ,
435439 FlushLockTable : 1 ,
440+ MutateBatchHeader : 1 ,
436441 }
437442 batchOpConfig := BatchOperationConfig {
438443 Batch : 4 ,
@@ -498,6 +503,14 @@ func newAllOperationsConfig() GeneratorConfig {
498503// operations/make some operations more likely.
499504func NewDefaultConfig () GeneratorConfig {
500505 config := newAllOperationsConfig ()
506+
507+ // MutateBatchHeader is only valid in batches.
508+ config .Ops .DB .MutateBatchHeader = 0
509+ config .Ops .ClosureTxn .TxnClientOps .MutateBatchHeader = 0
510+
511+ // TODO(#153446): Header mutations with EndTransaction are not currently safe.
512+ config .Ops .ClosureTxn .CommitBatchOps .MutateBatchHeader = 0
513+
501514 // DeleteRangeUsingTombstone does not support transactions.
502515 config .Ops .ClosureTxn .TxnClientOps .DeleteRangeUsingTombstone = 0
503516 config .Ops .ClosureTxn .TxnBatchOps .Ops .DeleteRangeUsingTombstone = 0
@@ -876,6 +889,7 @@ func (g *generator) registerClientOps(allowed *[]opGen, c *ClientOperationConfig
876889 addOpGen (allowed , randAddSSTable , c .AddSSTable )
877890 addOpGen (allowed , randBarrier , c .Barrier )
878891 addOpGen (allowed , randFlushLockTable , c .FlushLockTable )
892+ addOpGen (allowed , randBatchMutation , c .MutateBatchHeader )
879893}
880894
881895func (g * generator ) registerBatchOps (allowed * []opGen , c * BatchOperationConfig ) {
@@ -1452,6 +1466,19 @@ func randMergeIsSplit(g *generator, rng *rand.Rand) Operation {
14521466 return merge (key )
14531467}
14541468
1469+ func randBatchMutation (g * generator , rng * rand.Rand ) Operation {
1470+ op := & MutateBatchHeaderOperation {}
1471+ // We currently only support two header option mutations, both of which can
1472+ // lead to early termination. Half the time we choose a value very likely to
1473+ // lead to early termination.
1474+ if rng .Float64 () > 0.5 {
1475+ op .MaxSpanRequestKeys = randItem (rng , []int64 {1 , 100 })
1476+ } else {
1477+ op .TargetBytes = randItem (rng , []int64 {1 , 1 << 20 /* 1MiB */ })
1478+ }
1479+ return Operation {MutateBatchHeader : op }
1480+ }
1481+
14551482func makeRemoveReplicaFn (key string , current []roachpb.ReplicationTarget , voter bool ) opGenFunc {
14561483 return func (g * generator , rng * rand.Rand ) Operation {
14571484 var changeType roachpb.ReplicaChangeType
@@ -1565,6 +1592,13 @@ func makeRandBatch(c *ClientOperationConfig) opGenFunc {
15651592 numOps := rng .Intn (4 )
15661593 ops := make ([]Operation , numOps )
15671594 var addedForwardScan , addedReverseScan bool
1595+
1596+ // TODO(ssd): MutateBatchHeader is disallowed with Puts because of
1597+ // validation in the txnWriteBuffer that disallows such requests. We could
1598+ // relax this restriction for many batches if we had information about the
1599+ // enclosing transaction here.
1600+ var addedPutOrCPut , addedBatchHeaderMutation bool
1601+
15681602 for i := 0 ; i < numOps ; i ++ {
15691603 ops [i ] = g .selectOp (rng , allowed )
15701604 if ops [i ].Scan != nil {
@@ -1585,6 +1619,20 @@ func makeRandBatch(c *ClientOperationConfig) opGenFunc {
15851619 }
15861620 addedReverseScan = true
15871621 }
1622+ } else if ops [i ].Put != nil {
1623+ if addedBatchHeaderMutation {
1624+ i --
1625+ continue
1626+ }
1627+ addedPutOrCPut = true
1628+ } else if ops [i ].MutateBatchHeader != nil {
1629+ // In addition to avoiding batch mutations when we have Puts or CPuts,
1630+ // we also skip adding mutations if one is already added.
1631+ if addedPutOrCPut || addedBatchHeaderMutation {
1632+ i --
1633+ continue
1634+ }
1635+ addedBatchHeaderMutation = true
15881636 }
15891637 }
15901638 return batch (ops ... )
@@ -1803,6 +1851,10 @@ func keysBetween(keys map[string]struct{}, start, end string) []string {
18031851 return between
18041852}
18051853
1854+ func randItem [T any ](rng * rand.Rand , l []T ) T {
1855+ return l [rng .Intn (len (l ))]
1856+ }
1857+
18061858func randKey (rng * rand.Rand ) string {
18071859 // Avoid the endpoints because having point writes at the
18081860 // endpoints complicates randRangeSpan.
0 commit comments