Skip to content

Commit 112f5cb

Browse files
kamijin-fantadisksing
authored andcommitted
add rawkv/ReverseScan (#13)
Signed-off-by: kamijin_fanta <[email protected]>
1 parent 2130e26 commit 112f5cb

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

rawkv/rawkv.go

+47
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,53 @@ func (c *Client) Scan(startKey, endKey []byte, limit int) (keys [][]byte, values
302302
return
303303
}
304304

305+
// ReverseScan queries continuous kv pairs in range [endKey, startKey), up to limit pairs.
306+
// Direction is different from Scan, upper to lower.
307+
// If endKey is empty, it means unbounded.
308+
// If you want to include the startKey or exclude the endKey, append a '\0' to the key. For example, to scan
309+
// (endKey, startKey], you can write:
310+
// `ReverseScan(append(startKey, '\0'), append(endKey, '\0'), limit)`.
311+
// It doesn't support Scanning from "", because locating the last Region is not yet implemented.
312+
func (c *Client) ReverseScan(startKey, endKey []byte, limit int) (keys [][]byte, values [][]byte, err error) {
313+
start := time.Now()
314+
defer func() {
315+
metrics.RawkvCmdHistogram.WithLabelValues("raw_reverse_scan").Observe(time.Since(start).Seconds())
316+
}()
317+
318+
if limit > config.MaxRawKVScanLimit {
319+
return nil, nil, errors.WithStack(ErrMaxScanLimitExceeded)
320+
}
321+
322+
for len(keys) < limit {
323+
req := &rpc.Request{
324+
Type: rpc.CmdRawScan,
325+
RawScan: &kvrpcpb.RawScanRequest{
326+
StartKey: startKey,
327+
EndKey: endKey,
328+
Limit: uint32(limit - len(keys)),
329+
Reverse: true,
330+
},
331+
}
332+
resp, loc, err := c.sendReq(startKey, req)
333+
if err != nil {
334+
return nil, nil, err
335+
}
336+
cmdResp := resp.RawScan
337+
if cmdResp == nil {
338+
return nil, nil, errors.WithStack(rpc.ErrBodyMissing)
339+
}
340+
for _, pair := range cmdResp.Kvs {
341+
keys = append(keys, pair.Key)
342+
values = append(values, pair.Value)
343+
}
344+
startKey = loc.EndKey
345+
if len(startKey) == 0 {
346+
break
347+
}
348+
}
349+
return
350+
}
351+
305352
func (c *Client) sendReq(key []byte, req *rpc.Request) (*rpc.Response, *locate.KeyLocation, error) {
306353
bo := retry.NewBackoffer(context.Background(), retry.RawkvMaxBackoff)
307354
sender := rpc.NewRegionRequestSender(c.regionCache, c.rpcClient)

rawkv/rawkv_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,26 @@ func (s *testRawKVSuite) mustScanRange(c *C, startKey string, endKey string, lim
129129
}
130130
}
131131

132+
func (s *testRawKVSuite) mustReverseScan(c *C, startKey []byte, limit int, expect ...string) {
133+
keys, values, err := s.client.ReverseScan(startKey, nil, limit)
134+
c.Assert(err, IsNil)
135+
c.Assert(len(keys)*2, Equals, len(expect))
136+
for i := range keys {
137+
c.Assert(string(keys[i]), Equals, expect[i*2])
138+
c.Assert(string(values[i]), Equals, expect[i*2+1])
139+
}
140+
}
141+
142+
func (s *testRawKVSuite) mustReverseScanRange(c *C, startKey, endKey []byte, limit int, expect ...string) {
143+
keys, values, err := s.client.ReverseScan(startKey, endKey, limit)
144+
c.Assert(err, IsNil)
145+
c.Assert(len(keys)*2, Equals, len(expect))
146+
for i := range keys {
147+
c.Assert(string(keys[i]), Equals, expect[i*2])
148+
c.Assert(string(values[i]), Equals, expect[i*2+1])
149+
}
150+
}
151+
132152
func (s *testRawKVSuite) mustDeleteRange(c *C, startKey, endKey []byte, expected map[string]string) {
133153
err := s.client.DeleteRange(startKey, endKey)
134154
c.Assert(err, IsNil)

0 commit comments

Comments
 (0)