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