github.com/alexdevranger/node-1.8.27@v0.0.0-20221128213301-aa5841e41d2d/swarm/storage/mock/db/db.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-dubxcoin library. 3 // 4 // The go-dubxcoin library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-dubxcoin library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-dubxcoin library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package db implements a mock store that keeps all chunk data in LevelDB database. 18 package db 19 20 import ( 21 "archive/tar" 22 "bytes" 23 "encoding/json" 24 "io" 25 "io/ioutil" 26 27 "github.com/syndtr/goleveldb/leveldb" 28 "github.com/syndtr/goleveldb/leveldb/util" 29 30 "github.com/alexdevranger/node-1.8.27/common" 31 "github.com/alexdevranger/node-1.8.27/swarm/storage/mock" 32 ) 33 34 // GlobalStore contains the LevelDB database that is storing 35 // chunk data for all swarm nodes. 36 // Closing the GlobalStore with Close method is required to 37 // release resources used by the database. 38 type GlobalStore struct { 39 db *leveldb.DB 40 } 41 42 // NewGlobalStore creates a new instance of GlobalStore. 43 func NewGlobalStore(path string) (s *GlobalStore, err error) { 44 db, err := leveldb.OpenFile(path, nil) 45 if err != nil { 46 return nil, err 47 } 48 return &GlobalStore{ 49 db: db, 50 }, nil 51 } 52 53 // Close releases the resources used by the underlying LevelDB. 54 func (s *GlobalStore) Close() error { 55 return s.db.Close() 56 } 57 58 // NewNodeStore returns a new instance of NodeStore that retrieves and stores 59 // chunk data only for a node with address addr. 60 func (s *GlobalStore) NewNodeStore(addr common.Address) *mock.NodeStore { 61 return mock.NewNodeStore(addr, s) 62 } 63 64 // Get returns chunk data if the chunk with key exists for node 65 // on address addr. 66 func (s *GlobalStore) Get(addr common.Address, key []byte) (data []byte, err error) { 67 has, err := s.db.Has(nodeDBKey(addr, key), nil) 68 if err != nil { 69 return nil, mock.ErrNotFound 70 } 71 if !has { 72 return nil, mock.ErrNotFound 73 } 74 data, err = s.db.Get(dataDBKey(key), nil) 75 if err == leveldb.ErrNotFound { 76 err = mock.ErrNotFound 77 } 78 return 79 } 80 81 // Put saves the chunk data for node with address addr. 82 func (s *GlobalStore) Put(addr common.Address, key []byte, data []byte) error { 83 batch := new(leveldb.Batch) 84 batch.Put(nodeDBKey(addr, key), nil) 85 batch.Put(dataDBKey(key), data) 86 return s.db.Write(batch, nil) 87 } 88 89 // Delete removes the chunk reference to node with address addr. 90 func (s *GlobalStore) Delete(addr common.Address, key []byte) error { 91 batch := new(leveldb.Batch) 92 batch.Delete(nodeDBKey(addr, key)) 93 return s.db.Write(batch, nil) 94 } 95 96 // HasKey returns whether a node with addr contains the key. 97 func (s *GlobalStore) HasKey(addr common.Address, key []byte) bool { 98 has, err := s.db.Has(nodeDBKey(addr, key), nil) 99 if err != nil { 100 has = false 101 } 102 return has 103 } 104 105 // Import reads tar archive from a reader that contains exported chunk data. 106 // It returns the number of chunks imported and an error. 107 func (s *GlobalStore) Import(r io.Reader) (n int, err error) { 108 tr := tar.NewReader(r) 109 110 for { 111 hdr, err := tr.Next() 112 if err != nil { 113 if err == io.EOF { 114 break 115 } 116 return n, err 117 } 118 119 data, err := ioutil.ReadAll(tr) 120 if err != nil { 121 return n, err 122 } 123 124 var c mock.ExportedChunk 125 if err = json.Unmarshal(data, &c); err != nil { 126 return n, err 127 } 128 129 batch := new(leveldb.Batch) 130 for _, addr := range c.Addrs { 131 batch.Put(nodeDBKeyHex(addr, hdr.Name), nil) 132 } 133 134 batch.Put(dataDBKey(common.Hex2Bytes(hdr.Name)), c.Data) 135 if err = s.db.Write(batch, nil); err != nil { 136 return n, err 137 } 138 139 n++ 140 } 141 return n, err 142 } 143 144 // Export writes to a writer a tar archive with all chunk data from 145 // the store. It returns the number fo chunks exported and an error. 146 func (s *GlobalStore) Export(w io.Writer) (n int, err error) { 147 tw := tar.NewWriter(w) 148 defer tw.Close() 149 150 buf := bytes.NewBuffer(make([]byte, 0, 1024)) 151 encoder := json.NewEncoder(buf) 152 153 iter := s.db.NewIterator(util.BytesPrefix(nodeKeyPrefix), nil) 154 defer iter.Release() 155 156 var currentKey string 157 var addrs []common.Address 158 159 saveChunk := func(hexKey string) error { 160 key := common.Hex2Bytes(hexKey) 161 162 data, err := s.db.Get(dataDBKey(key), nil) 163 if err != nil { 164 return err 165 } 166 167 buf.Reset() 168 if err = encoder.Encode(mock.ExportedChunk{ 169 Addrs: addrs, 170 Data: data, 171 }); err != nil { 172 return err 173 } 174 175 d := buf.Bytes() 176 hdr := &tar.Header{ 177 Name: hexKey, 178 Mode: 0644, 179 Size: int64(len(d)), 180 } 181 if err := tw.WriteHeader(hdr); err != nil { 182 return err 183 } 184 if _, err := tw.Write(d); err != nil { 185 return err 186 } 187 n++ 188 return nil 189 } 190 191 for iter.Next() { 192 k := bytes.TrimPrefix(iter.Key(), nodeKeyPrefix) 193 i := bytes.Index(k, []byte("-")) 194 if i < 0 { 195 continue 196 } 197 hexKey := string(k[:i]) 198 199 if currentKey == "" { 200 currentKey = hexKey 201 } 202 203 if hexKey != currentKey { 204 if err = saveChunk(currentKey); err != nil { 205 return n, err 206 } 207 208 addrs = addrs[:0] 209 } 210 211 currentKey = hexKey 212 addrs = append(addrs, common.BytesToAddress(k[i:])) 213 } 214 215 if len(addrs) > 0 { 216 if err = saveChunk(currentKey); err != nil { 217 return n, err 218 } 219 } 220 221 return n, err 222 } 223 224 var ( 225 nodeKeyPrefix = []byte("node-") 226 dataKeyPrefix = []byte("data-") 227 ) 228 229 // nodeDBKey constructs a database key for key/node mappings. 230 func nodeDBKey(addr common.Address, key []byte) []byte { 231 return nodeDBKeyHex(addr, common.Bytes2Hex(key)) 232 } 233 234 // nodeDBKeyHex constructs a database key for key/node mappings 235 // using the hexadecimal string representation of the key. 236 func nodeDBKeyHex(addr common.Address, hexKey string) []byte { 237 return append(append(nodeKeyPrefix, []byte(hexKey+"-")...), addr[:]...) 238 } 239 240 // dataDBkey constructs a database key for key/data storage. 241 func dataDBKey(key []byte) []byte { 242 return append(dataKeyPrefix, key...) 243 }