You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							143 lines
						
					
					
						
							3.7 KiB
						
					
					
				
			
		
		
	
	
							143 lines
						
					
					
						
							3.7 KiB
						
					
					
				| // 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))
 | |
| }
 | |
| 
 |