github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/core/rawdb/table.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package rawdb 19 20 import ( 21 "github.com/AigarNetwork/aigar/ethdb" 22 ) 23 24 // table is a wrapper around a database that prefixes each key access with a pre- 25 // configured string. 26 type table struct { 27 db ethdb.Database 28 prefix string 29 } 30 31 // NewTable returns a database object that prefixes all keys with a given string. 32 func NewTable(db ethdb.Database, prefix string) ethdb.Database { 33 return &table{ 34 db: db, 35 prefix: prefix, 36 } 37 } 38 39 // Close is a noop to implement the Database interface. 40 func (t *table) Close() error { 41 return nil 42 } 43 44 // Has retrieves if a prefixed version of a key is present in the database. 45 func (t *table) Has(key []byte) (bool, error) { 46 return t.db.Has(append([]byte(t.prefix), key...)) 47 } 48 49 // Get retrieves the given prefixed key if it's present in the database. 50 func (t *table) Get(key []byte) ([]byte, error) { 51 return t.db.Get(append([]byte(t.prefix), key...)) 52 } 53 54 // HasAncient is a noop passthrough that just forwards the request to the underlying 55 // database. 56 func (t *table) HasAncient(kind string, number uint64) (bool, error) { 57 return t.db.HasAncient(kind, number) 58 } 59 60 // Ancient is a noop passthrough that just forwards the request to the underlying 61 // database. 62 func (t *table) Ancient(kind string, number uint64) ([]byte, error) { 63 return t.db.Ancient(kind, number) 64 } 65 66 // Ancients is a noop passthrough that just forwards the request to the underlying 67 // database. 68 func (t *table) Ancients() (uint64, error) { 69 return t.db.Ancients() 70 } 71 72 // AncientSize is a noop passthrough that just forwards the request to the underlying 73 // database. 74 func (t *table) AncientSize(kind string) (uint64, error) { 75 return t.db.AncientSize(kind) 76 } 77 78 // AppendAncient is a noop passthrough that just forwards the request to the underlying 79 // database. 80 func (t *table) AppendAncient(number uint64, hash, header, body, receipts, td []byte) error { 81 return t.db.AppendAncient(number, hash, header, body, receipts, td) 82 } 83 84 // TruncateAncients is a noop passthrough that just forwards the request to the underlying 85 // database. 86 func (t *table) TruncateAncients(items uint64) error { 87 return t.db.TruncateAncients(items) 88 } 89 90 // Sync is a noop passthrough that just forwards the request to the underlying 91 // database. 92 func (t *table) Sync() error { 93 return t.db.Sync() 94 } 95 96 // Put inserts the given value into the database at a prefixed version of the 97 // provided key. 98 func (t *table) Put(key []byte, value []byte) error { 99 return t.db.Put(append([]byte(t.prefix), key...), value) 100 } 101 102 // Delete removes the given prefixed key from the database. 103 func (t *table) Delete(key []byte) error { 104 return t.db.Delete(append([]byte(t.prefix), key...)) 105 } 106 107 // NewIterator creates a binary-alphabetical iterator over the entire keyspace 108 // contained within the database. 109 func (t *table) NewIterator() ethdb.Iterator { 110 return t.NewIteratorWithPrefix(nil) 111 } 112 113 // NewIteratorWithStart creates a binary-alphabetical iterator over a subset of 114 // database content starting at a particular initial key (or after, if it does 115 // not exist). 116 func (t *table) NewIteratorWithStart(start []byte) ethdb.Iterator { 117 return t.db.NewIteratorWithStart(start) 118 } 119 120 // NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset 121 // of database content with a particular key prefix. 122 func (t *table) NewIteratorWithPrefix(prefix []byte) ethdb.Iterator { 123 return t.db.NewIteratorWithPrefix(append([]byte(t.prefix), prefix...)) 124 } 125 126 // Stat returns a particular internal stat of the database. 127 func (t *table) Stat(property string) (string, error) { 128 return t.db.Stat(property) 129 } 130 131 // Compact flattens the underlying data store for the given key range. In essence, 132 // deleted and overwritten versions are discarded, and the data is rearranged to 133 // reduce the cost of operations needed to access them. 134 // 135 // A nil start is treated as a key before all keys in the data store; a nil limit 136 // is treated as a key after all keys in the data store. If both is nil then it 137 // will compact entire data store. 138 func (t *table) Compact(start []byte, limit []byte) error { 139 // If no start was specified, use the table prefix as the first value 140 if start == nil { 141 start = []byte(t.prefix) 142 } 143 // If no limit was specified, use the first element not matching the prefix 144 // as the limit 145 if limit == nil { 146 limit = []byte(t.prefix) 147 for i := len(limit) - 1; i >= 0; i-- { 148 // Bump the current character, stopping if it doesn't overflow 149 limit[i]++ 150 if limit[i] > 0 { 151 break 152 } 153 // Character overflown, proceed to the next or nil if the last 154 if i == 0 { 155 limit = nil 156 } 157 } 158 } 159 // Range correctly calculated based on table prefix, delegate down 160 return t.db.Compact(start, limit) 161 } 162 163 // NewBatch creates a write-only database that buffers changes to its host db 164 // until a final write is called, each operation prefixing all keys with the 165 // pre-configured string. 166 func (t *table) NewBatch() ethdb.Batch { 167 return &tableBatch{t.db.NewBatch(), t.prefix} 168 } 169 170 // tableBatch is a wrapper around a database batch that prefixes each key access 171 // with a pre-configured string. 172 type tableBatch struct { 173 batch ethdb.Batch 174 prefix string 175 } 176 177 // Put inserts the given value into the batch for later committing. 178 func (b *tableBatch) Put(key, value []byte) error { 179 return b.batch.Put(append([]byte(b.prefix), key...), value) 180 } 181 182 // Delete inserts the a key removal into the batch for later committing. 183 func (b *tableBatch) Delete(key []byte) error { 184 return b.batch.Delete(append([]byte(b.prefix), key...)) 185 } 186 187 // ValueSize retrieves the amount of data queued up for writing. 188 func (b *tableBatch) ValueSize() int { 189 return b.batch.ValueSize() 190 } 191 192 // Write flushes any accumulated data to disk. 193 func (b *tableBatch) Write() error { 194 return b.batch.Write() 195 } 196 197 // Reset resets the batch for reuse. 198 func (b *tableBatch) Reset() { 199 b.batch.Reset() 200 } 201 202 // Replay replays the batch contents. 203 func (b *tableBatch) Replay(w ethdb.KeyValueWriter) error { 204 return b.batch.Replay(w) 205 }