Example #1
0
// deleteRow adds to the batch the kv operations necessary to delete a table row
// with the given values.
func (rd *rowDeleter) deleteRow(ctx context.Context, b *client.Batch, values []parser.Datum) error {
	if err := rd.fks.checkAll(values); err != nil {
		return err
	}

	primaryIndexKey, secondaryIndexEntries, err := rd.helper.encodeIndexes(rd.fetchColIDtoRowIndex, values)
	if err != nil {
		return err
	}

	for _, secondaryIndexEntry := range secondaryIndexEntries {
		if log.V(2) {
			log.Infof(ctx, "Del %s", secondaryIndexEntry.Key)
		}
		b.Del(secondaryIndexEntry.Key)
	}

	// Delete the row.
	rd.startKey = roachpb.Key(primaryIndexKey)
	rd.endKey = roachpb.Key(encoding.EncodeNotNullDescending(primaryIndexKey))
	if log.V(2) {
		log.Infof(ctx, "DelRange %s - %s", rd.startKey, rd.endKey)
	}
	b.DelRange(&rd.startKey, &rd.endKey, false)
	rd.startKey, rd.endKey = nil, nil

	return nil
}
Example #2
0
// TestTxnDelRangeIntentResolutionCounts ensures that intents left behind by a
// DelRange with a MaxSpanRequestKeys limit are resolved correctly and by
// using the minimal span of keys.
func TestTxnDelRangeIntentResolutionCounts(t *testing.T) {
	defer leaktest.AfterTest(t)()
	var intentResolutionCount int64
	params := base.TestServerArgs{
		Knobs: base.TestingKnobs{
			Store: &storage.StoreTestingKnobs{
				NumKeysEvaluatedForRangeIntentResolution: &intentResolutionCount,
				TestingCommandFilter: func(filterArgs storagebase.FilterArgs) *roachpb.Error {
					req, ok := filterArgs.Req.(*roachpb.ResolveIntentRequest)
					if ok {
						key := req.Header().Key.String()
						// Check if the intent is from the range being
						// scanned below.
						if key >= "a" && key < "d" {
							t.Errorf("resolving intent on key %s", key)
						}
					}
					return nil
				},
			},
		},
	}
	s, _, db := serverutils.StartServer(t, params)
	defer s.Stopper().Stop()

	for _, abortTxn := range []bool{false, true} {
		spanSize := int64(10)
		prefixes := []string{"a", "b", "c"}
		for i := int64(0); i < spanSize; i++ {
			for _, prefix := range prefixes {
				if err := db.Put(context.TODO(), fmt.Sprintf("%s%d", prefix, i), "v"); err != nil {
					t.Fatal(err)
				}
			}
		}
		totalNumKeys := int64(len(prefixes)) * spanSize

		atomic.StoreInt64(&intentResolutionCount, 0)
		limit := totalNumKeys / 2
		if err := db.Txn(context.TODO(), func(txn *client.Txn) error {
			var b client.Batch
			// Fully deleted.
			b.DelRange("a", "b", false)
			// Partially deleted.
			b.DelRange("b", "c", false)
			// Not deleted.
			b.DelRange("c", "d", false)
			b.Header.MaxSpanRequestKeys = limit
			if err := txn.Run(&b); err != nil {
				return err
			}
			if abortTxn {
				return errors.New("aborting txn")
			}
			return nil
		}); err != nil && !abortTxn {
			t.Fatal(err)
		}

		// Ensure that the correct number of keys were evaluated for intents.
		if numKeys := atomic.LoadInt64(&intentResolutionCount); numKeys != limit {
			t.Fatalf("abortTxn: %v, resolved %d keys, expected %d", abortTxn, numKeys, limit)
		}

		// Ensure no intents are left behind. Scan the entire span to resolve
		// any intents that were left behind; intents are resolved internally
		// through ResolveIntentRequest(s).
		kvs, err := db.Scan(context.TODO(), "a", "d", totalNumKeys)
		if err != nil {
			t.Fatal(err)
		}
		expectedNumKeys := totalNumKeys / 2
		if abortTxn {
			expectedNumKeys = totalNumKeys
		}
		if int64(len(kvs)) != expectedNumKeys {
			t.Errorf("abortTxn: %v, %d keys left behind, expected=%d",
				abortTxn, len(kvs), expectedNumKeys)
		}
	}
}