Example #1
0
// TestRocksDBCompaction verifies that a garbage collector can be
// installed on a RocksDB engine and will properly compact entries
// response cache and transaction entries.
func TestRocksDBCompaction(t *testing.T) {
	gob.Register(proto.Timestamp{})
	loc := util.CreateTempDirectory()
	rocksdb := NewRocksDB(proto.Attributes{Attrs: []string{"ssd"}}, loc)
	rocksdb.SetGCTimeouts(func() (minTxnTS, minRCacheTS int64) {
		minTxnTS = 1
		minRCacheTS = 2
		return
	})
	err := rocksdb.Start()
	if err != nil {
		t.Fatalf("could not create new rocksdb db instance at %s: %v", loc, err)
	}
	defer func(t *testing.T) {
		rocksdb.Close()
		if err := rocksdb.Destroy(); err != nil {
			t.Errorf("could not delete rocksdb db at %s: %v", loc, err)
		}
	}(t)

	rcPre := KeyLocalRangeResponseCachePrefix
	txnPre := KeyLocalTransactionPrefix

	// Write a two transaction values and two response cache values such
	// that exactly one of each should be GC'd based on our GC timeouts.
	batch := []interface{}{
		// TODO(spencer): use Transaction and Response protobufs here.
		BatchPut{Key: MakeKey(rcPre, Key("a")), Value: encodePutResponse(makeTS(2, 0), t)},
		BatchPut{Key: MakeKey(rcPre, Key("b")), Value: encodePutResponse(makeTS(3, 0), t)},

		BatchPut{Key: MakeKey(txnPre, Key("a")), Value: encodeTransaction(makeTS(1, 0), t)},
		BatchPut{Key: MakeKey(txnPre, Key("b")), Value: encodeTransaction(makeTS(2, 0), t)},
	}
	if err := rocksdb.WriteBatch(batch); err != nil {
		t.Fatal(err)
	}

	// Compact range and scan remaining values to compare.
	rocksdb.CompactRange(nil, nil)
	keyvals, err := rocksdb.Scan(KeyMin, KeyMax, 0)
	if err != nil {
		t.Fatalf("could not run scan: %v", err)
	}
	var keys []Key
	for _, kv := range keyvals {
		keys = append(keys, kv.Key)
	}
	expKeys := []Key{
		MakeKey(rcPre, Key("b")),
		MakeKey(txnPre, Key("b")),
	}
	if !reflect.DeepEqual(expKeys, keys) {
		t.Errorf("expected keys %s, got keys %s", expKeys, keys)
	}
}
// TestResponseCacheGC verifies that response cache entries are
// garbage collected periodically.
func TestResponseCacheGC(t *testing.T) {
	loc := util.CreateTempDirectory()
	rocksdb := engine.NewRocksDB(proto.Attributes{Attrs: []string{"ssd"}}, loc)
	if err := rocksdb.Start(); err != nil {
		t.Fatalf("could not create new rocksdb db instance at %s: %v", loc, err)
	}
	defer func(t *testing.T) {
		rocksdb.Close()
		if err := rocksdb.Destroy(); err != nil {
			t.Errorf("could not destroy rocksdb db at %s: %v", loc, err)
		}
	}(t)

	rc := NewResponseCache(1, rocksdb)
	cmdID := makeCmdID(1, 1)

	// Add response for cmdID with timestamp at time=1ns.
	copyIncR := incR
	copyIncR.Timestamp.WallTime = 1
	if err := rc.PutResponse(cmdID, &copyIncR); err != nil {
		t.Fatalf("unexpected error putting responpse: %v", err)
	}
	rocksdb.SetGCTimeouts(func() (minTxnTS, minRCacheTS int64) {
		minRCacheTS = 0 // avoids GC
		return
	})
	rocksdb.CompactRange(nil, nil)
	val := proto.IncrementResponse{}
	if ok, err := rc.GetResponse(cmdID, &val); !ok || err != nil || val.NewValue != 1 {
		t.Fatalf("unexpected response or error: %t, %v, %+v", ok, err, val)
	}

	// Now set minRCacheTS to 1, which will GC.
	rocksdb.SetGCTimeouts(func() (minTxnTS, minRCacheTS int64) {
		minRCacheTS = 1
		return
	})
	rocksdb.CompactRange(nil, nil)
	if ok, err := rc.GetResponse(cmdID, &val); ok || err != nil {
		t.Errorf("unexpected response or error: %t, %v", ok, err)
	}
}
Example #3
0
// TestRocksDBCompaction verifies that a garbage collector can be
// installed on a RocksDB engine and will properly compact response
// cache and transaction entries.
func TestRocksDBCompaction(t *testing.T) {
	gob.Register(proto.Timestamp{})
	loc := util.CreateTempDirectory()
	rocksdb := newMemRocksDB(proto.Attributes{Attrs: []string{"ssd"}}, testCacheSize)
	err := rocksdb.Start()
	if err != nil {
		t.Fatalf("could not create new rocksdb db instance at %s: %v", loc, err)
	}
	rocksdb.SetGCTimeouts(1, 2)
	defer func(t *testing.T) {
		rocksdb.Stop()
		if err := rocksdb.Destroy(); err != nil {
			t.Errorf("could not delete rocksdb db at %s: %v", loc, err)
		}
	}(t)

	cmdID := &proto.ClientCmdID{WallTime: 1, Random: 1}

	// Write two transaction values and two response cache values such
	// that exactly one of each should be GC'd based on our GC timeouts.
	kvs := []proto.KeyValue{
		{
			Key:   ResponseCacheKey(1, cmdID),
			Value: proto.Value{Bytes: encodePutResponse(makeTS(2, 0), t)},
		},
		{
			Key:   ResponseCacheKey(2, cmdID),
			Value: proto.Value{Bytes: encodePutResponse(makeTS(3, 0), t)},
		},
		{
			Key:   TransactionKey(proto.Key("a"), proto.Key(uuid.New())),
			Value: proto.Value{Bytes: encodeTransaction(makeTS(1, 0), t)},
		},
		{
			Key:   TransactionKey(proto.Key("b"), proto.Key(uuid.New())),
			Value: proto.Value{Bytes: encodeTransaction(makeTS(2, 0), t)},
		},
	}
	for _, kv := range kvs {
		if err := MVCCPut(rocksdb, nil, kv.Key, proto.ZeroTimestamp, kv.Value, nil); err != nil {
			t.Fatal(err)
		}
	}

	// Compact range and scan remaining values to compare.
	rocksdb.CompactRange(nil, nil)
	actualKVs, err := MVCCScan(rocksdb, KeyMin, KeyMax, 0, proto.ZeroTimestamp, nil)
	if err != nil {
		t.Fatalf("could not run scan: %v", err)
	}
	var keys []proto.Key
	for _, kv := range actualKVs {
		keys = append(keys, kv.Key)
	}
	expKeys := []proto.Key{
		kvs[1].Key,
		kvs[3].Key,
	}
	if !reflect.DeepEqual(expKeys, keys) {
		t.Errorf("expected keys %+v, got keys %+v", expKeys, keys)
	}
}