blob: c5736eca0dfddf15709ebf35e7d84717ad0a11eb [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package util
import (
"fmt"
"strconv"
"strings"
"v.io/v23/syncbase/util"
"v.io/v23/verror"
"v.io/x/lib/vlog"
)
// JoinKeyParts builds keys for accessing data in the storage engine.
func JoinKeyParts(parts ...string) string {
return strings.Join(parts, KeyPartSep)
}
// SplitKeyParts is the inverse of JoinKeyParts. Clients are generally
// encouraged to use SplitNKeyParts.
func SplitKeyParts(key string) []string {
return strings.Split(key, KeyPartSep)
}
// SplitNKeyParts is to SplitKeyParts as strings.SplitN is to strings.Split.
func SplitNKeyParts(key string, n int) []string {
return strings.SplitN(key, KeyPartSep, n)
}
// StripFirstKeyPartOrDie strips off the first part of the given key. Typically
// used to strip off the key prefixes defined in constants.go. Panics if the
// input string has fewer than two parts.
func StripFirstKeyPartOrDie(key string) string {
parts := SplitNKeyParts(key, 2)
if len(parts) < 2 {
vlog.Fatalf("StripFirstKeyPartOrDie: invalid key %q", key)
}
return parts[1]
}
// FirstKeyPart returns the first part of 'key', typically a key prefix defined
// in constants.go.
func FirstKeyPart(key string) string {
return SplitNKeyParts(key, 2)[0]
}
// IsRowKey returns true iff 'key' is a storage engine key for a row.
func IsRowKey(key string) bool {
return FirstKeyPart(key) == RowPrefix
}
// IsPermsKey returns true iff 'key' is a storage engine key for perms.
func IsPermsKey(key string) bool {
return FirstKeyPart(key) == PermsPrefix
}
// ParseTableAndRow extracts table and row parts from the given storage engine
// key for a row or perms. Returns an error if the given key is not a storage
// engine key for a row or perms.
func ParseTableAndRow(key string) (table string, row string, err error) {
parts := SplitNKeyParts(key, 3)
pfx := parts[0]
if len(parts) < 3 || (pfx != RowPrefix && pfx != PermsPrefix) {
return "", "", fmt.Errorf("ParseTableAndRow: invalid key %q", key)
}
return parts[1], parts[2], nil
}
// ParseTableAndRowOrDie calls ParseTableAndRow and panics on error.
func ParseTableAndRowOrDie(key string) (table string, row string) {
table, row, err := ParseTableAndRow(key)
if err != nil {
vlog.Fatal(err)
}
return table, row
}
// ScanPrefixArgs returns args for sn.Scan() for the specified prefix.
func ScanPrefixArgs(stKeyPrefix, prefix string) ([]byte, []byte) {
return ScanRangeArgs(stKeyPrefix, util.PrefixRangeStart(prefix), util.PrefixRangeLimit(prefix))
}
// ScanRangeArgs returns args for sn.Scan() for the specified range.
// If limit is "", all rows with keys >= start are included.
func ScanRangeArgs(stKeyPrefix, start, limit string) ([]byte, []byte) {
fullStart, fullLimit := JoinKeyParts(stKeyPrefix, start), JoinKeyParts(stKeyPrefix, limit)
if limit == "" {
fullLimit = util.PrefixRangeLimit(fullLimit)
}
return []byte(fullStart), []byte(fullLimit)
}
type BatchType int
const (
BatchTypeSn BatchType = iota // snapshot
BatchTypeTx // transaction
)
// JoinBatchInfo encodes batch type and id into a single "info" string.
func JoinBatchInfo(batchType BatchType, batchId uint64) string {
return strings.Join([]string{strconv.Itoa(int(batchType)), strconv.FormatUint(batchId, 10)}, BatchSep)
}
// SplitBatchInfo is the inverse of JoinBatchInfo.
func SplitBatchInfo(batchInfo string) (BatchType, uint64, error) {
parts := strings.Split(batchInfo, BatchSep)
if len(parts) != 2 {
return BatchTypeSn, 0, verror.New(verror.ErrBadArg, nil, batchInfo)
}
batchTypeInt, err := strconv.Atoi(parts[0])
if err != nil {
return BatchTypeSn, 0, err
}
batchType := BatchType(batchTypeInt)
if batchType != BatchTypeSn && batchType != BatchTypeTx {
return BatchTypeSn, 0, verror.New(verror.ErrBadArg, nil, batchInfo)
}
batchId, err := strconv.ParseUint(parts[1], 0, 64)
if err != nil {
return BatchTypeSn, 0, err
}
return batchType, batchId, nil
}