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 }