github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/network/stream/syncer.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:48</date> 10 //</624342676291981312> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 package stream 29 30 import ( 31 "context" 32 "math" 33 "strconv" 34 "time" 35 36 "github.com/ethereum/go-ethereum/metrics" 37 "github.com/ethereum/go-ethereum/swarm/log" 38 "github.com/ethereum/go-ethereum/swarm/storage" 39 ) 40 41 const ( 42 // 43 BatchSize = 128 44 ) 45 46 // 47 // 48 // 49 // 50 type SwarmSyncerServer struct { 51 po uint8 52 db *storage.DBAPI 53 sessionAt uint64 54 start uint64 55 quit chan struct{} 56 } 57 58 // 59 func NewSwarmSyncerServer(live bool, po uint8, db *storage.DBAPI) (*SwarmSyncerServer, error) { 60 sessionAt := db.CurrentBucketStorageIndex(po) 61 var start uint64 62 if live { 63 start = sessionAt 64 } 65 return &SwarmSyncerServer{ 66 po: po, 67 db: db, 68 sessionAt: sessionAt, 69 start: start, 70 quit: make(chan struct{}), 71 }, nil 72 } 73 74 func RegisterSwarmSyncerServer(streamer *Registry, db *storage.DBAPI) { 75 streamer.RegisterServerFunc("SYNC", func(p *Peer, t string, live bool) (Server, error) { 76 po, err := ParseSyncBinKey(t) 77 if err != nil { 78 return nil, err 79 } 80 return NewSwarmSyncerServer(live, po, db) 81 }) 82 // 83 // 84 // 85 } 86 87 // 88 func (s *SwarmSyncerServer) Close() { 89 close(s.quit) 90 } 91 92 // 93 func (s *SwarmSyncerServer) GetData(ctx context.Context, key []byte) ([]byte, error) { 94 chunk, err := s.db.Get(ctx, storage.Address(key)) 95 if err == storage.ErrFetching { 96 <-chunk.ReqC 97 } else if err != nil { 98 return nil, err 99 } 100 return chunk.SData, nil 101 } 102 103 // 104 func (s *SwarmSyncerServer) SetNextBatch(from, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) { 105 var batch []byte 106 i := 0 107 if from == 0 { 108 from = s.start 109 } 110 if to <= from || from >= s.sessionAt { 111 to = math.MaxUint64 112 } 113 var ticker *time.Ticker 114 defer func() { 115 if ticker != nil { 116 ticker.Stop() 117 } 118 }() 119 var wait bool 120 for { 121 if wait { 122 if ticker == nil { 123 ticker = time.NewTicker(1000 * time.Millisecond) 124 } 125 select { 126 case <-ticker.C: 127 case <-s.quit: 128 return nil, 0, 0, nil, nil 129 } 130 } 131 132 metrics.GetOrRegisterCounter("syncer.setnextbatch.iterator", nil).Inc(1) 133 err := s.db.Iterator(from, to, s.po, func(addr storage.Address, idx uint64) bool { 134 batch = append(batch, addr[:]...) 135 i++ 136 to = idx 137 return i < BatchSize 138 }) 139 if err != nil { 140 return nil, 0, 0, nil, err 141 } 142 if len(batch) > 0 { 143 break 144 } 145 wait = true 146 } 147 148 log.Trace("Swarm syncer offer batch", "po", s.po, "len", i, "from", from, "to", to, "current store count", s.db.CurrentBucketStorageIndex(s.po)) 149 return batch, from, to, nil, nil 150 } 151 152 // 153 type SwarmSyncerClient struct { 154 sessionAt uint64 155 nextC chan struct{} 156 sessionRoot storage.Address 157 sessionReader storage.LazySectionReader 158 retrieveC chan *storage.Chunk 159 storeC chan *storage.Chunk 160 db *storage.DBAPI 161 // 162 currentRoot storage.Address 163 requestFunc func(chunk *storage.Chunk) 164 end, start uint64 165 peer *Peer 166 ignoreExistingRequest bool 167 stream Stream 168 } 169 170 // 171 func NewSwarmSyncerClient(p *Peer, db *storage.DBAPI, ignoreExistingRequest bool, stream Stream) (*SwarmSyncerClient, error) { 172 return &SwarmSyncerClient{ 173 db: db, 174 peer: p, 175 ignoreExistingRequest: ignoreExistingRequest, 176 stream: stream, 177 }, nil 178 } 179 180 // 181 // 182 // 183 // 184 // 185 // 186 // 187 // 188 // 189 // 190 // 191 // 192 // 193 // 194 // 195 // 196 // 197 // 198 // 199 // 200 // 201 202 // 203 // 204 // 205 // 206 // 207 // 208 // 209 // 210 // 211 // 212 // 213 // 214 // 215 216 // 217 // 218 func RegisterSwarmSyncerClient(streamer *Registry, db *storage.DBAPI) { 219 streamer.RegisterClientFunc("SYNC", func(p *Peer, t string, live bool) (Client, error) { 220 return NewSwarmSyncerClient(p, db, true, NewStream("SYNC", t, live)) 221 }) 222 } 223 224 // 225 func (s *SwarmSyncerClient) NeedData(ctx context.Context, key []byte) (wait func()) { 226 chunk, _ := s.db.GetOrCreateRequest(ctx, key) 227 // 228 229 // 230 // 231 if chunk.ReqC == nil { // 232 return nil 233 } 234 // 235 return func() { 236 chunk.WaitToStore() 237 } 238 } 239 240 // 241 func (s *SwarmSyncerClient) BatchDone(stream Stream, from uint64, hashes []byte, root []byte) func() (*TakeoverProof, error) { 242 // 243 // 244 // 245 // 246 return nil 247 } 248 249 func (s *SwarmSyncerClient) TakeoverProof(stream Stream, from uint64, hashes []byte, root storage.Address) (*TakeoverProof, error) { 250 // 251 // 252 // 253 // 254 // 255 // 256 // 257 // 258 // 259 // 260 // 261 // 262 // 263 // 264 // 265 // 266 // 267 // 268 // 269 // 270 // 271 // 272 // 273 // 274 // 275 s.end += uint64(len(hashes)) / HashSize 276 takeover := &Takeover{ 277 Stream: stream, 278 Start: s.start, 279 End: s.end, 280 Root: root, 281 } 282 // 283 return &TakeoverProof{ 284 Takeover: takeover, 285 Sig: nil, 286 }, nil 287 } 288 289 func (s *SwarmSyncerClient) Close() {} 290 291 // 292 // 293 const syncBinKeyBase = 36 294 295 // 296 // 297 func FormatSyncBinKey(bin uint8) string { 298 return strconv.FormatUint(uint64(bin), syncBinKeyBase) 299 } 300 301 // 302 // 303 func ParseSyncBinKey(s string) (uint8, error) { 304 bin, err := strconv.ParseUint(s, syncBinKeyBase, 8) 305 if err != nil { 306 return 0, err 307 } 308 return uint8(bin), nil 309 } 310