@@ -304,22 +304,48 @@ func (tx *Txn) DeletePartition(
304304func (tx * Txn ) GetPartitionMetadata (
305305 ctx context.Context , treeKey cspann.TreeKey , partitionKey cspann.PartitionKey , forUpdate bool ,
306306) (cspann.PartitionMetadata , error ) {
307- // TODO(mw5h): Add to an existing batch instead of starting a new one.
308- b := tx .kv .NewBatch ()
309-
310307 metadataKey := vecencoding .EncodeMetadataKey (tx .store .prefix , treeKey , partitionKey )
311- if forUpdate {
312- // By acquiring a shared lock on metadata key, we prevent splits/merges of
313- // this partition from conflicting with the add operation.
314- b .GetForShare (metadataKey , tx .lockDurability )
315- } else {
316- b .Get (metadataKey )
317- }
318308
319- // Run the batch and get the partition metadata from results.
320- if err := tx .kv .Run (ctx , b ); err != nil {
321- return cspann.PartitionMetadata {},
322- errors .Wrapf (err , "getting partition metadata for %d" , partitionKey )
309+ // By acquiring a shared lock on metadata key, we prevent splits/merges of
310+ // this partition from conflicting with the add operation.
311+ b , err := func () (b * kv.Batch , err error ) {
312+ // TODO(mw5h): Add to an existing batch instead of starting a new one.
313+ b = tx .kv .NewBatch ()
314+
315+ if tx .kv .Sender ().GetSteppingMode (ctx ) == kv .SteppingEnabled {
316+ // When there are multiple inserts within the same SQL statement, the
317+ // first insert will trigger creation of the metadata record. However,
318+ // subsequent inserts will not be able to "see" this record, since they
319+ // will read at a lower sequence number than the metadata record was
320+ // written. Handle this issue by temporarily stepping the read sequence
321+ // number so the latest metadata can be read.
322+ prevSeqNum := tx .kv .GetReadSeqNum ()
323+ if err = tx .kv .Step (ctx , false /* allowReadTimestampStep */ ); err != nil {
324+ return nil , err
325+ }
326+ defer func () {
327+ // Restore the original sequence number.
328+ if readErr := tx .kv .SetReadSeqNum (prevSeqNum ); err != nil {
329+ err = errors .CombineErrors (err , readErr )
330+ }
331+ }()
332+ }
333+
334+ if forUpdate {
335+ b .GetForShare (metadataKey , tx .lockDurability )
336+ } else {
337+ b .Get (metadataKey )
338+ }
339+
340+ // Run the batch.
341+ if err := tx .kv .Run (ctx , b ); err != nil {
342+ return nil , errors .Wrapf (err , "getting partition metadata for %d" , partitionKey )
343+ }
344+
345+ return b , nil
346+ }()
347+ if err != nil {
348+ return cspann.PartitionMetadata {}, err
323349 }
324350
325351 // If we're preparing to update the root partition, then lazily create its
@@ -591,10 +617,10 @@ func (tx *Txn) GetFullVectors(
591617}
592618
593619// createRootPartition uses the KV CPut operation to create metadata for the
594- // root partition, and then returns that metadata.
595- //
596- // NOTE: CPut always "sees" the latest write of the metadata record, even if the
597- // timestamp of that write is higher than this transaction's .
620+ // root partition, and then returns that metadata. If another transaction races
621+ // and creates the root partition at a higher timestamp, createRootPartition
622+ // returns a WriteTooOld error, which will trigger a refresh of this transaction
623+ // at the higher timestamp .
598624func (tx * Txn ) createRootPartition (
599625 ctx context.Context , metadataKey roachpb.Key ,
600626) (cspann.PartitionMetadata , error ) {
@@ -606,22 +632,11 @@ func (tx *Txn) createRootPartition(
606632 }
607633 encoded := vecencoding .EncodeMetadataValue (metadata )
608634
609- // Use CPutAllowingIfNotExists in order to handle the case where the same
610- // transaction inserts multiple vectors (e.g. multiple VALUES rows). In that
611- // case, the first row will trigger creation of the metadata record. However,
612- // subsequent inserts will not be able to "see" this record, since they will
613- // read at a lower sequence number than the metadata record was written.
614- // However, CPutAllowingIfNotExists will read at the higher sequence number
615- // and see that the record was already created.
616- //
617- // On the other hand, if a different transaction wrote the record, it will
618- // have a higher timestamp, and that will trigger a WriteTooOld error.
619- // Transactions which lose that race need to be refreshed.
620- var roachval roachpb.Value
621- roachval .SetBytes (encoded )
622- b .CPutAllowingIfNotExists (metadataKey , & roachval , roachval .TagAndDataBytes ())
635+ // Use CPut to detect the case where another transaction is racing to create
636+ // the root partition. CPut always "sees" the latest version of the metadata
637+ // record.
638+ b .CPut (metadataKey , encoded , nil /* expValue */ )
623639 if err := tx .kv .Run (ctx , b ); err != nil {
624- // Lost the race to a different transaction.
625640 return cspann.PartitionMetadata {}, errors .Wrapf (err , "creating root partition metadata" )
626641 }
627642 return metadata , nil
0 commit comments