github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/storage/mock/db/db.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:45</date>
    10  //</624450120414400512>
    11  
    12  
    13  //包DB实现了一个模拟存储,它将所有块数据保存在LevelDB数据库中。
    14  package db
    15  
    16  import (
    17  	"archive/tar"
    18  	"bytes"
    19  	"encoding/json"
    20  	"io"
    21  	"io/ioutil"
    22  
    23  	"github.com/syndtr/goleveldb/leveldb"
    24  	"github.com/syndtr/goleveldb/leveldb/util"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/swarm/storage/mock"
    28  )
    29  
    30  //GlobalStore包含正在存储的LevelDB数据库
    31  //所有群节点的块数据。
    32  //使用关闭方法关闭GlobalStore需要
    33  //释放数据库使用的资源。
    34  type GlobalStore struct {
    35  	db *leveldb.DB
    36  }
    37  
    38  //NewGlobalStore创建了一个新的GlobalStore实例。
    39  func NewGlobalStore(path string) (s *GlobalStore, err error) {
    40  	db, err := leveldb.OpenFile(path, nil)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	return &GlobalStore{
    45  		db: db,
    46  	}, nil
    47  }
    48  
    49  //close释放基础级别db使用的资源。
    50  func (s *GlobalStore) Close() error {
    51  	return s.db.Close()
    52  }
    53  
    54  //new nodestore返回一个新的nodestore实例,用于检索和存储
    55  //仅对地址为的节点进行数据块处理。
    56  func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore {
    57  	return mock.NewNodeStore(addr, s)
    58  }
    59  
    60  //如果节点存在键为的块,则get返回块数据
    61  //地址地址。
    62  func (s *GlobalStore) Get(addr common.Address, key []byte) (data []byte, err error) {
    63  	has, err := s.db.Has(nodeDBKey(addr, key), nil)
    64  	if err != nil {
    65  		return nil, mock.ErrNotFound
    66  	}
    67  	if !has {
    68  		return nil, mock.ErrNotFound
    69  	}
    70  	data, err = s.db.Get(dataDBKey(key), nil)
    71  	if err == leveldb.ErrNotFound {
    72  		err = mock.ErrNotFound
    73  	}
    74  	return
    75  }
    76  
    77  //Put保存带有地址addr的节点的块数据。
    78  func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error {
    79  	batch := new(leveldb.Batch)
    80  	batch.Put(nodeDBKey(addr, key), nil)
    81  	batch.Put(dataDBKey(key), data)
    82  	return s.db.Write(batch, nil)
    83  }
    84  
    85  //删除删除对地址为addr的节点的块引用。
    86  func (s *GlobalStore) Delete(addr common.Address, key []byte) error {
    87  	batch := new(leveldb.Batch)
    88  	batch.Delete(nodeDBKey(addr, key))
    89  	return s.db.Write(batch, nil)
    90  }
    91  
    92  //haskey返回带有addr的节点是否包含键。
    93  func (s *GlobalStore) HasKey(addr common.Address, key []byte) bool {
    94  	has, err := s.db.Has(nodeDBKey(addr, key), nil)
    95  	if err != nil {
    96  		has = false
    97  	}
    98  	return has
    99  }
   100  
   101  //import从包含导出块数据的读卡器读取tar存档。
   102  //它返回导入的块的数量和错误。
   103  func (s *GlobalStore) Import(r io.Reader) (n int, err error) {
   104  	tr := tar.NewReader(r)
   105  
   106  	for {
   107  		hdr, err := tr.Next()
   108  		if err != nil {
   109  			if err == io.EOF {
   110  				break
   111  			}
   112  			return n, err
   113  		}
   114  
   115  		data, err := ioutil.ReadAll(tr)
   116  		if err != nil {
   117  			return n, err
   118  		}
   119  
   120  		var c mock.ExportedChunk
   121  		if err = json.Unmarshal(data, &c); err != nil {
   122  			return n, err
   123  		}
   124  
   125  		batch := new(leveldb.Batch)
   126  		for _, addr := range c.Addrs {
   127  			batch.Put(nodeDBKeyHex(addr, hdr.Name), nil)
   128  		}
   129  
   130  		batch.Put(dataDBKey(common.Hex2Bytes(hdr.Name)), c.Data)
   131  		if err = s.db.Write(batch, nil); err != nil {
   132  			return n, err
   133  		}
   134  
   135  		n++
   136  	}
   137  	return n, err
   138  }
   139  
   140  //将包含所有块数据的tar存档导出到写入程序
   141  //商店。它返回导出的块的数量和错误。
   142  func (s *GlobalStore) Export(w io.Writer) (n int, err error) {
   143  	tw := tar.NewWriter(w)
   144  	defer tw.Close()
   145  
   146  	buf := bytes.NewBuffer(make([]byte, 0, 1024))
   147  	encoder := json.NewEncoder(buf)
   148  
   149  	iter := s.db.NewIterator(util.BytesPrefix(nodeKeyPrefix), nil)
   150  	defer iter.Release()
   151  
   152  	var currentKey string
   153  	var addrs []common.Address
   154  
   155  	saveChunk := func(hexKey string) error {
   156  		key := common.Hex2Bytes(hexKey)
   157  
   158  		data, err := s.db.Get(dataDBKey(key), nil)
   159  		if err != nil {
   160  			return err
   161  		}
   162  
   163  		buf.Reset()
   164  		if err = encoder.Encode(mock.ExportedChunk{
   165  			Addrs: addrs,
   166  			Data:  data,
   167  		}); err != nil {
   168  			return err
   169  		}
   170  
   171  		d := buf.Bytes()
   172  		hdr := &tar.Header{
   173  			Name: hexKey,
   174  			Mode: 0644,
   175  			Size: int64(len(d)),
   176  		}
   177  		if err := tw.WriteHeader(hdr); err != nil {
   178  			return err
   179  		}
   180  		if _, err := tw.Write(d); err != nil {
   181  			return err
   182  		}
   183  		n++
   184  		return nil
   185  	}
   186  
   187  	for iter.Next() {
   188  		k := bytes.TrimPrefix(iter.Key(), nodeKeyPrefix)
   189  		i := bytes.Index(k, []byte("-"))
   190  		if i < 0 {
   191  			continue
   192  		}
   193  		hexKey := string(k[:i])
   194  
   195  		if currentKey == "" {
   196  			currentKey = hexKey
   197  		}
   198  
   199  		if hexKey != currentKey {
   200  			if err = saveChunk(currentKey); err != nil {
   201  				return n, err
   202  			}
   203  
   204  			addrs = addrs[:0]
   205  		}
   206  
   207  		currentKey = hexKey
   208  		addrs = append(addrs, common.BytesToAddress(k[i:]))
   209  	}
   210  
   211  	if len(addrs) > 0 {
   212  		if err = saveChunk(currentKey); err != nil {
   213  			return n, err
   214  		}
   215  	}
   216  
   217  	return n, err
   218  }
   219  
   220  var (
   221  	nodeKeyPrefix = []byte("node-")
   222  	dataKeyPrefix = []byte("data-")
   223  )
   224  
   225  //nodedbkey为键/节点映射构造数据库键。
   226  func nodeDBKey(addr common.Address, key []byte) []byte {
   227  	return nodeDBKeyHex(addr, common.Bytes2Hex(key))
   228  }
   229  
   230  //nodedbkeyhex为键/节点映射构造数据库键
   231  //使用键的十六进制字符串表示形式。
   232  func nodeDBKeyHex(addr common.Address, hexKey string) []byte {
   233  	return append(append(nodeKeyPrefix, []byte(hexKey+"-")...), addr[:]...)
   234  }
   235  
   236  //datadbkey为键/数据存储构造数据库键。
   237  func dataDBKey(key []byte) []byte {
   238  	return append(dataKeyPrefix, key...)
   239  }
   240