github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/swarm/shed/index.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package shed
    18  
    19  import (
    20  	"bytes"
    21  
    22  	"github.com/syndtr/goleveldb/leveldb"
    23  )
    24  
    25  // Item holds fields relevant to Swarm Chunk data and metadata.
    26  // All information required for swarm storage and operations
    27  // on that storage must be defined here.
    28  // This structure is logically connected to swarm storage,
    29  // the only part of this package that is not generalized,
    30  // mostly for performance reasons.
    31  //
    32  // Item is a type that is used for retrieving, storing and encoding
    33  // chunk data and metadata. It is passed as an argument to Index encoding
    34  // functions, get function and put function.
    35  // But it is also returned with additional data from get function call
    36  // and as the argument in iterator function definition.
    37  type Item struct {
    38  	Address         []byte
    39  	Data            []byte
    40  	AccessTimestamp int64
    41  	StoreTimestamp  int64
    42  	// UseMockStore is a pointer to identify
    43  	// an unset state of the field in Join function.
    44  	UseMockStore *bool
    45  }
    46  
    47  // Merge is a helper method to construct a new
    48  // Item by filling up fields with default values
    49  // of a particular Item with values from another one.
    50  func (i Item) Merge(i2 Item) (new Item) {
    51  	if i.Address == nil {
    52  		i.Address = i2.Address
    53  	}
    54  	if i.Data == nil {
    55  		i.Data = i2.Data
    56  	}
    57  	if i.AccessTimestamp == 0 {
    58  		i.AccessTimestamp = i2.AccessTimestamp
    59  	}
    60  	if i.StoreTimestamp == 0 {
    61  		i.StoreTimestamp = i2.StoreTimestamp
    62  	}
    63  	if i.UseMockStore == nil {
    64  		i.UseMockStore = i2.UseMockStore
    65  	}
    66  	return i
    67  }
    68  
    69  // Index represents a set of LevelDB key value pairs that have common
    70  // prefix. It holds functions for encoding and decoding keys and values
    71  // to provide transparent actions on saved data which inclide:
    72  // - getting a particular Item
    73  // - saving a particular Item
    74  // - iterating over a sorted LevelDB keys
    75  // It implements IndexIteratorInterface interface.
    76  type Index struct {
    77  	db              *DB
    78  	prefix          []byte
    79  	encodeKeyFunc   func(fields Item) (key []byte, err error)
    80  	decodeKeyFunc   func(key []byte) (e Item, err error)
    81  	encodeValueFunc func(fields Item) (value []byte, err error)
    82  	decodeValueFunc func(keyFields Item, value []byte) (e Item, err error)
    83  }
    84  
    85  // IndexFuncs structure defines functions for encoding and decoding
    86  // LevelDB keys and values for a specific index.
    87  type IndexFuncs struct {
    88  	EncodeKey   func(fields Item) (key []byte, err error)
    89  	DecodeKey   func(key []byte) (e Item, err error)
    90  	EncodeValue func(fields Item) (value []byte, err error)
    91  	DecodeValue func(keyFields Item, value []byte) (e Item, err error)
    92  }
    93  
    94  // NewIndex returns a new Index instance with defined name and
    95  // encoding functions. The name must be unique and will be validated
    96  // on database schema for a key prefix byte.
    97  func (db *DB) NewIndex(name string, funcs IndexFuncs) (f Index, err error) {
    98  	id, err := db.schemaIndexPrefix(name)
    99  	if err != nil {
   100  		return f, err
   101  	}
   102  	prefix := []byte{id}
   103  	return Index{
   104  		db:     db,
   105  		prefix: prefix,
   106  		// This function adjusts Index LevelDB key
   107  		// by appending the provided index id byte.
   108  		// This is needed to avoid collisions between keys of different
   109  		// indexes as all index ids are unique.
   110  		encodeKeyFunc: func(e Item) (key []byte, err error) {
   111  			key, err = funcs.EncodeKey(e)
   112  			if err != nil {
   113  				return nil, err
   114  			}
   115  			return append(append(make([]byte, 0, len(key)+1), prefix...), key...), nil
   116  		},
   117  		// This function reverses the encodeKeyFunc constructed key
   118  		// to transparently work with index keys without their index ids.
   119  		// It assumes that index keys are prefixed with only one byte.
   120  		decodeKeyFunc: func(key []byte) (e Item, err error) {
   121  			return funcs.DecodeKey(key[1:])
   122  		},
   123  		encodeValueFunc: funcs.EncodeValue,
   124  		decodeValueFunc: funcs.DecodeValue,
   125  	}, nil
   126  }
   127  
   128  // Get accepts key fields represented as Item to retrieve a
   129  // value from the index and return maximum available information
   130  // from the index represented as another Item.
   131  func (f Index) Get(keyFields Item) (out Item, err error) {
   132  	key, err := f.encodeKeyFunc(keyFields)
   133  	if err != nil {
   134  		return out, err
   135  	}
   136  	value, err := f.db.Get(key)
   137  	if err != nil {
   138  		return out, err
   139  	}
   140  	out, err = f.decodeValueFunc(keyFields, value)
   141  	if err != nil {
   142  		return out, err
   143  	}
   144  	return out.Merge(keyFields), nil
   145  }
   146  
   147  // Put accepts Item to encode information from it
   148  // and save it to the database.
   149  func (f Index) Put(i Item) (err error) {
   150  	key, err := f.encodeKeyFunc(i)
   151  	if err != nil {
   152  		return err
   153  	}
   154  	value, err := f.encodeValueFunc(i)
   155  	if err != nil {
   156  		return err
   157  	}
   158  	return f.db.Put(key, value)
   159  }
   160  
   161  // PutInBatch is the same as Put method, but it just
   162  // saves the key/value pair to the batch instead
   163  // directly to the database.
   164  func (f Index) PutInBatch(batch *leveldb.Batch, i Item) (err error) {
   165  	key, err := f.encodeKeyFunc(i)
   166  	if err != nil {
   167  		return err
   168  	}
   169  	value, err := f.encodeValueFunc(i)
   170  	if err != nil {
   171  		return err
   172  	}
   173  	batch.Put(key, value)
   174  	return nil
   175  }
   176  
   177  // Delete accepts Item to remove a key/value pair
   178  // from the database based on its fields.
   179  func (f Index) Delete(keyFields Item) (err error) {
   180  	key, err := f.encodeKeyFunc(keyFields)
   181  	if err != nil {
   182  		return err
   183  	}
   184  	return f.db.Delete(key)
   185  }
   186  
   187  // DeleteInBatch is the same as Delete just the operation
   188  // is performed on the batch instead on the database.
   189  func (f Index) DeleteInBatch(batch *leveldb.Batch, keyFields Item) (err error) {
   190  	key, err := f.encodeKeyFunc(keyFields)
   191  	if err != nil {
   192  		return err
   193  	}
   194  	batch.Delete(key)
   195  	return nil
   196  }
   197  
   198  // IndexIterFunc is a callback on every Item that is decoded
   199  // by iterating on an Index keys.
   200  // By returning a true for stop variable, iteration will
   201  // stop, and by returning the error, that error will be
   202  // propagated to the called iterator method on Index.
   203  type IndexIterFunc func(item Item) (stop bool, err error)
   204  
   205  // IterateOptions defines optional parameters for Iterate function.
   206  type IterateOptions struct {
   207  	// StartFrom is the Item to start the iteration from.
   208  	StartFrom *Item
   209  	// If SkipStartFromItem is true, StartFrom item will not
   210  	// be iterated on.
   211  	SkipStartFromItem bool
   212  	// Iterate over items which keys have a common prefix.
   213  	Prefix []byte
   214  }
   215  
   216  // Iterate function iterates over keys of the Index.
   217  // If IterateOptions is nil, the iterations is over all keys.
   218  func (f Index) Iterate(fn IndexIterFunc, options *IterateOptions) (err error) {
   219  	if options == nil {
   220  		options = new(IterateOptions)
   221  	}
   222  	// construct a prefix with Index prefix and optional common key prefix
   223  	prefix := append(f.prefix, options.Prefix...)
   224  	// start from the prefix
   225  	startKey := prefix
   226  	if options.StartFrom != nil {
   227  		// start from the provided StartFrom Item key value
   228  		startKey, err = f.encodeKeyFunc(*options.StartFrom)
   229  		if err != nil {
   230  			return err
   231  		}
   232  	}
   233  	it := f.db.NewIterator()
   234  	defer it.Release()
   235  
   236  	// move the cursor to the start key
   237  	ok := it.Seek(startKey)
   238  	if !ok {
   239  		// stop iterator if seek has failed
   240  		return it.Error()
   241  	}
   242  	if options.SkipStartFromItem && bytes.Equal(startKey, it.Key()) {
   243  		// skip the start from Item if it is the first key
   244  		// and it is explicitly configured to skip it
   245  		ok = it.Next()
   246  	}
   247  	for ; ok; ok = it.Next() {
   248  		key := it.Key()
   249  		if !bytes.HasPrefix(key, prefix) {
   250  			break
   251  		}
   252  		// create a copy of key byte slice not to share leveldb underlaying slice array
   253  		keyItem, err := f.decodeKeyFunc(append([]byte(nil), key...))
   254  		if err != nil {
   255  			return err
   256  		}
   257  		// create a copy of value byte slice not to share leveldb underlaying slice array
   258  		valueItem, err := f.decodeValueFunc(keyItem, append([]byte(nil), it.Value()...))
   259  		if err != nil {
   260  			return err
   261  		}
   262  		stop, err := fn(keyItem.Merge(valueItem))
   263  		if err != nil {
   264  			return err
   265  		}
   266  		if stop {
   267  			break
   268  		}
   269  	}
   270  	return it.Error()
   271  }
   272  
   273  // Count returns the number of items in index.
   274  func (f Index) Count() (count int, err error) {
   275  	it := f.db.NewIterator()
   276  	defer it.Release()
   277  
   278  	for ok := it.Seek(f.prefix); ok; ok = it.Next() {
   279  		key := it.Key()
   280  		if key[0] != f.prefix[0] {
   281  			break
   282  		}
   283  		count++
   284  	}
   285  	return count, it.Error()
   286  }
   287  
   288  // CountFrom returns the number of items in index keys
   289  // starting from the key encoded from the provided Item.
   290  func (f Index) CountFrom(start Item) (count int, err error) {
   291  	startKey, err := f.encodeKeyFunc(start)
   292  	if err != nil {
   293  		return 0, err
   294  	}
   295  	it := f.db.NewIterator()
   296  	defer it.Release()
   297  
   298  	for ok := it.Seek(startKey); ok; ok = it.Next() {
   299  		key := it.Key()
   300  		if key[0] != f.prefix[0] {
   301  			break
   302  		}
   303  		count++
   304  	}
   305  	return count, it.Error()
   306  }