|
- // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
- // All rights reserved.
- //
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
- package leveldb
-
- import (
- "encoding/binary"
- "fmt"
-
- "github.com/syndtr/goleveldb/leveldb/errors"
- "github.com/syndtr/goleveldb/leveldb/storage"
- )
-
- // ErrInternalKeyCorrupted records internal key corruption.
- type ErrInternalKeyCorrupted struct {
- Ikey []byte
- Reason string
- }
-
- func (e *ErrInternalKeyCorrupted) Error() string {
- return fmt.Sprintf("leveldb: internal key %q corrupted: %s", e.Ikey, e.Reason)
- }
-
- func newErrInternalKeyCorrupted(ikey []byte, reason string) error {
- return errors.NewErrCorrupted(storage.FileDesc{}, &ErrInternalKeyCorrupted{append([]byte{}, ikey...), reason})
- }
-
- type keyType uint
-
- func (kt keyType) String() string {
- switch kt {
- case keyTypeDel:
- return "d"
- case keyTypeVal:
- return "v"
- }
- return fmt.Sprintf("<invalid:%#x>", uint(kt))
- }
-
- // Value types encoded as the last component of internal keys.
- // Don't modify; this value are saved to disk.
- const (
- keyTypeDel = keyType(0)
- keyTypeVal = keyType(1)
- )
-
- // keyTypeSeek defines the keyType that should be passed when constructing an
- // internal key for seeking to a particular sequence number (since we
- // sort sequence numbers in decreasing order and the value type is
- // embedded as the low 8 bits in the sequence number in internal keys,
- // we need to use the highest-numbered ValueType, not the lowest).
- const keyTypeSeek = keyTypeVal
-
- const (
- // Maximum value possible for sequence number; the 8-bits are
- // used by value type, so its can packed together in single
- // 64-bit integer.
- keyMaxSeq = (uint64(1) << 56) - 1
- // Maximum value possible for packed sequence number and type.
- keyMaxNum = (keyMaxSeq << 8) | uint64(keyTypeSeek)
- )
-
- // Maximum number encoded in bytes.
- var keyMaxNumBytes = make([]byte, 8)
-
- func init() {
- binary.LittleEndian.PutUint64(keyMaxNumBytes, keyMaxNum)
- }
-
- type internalKey []byte
-
- func makeInternalKey(dst, ukey []byte, seq uint64, kt keyType) internalKey {
- if seq > keyMaxSeq {
- panic("leveldb: invalid sequence number")
- } else if kt > keyTypeVal {
- panic("leveldb: invalid type")
- }
-
- dst = ensureBuffer(dst, len(ukey)+8)
- copy(dst, ukey)
- binary.LittleEndian.PutUint64(dst[len(ukey):], (seq<<8)|uint64(kt))
- return internalKey(dst)
- }
-
- func parseInternalKey(ik []byte) (ukey []byte, seq uint64, kt keyType, err error) {
- if len(ik) < 8 {
- return nil, 0, 0, newErrInternalKeyCorrupted(ik, "invalid length")
- }
- num := binary.LittleEndian.Uint64(ik[len(ik)-8:])
- seq, kt = uint64(num>>8), keyType(num&0xff)
- if kt > keyTypeVal {
- return nil, 0, 0, newErrInternalKeyCorrupted(ik, "invalid type")
- }
- ukey = ik[:len(ik)-8]
- return
- }
-
- func validInternalKey(ik []byte) bool {
- _, _, _, err := parseInternalKey(ik)
- return err == nil
- }
-
- func (ik internalKey) assert() {
- if ik == nil {
- panic("leveldb: nil internalKey")
- }
- if len(ik) < 8 {
- panic(fmt.Sprintf("leveldb: internal key %q, len=%d: invalid length", []byte(ik), len(ik)))
- }
- }
-
- func (ik internalKey) ukey() []byte {
- ik.assert()
- return ik[:len(ik)-8]
- }
-
- func (ik internalKey) num() uint64 {
- ik.assert()
- return binary.LittleEndian.Uint64(ik[len(ik)-8:])
- }
-
- func (ik internalKey) parseNum() (seq uint64, kt keyType) {
- num := ik.num()
- seq, kt = uint64(num>>8), keyType(num&0xff)
- if kt > keyTypeVal {
- panic(fmt.Sprintf("leveldb: internal key %q, len=%d: invalid type %#x", []byte(ik), len(ik), kt))
- }
- return
- }
-
- func (ik internalKey) String() string {
- if ik == nil {
- return "<nil>"
- }
-
- if ukey, seq, kt, err := parseInternalKey(ik); err == nil {
- return fmt.Sprintf("%s,%s%d", shorten(string(ukey)), kt, seq)
- }
- return fmt.Sprintf("<invalid:%#x>", []byte(ik))
- }
|