// Get returns the value for a specified key. func (r *Range) Get(batch engine.Engine, args proto.GetRequest) (proto.GetResponse, []proto.Intent, error) { var reply proto.GetResponse val, intents, err := engine.MVCCGet(batch, args.Key, args.Timestamp, args.ReadConsistency == proto.CONSISTENT, args.Txn) reply.Value = val return reply, intents, err }
// Get returns the value for a specified key. func (r *Range) Get(batch engine.Engine, args *proto.GetRequest, reply *proto.GetResponse) []proto.Intent { val, intents, err := engine.MVCCGet(batch, args.Key, args.Timestamp, args.ReadConsistency == proto.CONSISTENT, args.Txn) reply.Value = val reply.SetGoError(err) return intents }
// Get returns the value for a specified key. func (r *Range) Get(args *proto.GetRequest, reply *proto.GetResponse) { val, err := r.engine.Get(args.Key) reply.Value = proto.Value{Bytes: val} reply.SetGoError(err) }
// Get returns the value for a specified key. func (r *Range) Get(args *proto.GetRequest, reply *proto.GetResponse) { val, err := r.mvcc.Get(args.Key, args.Timestamp, args.Txn) reply.Value = val reply.SetGoError(err) }
// verifyUncertainty writes values to a key in 5ns intervals and then launches // a transaction at each value's timestamp reading that value with // the maximumOffset given, verifying in the process that the correct values // are read (usually after one transaction restart). func verifyUncertainty(concurrency int, maxOffset time.Duration, t *testing.T) { db, _, clock, _, lSender, transport, err := createTestDB() if err != nil { t.Fatal(err) } defer transport.Close() txnOpts := &client.TransactionOptions{ Name: "test", } key := []byte("key-test") // wgStart waits for all transactions to line up, wgEnd has the main // function wait for them to finish. var wgStart, wgEnd sync.WaitGroup wgStart.Add(concurrency + 1) wgEnd.Add(concurrency) // Initial high offset to allow for future writes. clock.SetMaxOffset(999 * time.Nanosecond) for i := 0; i < concurrency; i++ { value := []byte(fmt.Sprintf("value-%d", i)) // Values will be written with 5ns spacing. futureTS := clock.Now().Add(5, 0) clock.Update(futureTS) // Expected number of versions skipped. skipCount := int(maxOffset) / 5 if i+skipCount >= concurrency { skipCount = concurrency - i - 1 } readValue := []byte(fmt.Sprintf("value-%d", i+skipCount)) pr := proto.PutResponse{} db.Call(proto.Put, &proto.PutRequest{ RequestHeader: proto.RequestHeader{ Key: key, }, Value: proto.Value{Bytes: value}, }, &pr) if err := pr.GoError(); err != nil { t.Errorf("%d: got write error: %v", i, err) } gr := proto.GetResponse{} db.Call(proto.Get, &proto.GetRequest{ RequestHeader: proto.RequestHeader{ Key: key, Timestamp: clock.Now(), }, }, &gr) if gr.GoError() != nil || gr.Value == nil || !bytes.Equal(gr.Value.Bytes, value) { t.Fatalf("%d: expected success reading value %+v: %v", i, gr.Value, gr.GoError()) } go func(i int) { defer wgEnd.Done() wgStart.Done() // Wait until the other goroutines are running. wgStart.Wait() txnManual := hlc.NewManualClock(futureTS.WallTime) txnClock := hlc.NewClock(txnManual.UnixNano) // Make sure to incorporate the logical component if the wall time // hasn't changed (i=0). The logical component will change // internally in a way we can't track, but we want to be just // ahead. txnClock.Update(futureTS.Add(0, 999)) // The written values are spaced out in intervals of 5ns, so // setting <5ns here should make do without any restarts while // higher values require roughly offset/5 restarts. txnClock.SetMaxOffset(maxOffset) sender := NewTxnCoordSender(lSender, txnClock, false) txnDB := client.NewKV(sender, nil) txnDB.User = storage.UserRoot if err := txnDB.RunTransaction(txnOpts, func(txn *client.KV) error { // Read within the transaction. gr := proto.GetResponse{} txn.Call(proto.Get, &proto.GetRequest{ RequestHeader: proto.RequestHeader{ Key: key, Timestamp: futureTS, }, }, &gr) if err := gr.GoError(); err != nil { if _, ok := gr.GoError().(*proto.ReadWithinUncertaintyIntervalError); ok { return err } return util.Errorf("unexpected read error of type %s: %v", reflect.TypeOf(err), err) } if gr.Value == nil || gr.Value.Bytes == nil { return util.Errorf("no value read") } if !bytes.Equal(gr.Value.Bytes, readValue) { return util.Errorf("%d: read wrong value %q at %v, wanted %q", i, gr.Value.Bytes, futureTS, readValue) } return nil }); err != nil { t.Error(err) } }(i) } // Kick the goroutines loose. wgStart.Done() // Wait for the goroutines to finish. wgEnd.Wait() }