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