github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/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 12:09:49</date> 10 //</624342681916542976> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 // 29 package db 30 31 import ( 32 "archive/tar" 33 "bytes" 34 "encoding/json" 35 "io" 36 "io/ioutil" 37 38 "github.com/syndtr/goleveldb/leveldb" 39 "github.com/syndtr/goleveldb/leveldb/util" 40 41 "github.com/ethereum/go-ethereum/common" 42 "github.com/ethereum/go-ethereum/swarm/storage/mock" 43 ) 44 45 // 46 // 47 // 48 // 49 type GlobalStore struct { 50 db *leveldb.DB 51 } 52 53 // 54 func NewGlobalStore(path string) (s *GlobalStore, err error) { 55 db, err := leveldb.OpenFile(path, nil) 56 if err != nil { 57 return nil, err 58 } 59 return &GlobalStore{ 60 db: db, 61 }, nil 62 } 63 64 // 65 func (s *GlobalStore) Close() error { 66 return s.db.Close() 67 } 68 69 // 70 // 71 func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore { 72 return mock.NewNodeStore(addr, s) 73 } 74 75 // 76 // 77 func (s *GlobalStore) Get(addr common.Address, key []byte) (data []byte, err error) { 78 has, err := s.db.Has(nodeDBKey(addr, key), nil) 79 if err != nil { 80 return nil, mock.ErrNotFound 81 } 82 if !has { 83 return nil, mock.ErrNotFound 84 } 85 data, err = s.db.Get(dataDBKey(key), nil) 86 if err == leveldb.ErrNotFound { 87 err = mock.ErrNotFound 88 } 89 return 90 } 91 92 // 93 func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error { 94 batch := new(leveldb.Batch) 95 batch.Put(nodeDBKey(addr, key), nil) 96 batch.Put(dataDBKey(key), data) 97 return s.db.Write(batch, nil) 98 } 99 100 // 101 func (s *GlobalStore) HasKey(addr common.Address, key []byte) bool { 102 has, err := s.db.Has(nodeDBKey(addr, key), nil) 103 if err != nil { 104 has = false 105 } 106 return has 107 } 108 109 // 110 // 111 func (s *GlobalStore) Import(r io.Reader) (n int, err error) { 112 tr := tar.NewReader(r) 113 114 for { 115 hdr, err := tr.Next() 116 if err != nil { 117 if err == io.EOF { 118 break 119 } 120 return n, err 121 } 122 123 data, err := ioutil.ReadAll(tr) 124 if err != nil { 125 return n, err 126 } 127 128 var c mock.ExportedChunk 129 if err = json.Unmarshal(data, &c); err != nil { 130 return n, err 131 } 132 133 batch := new(leveldb.Batch) 134 for _, addr := range c.Addrs { 135 batch.Put(nodeDBKeyHex(addr, hdr.Name), nil) 136 } 137 138 batch.Put(dataDBKey(common.Hex2Bytes(hdr.Name)), c.Data) 139 if err = s.db.Write(batch, nil); err != nil { 140 return n, err 141 } 142 143 n++ 144 } 145 return n, err 146 } 147 148 // 149 // 150 func (s *GlobalStore) Export(w io.Writer) (n int, err error) { 151 tw := tar.NewWriter(w) 152 defer tw.Close() 153 154 buf := bytes.NewBuffer(make([]byte, 0, 1024)) 155 encoder := json.NewEncoder(buf) 156 157 iter := s.db.NewIterator(util.BytesPrefix(nodeKeyPrefix), nil) 158 defer iter.Release() 159 160 var currentKey string 161 var addrs []common.Address 162 163 saveChunk := func(hexKey string) error { 164 key := common.Hex2Bytes(hexKey) 165 166 data, err := s.db.Get(dataDBKey(key), nil) 167 if err != nil { 168 return err 169 } 170 171 buf.Reset() 172 if err = encoder.Encode(mock.ExportedChunk{ 173 Addrs: addrs, 174 Data: data, 175 }); err != nil { 176 return err 177 } 178 179 d := buf.Bytes() 180 hdr := &tar.Header{ 181 Name: hexKey, 182 Mode: 0644, 183 Size: int64(len(d)), 184 } 185 if err := tw.WriteHeader(hdr); err != nil { 186 return err 187 } 188 if _, err := tw.Write(d); err != nil { 189 return err 190 } 191 n++ 192 return nil 193 } 194 195 for iter.Next() { 196 k := bytes.TrimPrefix(iter.Key(), nodeKeyPrefix) 197 i := bytes.Index(k, []byte("-")) 198 if i < 0 { 199 continue 200 } 201 hexKey := string(k[:i]) 202 203 if currentKey == "" { 204 currentKey = hexKey 205 } 206 207 if hexKey != currentKey { 208 if err = saveChunk(currentKey); err != nil { 209 return n, err 210 } 211 212 addrs = addrs[:0] 213 } 214 215 currentKey = hexKey 216 addrs = append(addrs, common.BytesToAddress(k[i:])) 217 } 218 219 if len(addrs) > 0 { 220 if err = saveChunk(currentKey); err != nil { 221 return n, err 222 } 223 } 224 225 return n, err 226 } 227 228 var ( 229 nodeKeyPrefix = []byte("node-") 230 dataKeyPrefix = []byte("data-") 231 ) 232 233 // 234 func nodeDBKey(addr common.Address, key []byte) []byte { 235 return nodeDBKeyHex(addr, common.Bytes2Hex(key)) 236 } 237 238 // 239 // 240 func nodeDBKeyHex(addr common.Address, hexKey string) []byte { 241 return append(append(nodeKeyPrefix, []byte(hexKey+"-")...), addr[:]...) 242 } 243 244 // 245 func dataDBKey(key []byte) []byte { 246 return append(dataKeyPrefix, key...) 247 } 248