// TestMultiRangeScanReverseScanInconsistent verifies that a Scan/ReverseScan // across ranges that doesn't require read consistency will set a timestamp // using the clock local to the distributed sender. func TestMultiRangeScanReverseScanInconsistent(t *testing.T) { defer leaktest.AfterTest(t) s, db := setupMultipleRanges(t, "b") defer s.Stop() // Write keys "a" and "b", the latter of which is the first key in the // second range. keys := []string{"a", "b"} ts := []time.Time{} b := &client.Batch{} for _, key := range keys { b.Put(key, "value") } if err := db.Run(b); err != nil { t.Fatal(err) } for i := range keys { ts = append(ts, b.Results[i].Rows[0].Timestamp()) log.Infof("%d: %s", i, b.Results[i].Rows[0].Timestamp()) } // Do an inconsistent Scan/ReverseScan from a new DistSender and verify // it does the read at its local clock and doesn't receive an // OpRequiresTxnError. We set the local clock to the timestamp of // the first key to verify it's used to read only key "a". manual := hlc.NewManualClock(ts[1].UnixNano() - 1) clock := hlc.NewClock(manual.UnixNano) ds := kv.NewDistSender(&kv.DistSenderContext{Clock: clock}, s.Gossip()) // Scan. call := proto.ScanCall(proto.Key("a"), proto.Key("c"), 0) sr := call.Reply.(*proto.ScanResponse) sa := call.Args.(*proto.ScanRequest) sa.ReadConsistency = proto.INCONSISTENT if err := client.SendCall(ds, call); err != nil { t.Fatal(err) } if l := len(sr.Rows); l != 1 { t.Fatalf("expected 1 row; got %d", l) } if key := string(sr.Rows[0].Key); keys[0] != key { t.Errorf("expected key %q; got %q", keys[0], key) } // ReverseScan. call = proto.ReverseScanCall(proto.Key("a"), proto.Key("c"), 0) rsr := call.Reply.(*proto.ReverseScanResponse) rsa := call.Args.(*proto.ReverseScanRequest) rsa.ReadConsistency = proto.INCONSISTENT if err := client.SendCall(ds, call); err != nil { t.Fatal(err) } if l := len(rsr.Rows); l != 1 { t.Fatalf("expected 1 row; got %d", l) } if key := string(rsr.Rows[0].Key); keys[0] != key { t.Errorf("expected key %q; got %q", keys[0], key) } }
func (b *Batch) scan(s, e interface{}, maxRows int64, isReverse bool) { begin, err := marshalKey(s) if err != nil { b.initResult(0, 0, err) return } end, err := marshalKey(e) if err != nil { b.initResult(0, 0, err) return } if !isReverse { b.calls = append(b.calls, proto.ScanCall(proto.Key(begin), proto.Key(end), maxRows)) } else { b.calls = append(b.calls, proto.ReverseScanCall(proto.Key(begin), proto.Key(end), maxRows)) } b.initResult(1, 0, nil) }