// prettyPrintInternal parse key with prefix in keyDict, // if the key don't march any prefix in keyDict, return its byte value with quotation and false, // or else return its human readable value and true. func prettyPrintInternal(key roachpb.Key) (string, bool) { var buf bytes.Buffer for _, k := range keyDict { if key.Compare(k.start) >= 0 && (k.end == nil || key.Compare(k.end) <= 0) { buf.WriteString(k.name) if k.end != nil && k.end.Compare(key) == 0 { buf.WriteString("/Max") return buf.String(), true } hasPrefix := false for _, e := range k.entries { if bytes.HasPrefix(key, e.prefix) { hasPrefix = true key = key[len(e.prefix):] fmt.Fprintf(&buf, "%s%s", e.name, e.ppFunc(key)) break } } if !hasPrefix { key = key[len(k.start):] fmt.Fprintf(&buf, "/%q", []byte(key)) } return buf.String(), true } } return fmt.Sprintf("%q", []byte(key)), false }
// PrettyPrint prints the key in a human readable format: // // Key's Format Key's Value // /Local/... "\x01"+... // /Store/... "\x01s"+... // /RangeID/... "\x01s"+[rangeid] // /[rangeid]/SequenceCache/[id]/seq:[seq] "\x01s"+[rangeid]+"res-"+[id]+[seq] // /[rangeid]/RaftLeaderLease "\x01s"+[rangeid]+"rfll" // /[rangeid]/RaftTombstone "\x01s"+[rangeid]+"rftb" // /[rangeid]/RaftHardState "\x01s"+[rangeid]+"rfth" // /[rangeid]/RaftAppliedIndex "\x01s"+[rangeid]+"rfta" // /[rangeid]/RaftLog/logIndex:[logIndex] "\x01s"+[rangeid]+"rftl"+[logIndex] // /[rangeid]/RaftTruncatedState "\x01s"+[rangeid]+"rftt" // /[rangeid]/RaftLastIndex "\x01s"+[rangeid]+"rfti" // /[rangeid]/RangeLastVerificationTimestamp "\x01s"+[rangeid]+"rlvt" // /[rangeid]/RangeStats "\x01s"+[rangeid]+"stat" // /Range/... "\x01k"+... // /RangeDescriptor/[key] "\x01k"+[key]+"rdsc" // /RangeTreeNode/[key] "\x01k"+[key]+"rtn-" // /Transaction/addrKey:[key]/id:[id] "\x01k"+[key]+"txn-"+[id] // /Local/Max "\x02" // // /Meta1/[key] "\x02"+[key] // /Meta2/[key] "\x03"+[key] // /System/... "\x04" // /StatusStore/[key] "\x04status-store-"+[key] // /StatusNode/[key] "\x04status-node-"+[key] // /System/Max "\x05" // // /Table/[key] [key] // // /Min "" // /Max "\xff\xff" func PrettyPrint(key roachpb.Key) string { if bytes.Equal(key, MaxKey) { return "/Max" } else if bytes.Equal(key, MinKey) { return "/Min" } var buf bytes.Buffer for _, k := range keyDict { if key.Compare(k.start) >= 0 && (k.end == nil || key.Compare(k.end) <= 0) { fmt.Fprintf(&buf, "%s", k.name) if k.end != nil && k.end.Compare(key) == 0 { fmt.Fprintf(&buf, "/Max") return buf.String() } hasPrefix := false for _, e := range k.entries { if bytes.HasPrefix(key, e.prefix) { hasPrefix = true key = key[len(e.prefix):] fmt.Fprintf(&buf, "%s%s", e.name, e.ppFunc(key)) break } } if !hasPrefix { key = key[len(k.start):] fmt.Fprintf(&buf, "/%q", []byte(key)) } return buf.String() } } return fmt.Sprintf("%q", []byte(key)) }
// fetch retrieves spans from the kv func (f *kvFetcher) fetch() error { batchSize := f.getBatchSize() b := &client.Batch{} b.Header.MaxScanResults = batchSize var resumeKey roachpb.Key if len(f.kvs) > 0 { resumeKey = f.kvs[len(f.kvs)-1].Key // To resume forward scans we will set the (inclusive) scan start to the Next of the last // received key. To resume reverse scans we will set the (exclusive) scan end to the last // received key. if !f.reverse { resumeKey = resumeKey.Next() } } atEnd := true if !f.reverse { for i := 0; i < len(f.spans); i++ { start := f.spans[i].Start if resumeKey != nil { if resumeKey.Compare(f.spans[i].End) >= 0 { // We are resuming from a key after this span. continue } if resumeKey.Compare(start) > 0 { // We are resuming from a key inside this span. // In this case we should technically reduce the max count for the span; but // since this count is only an optimization it's not incorrect to retrieve more // keys for the span. start = resumeKey } } atEnd = false b.Scan(start, f.spans[i].End, f.spans[i].Count) } } else { for i := len(f.spans) - 1; i >= 0; i-- { end := f.spans[i].End if resumeKey != nil { if resumeKey.Compare(f.spans[i].Start) <= 0 { // We are resuming from a key before this span. continue } if resumeKey.Compare(end) < 0 { // We are resuming from a key inside this span. // In this case we should technically reduce the max count for the span; but // since this count is only an optimization it's not incorrect to retrieve more // keys for the span. end = resumeKey } } atEnd = false b.ReverseScan(f.spans[i].Start, end, f.spans[i].Count) } } if atEnd { // The last scan happened to finish just at the end of the last span. f.kvs = nil f.fetchEnd = true return nil } if err := f.txn.Run(b); err != nil { return err } if f.kvs == nil { numResults := 0 for _, result := range b.Results { numResults += len(result.Rows) } f.kvs = make([]client.KeyValue, 0, numResults) } else { f.kvs = f.kvs[:0] } for _, result := range b.Results { f.kvs = append(f.kvs, result.Rows...) } f.batchIdx++ f.totalFetched += int64(len(f.kvs)) f.kvIndex = 0 if int64(len(f.kvs)) < batchSize { f.fetchEnd = true } // TODO(radu): We should fetch the next chunk in the background instead of waiting for the next // call to fetch(). We can use a pool of workers to issue the KV ops which will also limit the // total number of fetches that happen in parallel (and thus the amount of resources we use). return nil }