github.com/alanchchen/go-ethereum@v1.6.6-0.20170601190819-6171d01b1195/swarm/storage/types.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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-ethereum 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-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package storage 18 19 import ( 20 "bytes" 21 "crypto" 22 "fmt" 23 "hash" 24 "io" 25 "sync" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/crypto/sha3" 29 ) 30 31 type Hasher func() hash.Hash 32 33 // Peer is the recorded as Source on the chunk 34 // should probably not be here? but network should wrap chunk object 35 type Peer interface{} 36 37 type Key []byte 38 39 func (x Key) Size() uint { 40 return uint(len(x)) 41 } 42 43 func (x Key) isEqual(y Key) bool { 44 return bytes.Equal(x, y) 45 } 46 47 func (h Key) bits(i, j uint) uint { 48 ii := i >> 3 49 jj := i & 7 50 if ii >= h.Size() { 51 return 0 52 } 53 54 if jj+j <= 8 { 55 return uint((h[ii] >> jj) & ((1 << j) - 1)) 56 } 57 58 res := uint(h[ii] >> jj) 59 jj = 8 - jj 60 j -= jj 61 for j != 0 { 62 ii++ 63 if j < 8 { 64 res += uint(h[ii]&((1<<j)-1)) << jj 65 return res 66 } 67 res += uint(h[ii]) << jj 68 jj += 8 69 j -= 8 70 } 71 return res 72 } 73 74 func IsZeroKey(key Key) bool { 75 return len(key) == 0 || bytes.Equal(key, ZeroKey) 76 } 77 78 var ZeroKey = Key(common.Hash{}.Bytes()) 79 80 func MakeHashFunc(hash string) Hasher { 81 switch hash { 82 case "SHA256": 83 return crypto.SHA256.New 84 case "SHA3": 85 return sha3.NewKeccak256 86 } 87 return nil 88 } 89 90 func (key Key) Hex() string { 91 return fmt.Sprintf("%064x", []byte(key[:])) 92 } 93 94 func (key Key) Log() string { 95 if len(key[:]) < 4 { 96 return fmt.Sprintf("%x", []byte(key[:])) 97 } 98 return fmt.Sprintf("%08x", []byte(key[:4])) 99 } 100 101 func (key Key) String() string { 102 return fmt.Sprintf("%064x", []byte(key)[:]) 103 } 104 105 func (key Key) MarshalJSON() (out []byte, err error) { 106 return []byte(`"` + key.String() + `"`), nil 107 } 108 109 func (key *Key) UnmarshalJSON(value []byte) error { 110 s := string(value) 111 *key = make([]byte, 32) 112 h := common.Hex2Bytes(s[1 : len(s)-1]) 113 copy(*key, h) 114 return nil 115 } 116 117 // each chunk when first requested opens a record associated with the request 118 // next time a request for the same chunk arrives, this record is updated 119 // this request status keeps track of the request ID-s as well as the requesting 120 // peers and has a channel that is closed when the chunk is retrieved. Multiple 121 // local callers can wait on this channel (or combined with a timeout, block with a 122 // select). 123 type RequestStatus struct { 124 Key Key 125 Source Peer 126 C chan bool 127 Requesters map[uint64][]interface{} 128 } 129 130 func newRequestStatus(key Key) *RequestStatus { 131 return &RequestStatus{ 132 Key: key, 133 Requesters: make(map[uint64][]interface{}), 134 C: make(chan bool), 135 } 136 } 137 138 // Chunk also serves as a request object passed to ChunkStores 139 // in case it is a retrieval request, Data is nil and Size is 0 140 // Note that Size is not the size of the data chunk, which is Data.Size() 141 // but the size of the subtree encoded in the chunk 142 // 0 if request, to be supplied by the dpa 143 type Chunk struct { 144 Key Key // always 145 SData []byte // nil if request, to be supplied by dpa 146 Size int64 // size of the data covered by the subtree encoded in this chunk 147 Source Peer // peer 148 C chan bool // to signal data delivery by the dpa 149 Req *RequestStatus // request Status needed by netStore 150 wg *sync.WaitGroup // wg to synchronize 151 dbStored chan bool // never remove a chunk from memStore before it is written to dbStore 152 } 153 154 func NewChunk(key Key, rs *RequestStatus) *Chunk { 155 return &Chunk{Key: key, Req: rs} 156 } 157 158 /* 159 The ChunkStore interface is implemented by : 160 161 - MemStore: a memory cache 162 - DbStore: local disk/db store 163 - LocalStore: a combination (sequence of) memStore and dbStore 164 - NetStore: cloud storage abstraction layer 165 - DPA: local requests for swarm storage and retrieval 166 */ 167 type ChunkStore interface { 168 Put(*Chunk) // effectively there is no error even if there is an error 169 Get(Key) (*Chunk, error) 170 Close() 171 } 172 173 /* 174 Chunker is the interface to a component that is responsible for disassembling and assembling larger data and indended to be the dependency of a DPA storage system with fixed maximum chunksize. 175 176 It relies on the underlying chunking model. 177 178 When calling Split, the caller provides a channel (chan *Chunk) on which it receives chunks to store. The DPA delegates to storage layers (implementing ChunkStore interface). 179 180 Split returns an error channel, which the caller can monitor. 181 After getting notified that all the data has been split (the error channel is closed), the caller can safely read or save the root key. Optionally it times out if not all chunks get stored or not the entire stream of data has been processed. By inspecting the errc channel the caller can check if any explicit errors (typically IO read/write failures) occurred during splitting. 182 183 When calling Join with a root key, the caller gets returned a seekable lazy reader. The caller again provides a channel on which the caller receives placeholder chunks with missing data. The DPA is supposed to forward this to the chunk stores and notify the chunker if the data has been delivered (i.e. retrieved from memory cache, disk-persisted db or cloud based swarm delivery). As the seekable reader is used, the chunker then puts these together the relevant parts on demand. 184 */ 185 type Splitter interface { 186 /* 187 When splitting, data is given as a SectionReader, and the key is a hashSize long byte slice (Key), the root hash of the entire content will fill this once processing finishes. 188 New chunks to store are coming to caller via the chunk storage channel, which the caller provides. 189 wg is a Waitgroup (can be nil) that can be used to block until the local storage finishes 190 The caller gets returned an error channel, if an error is encountered during splitting, it is fed to errC error channel. 191 A closed error signals process completion at which point the key can be considered final if there were no errors. 192 */ 193 Split(io.Reader, int64, chan *Chunk, *sync.WaitGroup, *sync.WaitGroup) (Key, error) 194 } 195 196 type Joiner interface { 197 /* 198 Join reconstructs original content based on a root key. 199 When joining, the caller gets returned a Lazy SectionReader, which is 200 seekable and implements on-demand fetching of chunks as and where it is read. 201 New chunks to retrieve are coming to caller via the Chunk channel, which the caller provides. 202 If an error is encountered during joining, it appears as a reader error. 203 The SectionReader. 204 As a result, partial reads from a document are possible even if other parts 205 are corrupt or lost. 206 The chunks are not meant to be validated by the chunker when joining. This 207 is because it is left to the DPA to decide which sources are trusted. 208 */ 209 Join(key Key, chunkC chan *Chunk) LazySectionReader 210 } 211 212 type Chunker interface { 213 Joiner 214 Splitter 215 // returns the key length 216 // KeySize() int64 217 } 218 219 // Size, Seek, Read, ReadAt 220 type LazySectionReader interface { 221 Size(chan bool) (int64, error) 222 io.Seeker 223 io.Reader 224 io.ReaderAt 225 } 226 227 type LazyTestSectionReader struct { 228 *io.SectionReader 229 } 230 231 func (self *LazyTestSectionReader) Size(chan bool) (int64, error) { 232 return self.SectionReader.Size(), nil 233 }