github.com/iotexproject/iotex-core@v1.14.1-rc1/db/range_index.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package db
     7  
     8  import (
     9  	"github.com/pkg/errors"
    10  )
    11  
    12  var (
    13  	// MaxKey is the special key such that bytes.Compare(MaxUint64, MaxKey) = -1
    14  	MaxKey = []byte{255, 255, 255, 255, 255, 255, 255, 255, 0}
    15  	// NotExist is the empty byte slice to indicate a key does not exist (as a result of calling Purge())
    16  	NotExist = []byte{}
    17  )
    18  
    19  type (
    20  	// RangeIndex is a bucket of sparse <k, v> pair, where k consists of 8-byte value
    21  	// and all keys that falls in 2 consecutive k have the same v
    22  	// for example, given 3 entries in the bucket:
    23  	//
    24  	// k = 0x0000000000000004 ==> v1
    25  	// k = 0x0000000000000123 ==> v2
    26  	// k = 0x0000000000005678 ==> v3
    27  	//
    28  	// we have:
    29  	// for all key   0x0 <= k <  0x4,    value[k] = initial value
    30  	// for all key   0x4 <= k <  0x123,  value[k] = v1
    31  	// for all key 0x123 <= k <  0x5678, value[k] = v2
    32  	// for all key          k >= 0x5678, value[k] = v3
    33  	//
    34  	RangeIndex interface {
    35  		// Insert inserts a value into the index
    36  		Insert(uint64, []byte) error
    37  		// Get returns value by the key
    38  		Get(uint64) ([]byte, error)
    39  		// Delete deletes an existing key
    40  		Delete(uint64) error
    41  		// Purge deletes an existing key and all keys before it
    42  		Purge(uint64) error
    43  		// Close makes the index not usable
    44  		Close()
    45  	}
    46  
    47  	// rangeIndex is RangeIndex implementation based on bolt DB
    48  	rangeIndex struct {
    49  		kvStore KVStoreForRangeIndex
    50  		bucket  []byte
    51  	}
    52  )
    53  
    54  // NewRangeIndex creates a new instance of rangeIndex
    55  func NewRangeIndex(kv KVStore, name, init []byte) (RangeIndex, error) {
    56  	if kv == nil {
    57  		return nil, errors.Wrap(ErrInvalid, "KVStore object is nil")
    58  	}
    59  	kvRange, ok := kv.(KVStoreForRangeIndex)
    60  	if !ok {
    61  		return nil, errors.Wrap(ErrInvalid, "range index can only be created from KVStoreForRangeIndex")
    62  	}
    63  	if len(name) == 0 {
    64  		return nil, errors.Wrap(ErrInvalid, "bucket name is nil")
    65  	}
    66  	// check whether init value exist or not
    67  	v, err := kv.Get(string(name), MaxKey)
    68  	if errors.Cause(err) == ErrNotExist || v == nil {
    69  		// write the initial value
    70  		if err := kv.Put(string(name), MaxKey, init); err != nil {
    71  			return nil, errors.Wrapf(err, "failed to create range index %x", name)
    72  		}
    73  	}
    74  
    75  	bucket := make([]byte, len(name))
    76  	copy(bucket, name)
    77  
    78  	return &rangeIndex{
    79  		kvStore: kvRange,
    80  		bucket:  bucket,
    81  	}, nil
    82  }
    83  
    84  // Insert inserts a value into the index
    85  func (r *rangeIndex) Insert(key uint64, value []byte) error {
    86  	if key == 0 {
    87  		// by definition, Get(0) = initial value
    88  		// so insert 0 is not allowed
    89  		return errors.New("cannot insert 0 for range index")
    90  	}
    91  	return r.kvStore.Insert(r.bucket, key, value)
    92  }
    93  
    94  // Get returns value by the key
    95  func (r *rangeIndex) Get(key uint64) ([]byte, error) {
    96  	return r.kvStore.SeekNext(r.bucket, key)
    97  }
    98  
    99  // Delete deletes an existing key
   100  func (r *rangeIndex) Delete(key uint64) error {
   101  	return r.kvStore.Remove(r.bucket, key)
   102  }
   103  
   104  // Purge deletes an existing key and all keys before it
   105  func (r *rangeIndex) Purge(key uint64) error {
   106  	return r.kvStore.Purge(r.bucket, key)
   107  }
   108  
   109  // Close makes the index not usable
   110  func (r *rangeIndex) Close() {
   111  	// frees reference to db, the db object itself will be closed/freed by its owner, not here
   112  	r.kvStore = nil
   113  	r.bucket = nil
   114  }