github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/shed/index.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:44</date> 10 //</624450117914595328> 11 12 13 package shed 14 15 import ( 16 "bytes" 17 18 "github.com/syndtr/goleveldb/leveldb" 19 ) 20 21 //项目包含与群块数据和元数据相关的字段。 22 //群存储和操作所需的所有信息 23 //必须在此处定义该存储。 24 //这种结构在逻辑上与群存储相连, 25 //这个包中唯一没有被概括的部分, 26 //主要是出于性能原因。 27 // 28 //项是用于检索、存储和编码的类型 29 //块数据和元数据。它作为参数传递给索引编码 30 //函数、获取函数和Put函数。 31 //但是,它还返回来自get函数调用的附加数据 32 //作为迭代器函数定义中的参数。 33 type Item struct { 34 Address []byte 35 Data []byte 36 AccessTimestamp int64 37 StoreTimestamp int64 38 //useMockStore是用于标识 39 //join函数中字段的未设置状态。 40 UseMockStore *bool 41 } 42 43 //合并是一个帮助器方法,用于构造新的 44 //用默认值填充字段 45 //一个特定项的值来自另一个项。 46 func (i Item) Merge(i2 Item) (new Item) { 47 if i.Address == nil { 48 i.Address = i2.Address 49 } 50 if i.Data == nil { 51 i.Data = i2.Data 52 } 53 if i.AccessTimestamp == 0 { 54 i.AccessTimestamp = i2.AccessTimestamp 55 } 56 if i.StoreTimestamp == 0 { 57 i.StoreTimestamp = i2.StoreTimestamp 58 } 59 if i.UseMockStore == nil { 60 i.UseMockStore = i2.UseMockStore 61 } 62 return i 63 } 64 65 //索引表示一组具有公共 66 //前缀。它具有编码和解码密钥和值的功能 67 //要对包含以下内容的已保存数据提供透明操作: 68 //-获取特定项目 69 //-保存特定项目 70 //-在已排序的级别数据库键上迭代 71 //它实现了indexIteratorInterface接口。 72 type Index struct { 73 db *DB 74 prefix []byte 75 encodeKeyFunc func(fields Item) (key []byte, err error) 76 decodeKeyFunc func(key []byte) (e Item, err error) 77 encodeValueFunc func(fields Item) (value []byte, err error) 78 decodeValueFunc func(keyFields Item, value []byte) (e Item, err error) 79 } 80 81 //indexfuncs结构定义了用于编码和解码的函数 82 //特定索引的LevelDB键和值。 83 type IndexFuncs struct { 84 EncodeKey func(fields Item) (key []byte, err error) 85 DecodeKey func(key []byte) (e Item, err error) 86 EncodeValue func(fields Item) (value []byte, err error) 87 DecodeValue func(keyFields Item, value []byte) (e Item, err error) 88 } 89 90 //new index返回一个新的索引实例,该实例具有定义的名称和 91 //编码函数。名称必须唯一并将被验证 92 //对于键前缀字节的数据库架构。 93 func (db *DB) NewIndex(name string, funcs IndexFuncs) (f Index, err error) { 94 id, err := db.schemaIndexPrefix(name) 95 if err != nil { 96 return f, err 97 } 98 prefix := []byte{id} 99 return Index{ 100 db: db, 101 prefix: prefix, 102 //此函数用于调整索引级别DB键 103 //通过附加提供的索引ID字节。 104 //这是为了避免不同钥匙之间的碰撞 105 //索引,因为所有索引ID都是唯一的。 106 encodeKeyFunc: func(e Item) (key []byte, err error) { 107 key, err = funcs.EncodeKey(e) 108 if err != nil { 109 return nil, err 110 } 111 return append(append(make([]byte, 0, len(key)+1), prefix...), key...), nil 112 }, 113 //此函数用于反转EncodeKeyFunc构造的键 114 //在没有索引ID的情况下透明地使用索引键。 115 //它假定索引键的前缀只有一个字节。 116 decodeKeyFunc: func(key []byte) (e Item, err error) { 117 return funcs.DecodeKey(key[1:]) 118 }, 119 encodeValueFunc: funcs.EncodeValue, 120 decodeValueFunc: funcs.DecodeValue, 121 }, nil 122 } 123 124 //get接受表示为要检索的项的键字段 125 //索引中的值并返回最大可用信息 126 //从另一项表示的索引。 127 func (f Index) Get(keyFields Item) (out Item, err error) { 128 key, err := f.encodeKeyFunc(keyFields) 129 if err != nil { 130 return out, err 131 } 132 value, err := f.db.Get(key) 133 if err != nil { 134 return out, err 135 } 136 out, err = f.decodeValueFunc(keyFields, value) 137 if err != nil { 138 return out, err 139 } 140 return out.Merge(keyFields), nil 141 } 142 143 //放置接受项以对来自它的信息进行编码 144 //并保存到数据库。 145 func (f Index) Put(i Item) (err error) { 146 key, err := f.encodeKeyFunc(i) 147 if err != nil { 148 return err 149 } 150 value, err := f.encodeValueFunc(i) 151 if err != nil { 152 return err 153 } 154 return f.db.Put(key, value) 155 } 156 157 //putinbatch与put方法相同,但它只是 158 //将键/值对保存到批处理中 159 //直接到数据库。 160 func (f Index) PutInBatch(batch *leveldb.Batch, i Item) (err error) { 161 key, err := f.encodeKeyFunc(i) 162 if err != nil { 163 return err 164 } 165 value, err := f.encodeValueFunc(i) 166 if err != nil { 167 return err 168 } 169 batch.Put(key, value) 170 return nil 171 } 172 173 //删除接受项以删除键/值对 174 //基于其字段的数据库。 175 func (f Index) Delete(keyFields Item) (err error) { 176 key, err := f.encodeKeyFunc(keyFields) 177 if err != nil { 178 return err 179 } 180 return f.db.Delete(key) 181 } 182 183 //deleteinbatch与只删除操作相同 184 //在批处理上而不是在数据库上执行。 185 func (f Index) DeleteInBatch(batch *leveldb.Batch, keyFields Item) (err error) { 186 key, err := f.encodeKeyFunc(keyFields) 187 if err != nil { 188 return err 189 } 190 batch.Delete(key) 191 return nil 192 } 193 194 //indexiterfunc是对解码的每个项的回调 195 //通过迭代索引键。 196 //通过返回一个true for stop变量,迭代将 197 //停止,返回错误,该错误将 198 //传播到索引上被调用的迭代器方法。 199 type IndexIterFunc func(item Item) (stop bool, err error) 200 201 //迭代器定义迭代器函数的可选参数。 202 type IterateOptions struct { 203 //StartFrom是从中开始迭代的项。 204 StartFrom *Item 205 //如果skipStartFromItem为true,则StartFrom项不会 206 //重复进行。 207 SkipStartFromItem bool 208 //迭代键具有公共前缀的项。 209 Prefix []byte 210 } 211 212 //迭代函数迭代索引的键。 213 //如果迭代次数为零,则迭代次数将覆盖所有键。 214 func (f Index) Iterate(fn IndexIterFunc, options *IterateOptions) (err error) { 215 if options == nil { 216 options = new(IterateOptions) 217 } 218 //用索引前缀和可选的公共密钥前缀构造前缀 219 prefix := append(f.prefix, options.Prefix...) 220 //从前缀开始 221 startKey := prefix 222 if options.StartFrom != nil { 223 //从提供的StartFrom项键值开始 224 startKey, err = f.encodeKeyFunc(*options.StartFrom) 225 if err != nil { 226 return err 227 } 228 } 229 it := f.db.NewIterator() 230 defer it.Release() 231 232 //将光标移到开始键 233 ok := it.Seek(startKey) 234 if !ok { 235 //如果查找失败,则停止迭代器 236 return it.Error() 237 } 238 if options.SkipStartFromItem && bytes.Equal(startKey, it.Key()) { 239 //如果是第一个键,则跳过“从项目开始” 240 //它被明确配置为跳过它 241 ok = it.Next() 242 } 243 for ; ok; ok = it.Next() { 244 key := it.Key() 245 if !bytes.HasPrefix(key, prefix) { 246 break 247 } 248 //创建一个键字节切片的副本,不共享级别数据库基线切片数组 249 keyItem, err := f.decodeKeyFunc(append([]byte(nil), key...)) 250 if err != nil { 251 return err 252 } 253 //创建一个值字节切片的副本,不共享级别数据库基线切片数组 254 valueItem, err := f.decodeValueFunc(keyItem, append([]byte(nil), it.Value()...)) 255 if err != nil { 256 return err 257 } 258 stop, err := fn(keyItem.Merge(valueItem)) 259 if err != nil { 260 return err 261 } 262 if stop { 263 break 264 } 265 } 266 return it.Error() 267 } 268 269 //count返回索引中的项数。 270 func (f Index) Count() (count int, err error) { 271 it := f.db.NewIterator() 272 defer it.Release() 273 274 for ok := it.Seek(f.prefix); ok; ok = it.Next() { 275 key := it.Key() 276 if key[0] != f.prefix[0] { 277 break 278 } 279 count++ 280 } 281 return count, it.Error() 282 } 283 284 //CountFrom返回索引键中的项数 285 //从从提供的项编码的密钥开始。 286 func (f Index) CountFrom(start Item) (count int, err error) { 287 startKey, err := f.encodeKeyFunc(start) 288 if err != nil { 289 return 0, err 290 } 291 it := f.db.NewIterator() 292 defer it.Release() 293 294 for ok := it.Seek(startKey); ok; ok = it.Next() { 295 key := it.Key() 296 if key[0] != f.prefix[0] { 297 break 298 } 299 count++ 300 } 301 return count, it.Error() 302 } 303