syncer.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  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. package network
  17. import (
  18. "encoding/binary"
  19. "encoding/json"
  20. "fmt"
  21. "path/filepath"
  22. "github.com/ethereum/go-ethereum/log"
  23. "github.com/ethereum/go-ethereum/swarm/storage"
  24. )
  25. // syncer parameters (global, not peer specific) default values
  26. const (
  27. requestDbBatchSize = 512 // size of batch before written to request db
  28. keyBufferSize = 1024 // size of buffer for unsynced keys
  29. syncBatchSize = 128 // maximum batchsize for outgoing requests
  30. syncBufferSize = 128 // size of buffer for delivery requests
  31. syncCacheSize = 1024 // cache capacity to store request queue in memory
  32. )
  33. // priorities
  34. const (
  35. Low = iota // 0
  36. Medium // 1
  37. High // 2
  38. priorities // 3 number of priority levels
  39. )
  40. // request types
  41. const (
  42. DeliverReq = iota // 0
  43. PushReq // 1
  44. PropagateReq // 2
  45. HistoryReq // 3
  46. BacklogReq // 4
  47. )
  48. // json serialisable struct to record the syncronisation state between 2 peers
  49. type syncState struct {
  50. *storage.DbSyncState // embeds the following 4 fields:
  51. // Start Key // lower limit of address space
  52. // Stop Key // upper limit of address space
  53. // First uint64 // counter taken from last sync state
  54. // Last uint64 // counter of remote peer dbStore at the time of last connection
  55. SessionAt uint64 // set at the time of connection
  56. LastSeenAt uint64 // set at the time of connection
  57. Latest storage.Key // cursor of dbstore when last (continuously set by syncer)
  58. Synced bool // true iff Sync is done up to the last disconnect
  59. synced chan bool // signal that sync stage finished
  60. }
  61. // wrapper of db-s to provide mockable custom local chunk store access to syncer
  62. type DbAccess struct {
  63. db *storage.DbStore
  64. loc *storage.LocalStore
  65. }
  66. func NewDbAccess(loc *storage.LocalStore) *DbAccess {
  67. return &DbAccess{loc.DbStore.(*storage.DbStore), loc}
  68. }
  69. // to obtain the chunks from key or request db entry only
  70. func (self *DbAccess) get(key storage.Key) (*storage.Chunk, error) {
  71. return self.loc.Get(key)
  72. }
  73. // current storage counter of chunk db
  74. func (self *DbAccess) counter() uint64 {
  75. return self.db.Counter()
  76. }
  77. // implemented by dbStoreSyncIterator
  78. type keyIterator interface {
  79. Next() storage.Key
  80. }
  81. // generator function for iteration by address range and storage counter
  82. func (self *DbAccess) iterator(s *syncState) keyIterator {
  83. it, err := self.db.NewSyncIterator(*(s.DbSyncState))
  84. if err != nil {
  85. return nil
  86. }
  87. return keyIterator(it)
  88. }
  89. func (self syncState) String() string {
  90. if self.Synced {
  91. return fmt.Sprintf(
  92. "session started at: %v, last seen at: %v, latest key: %v",
  93. self.SessionAt, self.LastSeenAt,
  94. self.Latest.Log(),
  95. )
  96. } else {
  97. return fmt.Sprintf(
  98. "address: %v-%v, index: %v-%v, session started at: %v, last seen at: %v, latest key: %v",
  99. self.Start.Log(), self.Stop.Log(),
  100. self.First, self.Last,
  101. self.SessionAt, self.LastSeenAt,
  102. self.Latest.Log(),
  103. )
  104. }
  105. }
  106. // syncer parameters (global, not peer specific)
  107. type SyncParams struct {
  108. RequestDbPath string // path for request db (leveldb)
  109. RequestDbBatchSize uint // nuber of items before batch is saved to requestdb
  110. KeyBufferSize uint // size of key buffer
  111. SyncBatchSize uint // maximum batchsize for outgoing requests
  112. SyncBufferSize uint // size of buffer for
  113. SyncCacheSize uint // cache capacity to store request queue in memory
  114. SyncPriorities []uint // list of priority levels for req types 0-3
  115. SyncModes []bool // list of sync modes for for req types 0-3
  116. }
  117. // constructor with default values
  118. func NewDefaultSyncParams() *SyncParams {
  119. return &SyncParams{
  120. RequestDbBatchSize: requestDbBatchSize,
  121. KeyBufferSize: keyBufferSize,
  122. SyncBufferSize: syncBufferSize,
  123. SyncBatchSize: syncBatchSize,
  124. SyncCacheSize: syncCacheSize,
  125. SyncPriorities: []uint{High, Medium, Medium, Low, Low},
  126. SyncModes: []bool{true, true, true, true, false},
  127. }
  128. }
  129. //this can only finally be set after all config options (file, cmd line, env vars)
  130. //have been evaluated
  131. func (self *SyncParams) Init(path string) {
  132. self.RequestDbPath = filepath.Join(path, "requests")
  133. }
  134. // syncer is the agent that manages content distribution/storage replication/chunk storeRequest forwarding
  135. type syncer struct {
  136. *SyncParams // sync parameters
  137. syncF func() bool // if syncing is needed
  138. key storage.Key // remote peers address key
  139. state *syncState // sync state for our dbStore
  140. syncStates chan *syncState // different stages of sync
  141. deliveryRequest chan bool // one of two triggers needed to send unsyncedKeys
  142. newUnsyncedKeys chan bool // one of two triggers needed to send unsynced keys
  143. quit chan bool // signal to quit loops
  144. // DB related fields
  145. dbAccess *DbAccess // access to dbStore
  146. // native fields
  147. queues [priorities]*syncDb // in-memory cache / queues for sync reqs
  148. keys [priorities]chan interface{} // buffer for unsynced keys
  149. deliveries [priorities]chan *storeRequestMsgData // delivery
  150. // bzz protocol instance outgoing message callbacks (mockable for testing)
  151. unsyncedKeys func([]*syncRequest, *syncState) error // send unsyncedKeysMsg
  152. store func(*storeRequestMsgData) error // send storeRequestMsg
  153. }
  154. // a syncer instance is linked to each peer connection
  155. // constructor is called from protocol after successful handshake
  156. // the returned instance is attached to the peer and can be called
  157. // by the forwarder
  158. func newSyncer(
  159. db *storage.LDBDatabase, remotekey storage.Key,
  160. dbAccess *DbAccess,
  161. unsyncedKeys func([]*syncRequest, *syncState) error,
  162. store func(*storeRequestMsgData) error,
  163. params *SyncParams,
  164. state *syncState,
  165. syncF func() bool,
  166. ) (*syncer, error) {
  167. syncBufferSize := params.SyncBufferSize
  168. keyBufferSize := params.KeyBufferSize
  169. dbBatchSize := params.RequestDbBatchSize
  170. self := &syncer{
  171. syncF: syncF,
  172. key: remotekey,
  173. dbAccess: dbAccess,
  174. syncStates: make(chan *syncState, 20),
  175. deliveryRequest: make(chan bool, 1),
  176. newUnsyncedKeys: make(chan bool, 1),
  177. SyncParams: params,
  178. state: state,
  179. quit: make(chan bool),
  180. unsyncedKeys: unsyncedKeys,
  181. store: store,
  182. }
  183. // initialising
  184. for i := 0; i < priorities; i++ {
  185. self.keys[i] = make(chan interface{}, keyBufferSize)
  186. self.deliveries[i] = make(chan *storeRequestMsgData)
  187. // initialise a syncdb instance for each priority queue
  188. self.queues[i] = newSyncDb(db, remotekey, uint(i), syncBufferSize, dbBatchSize, self.deliver(uint(i)))
  189. }
  190. log.Info(fmt.Sprintf("syncer started: %v", state))
  191. // launch chunk delivery service
  192. go self.syncDeliveries()
  193. // launch sync task manager
  194. if self.syncF() {
  195. go self.sync()
  196. }
  197. // process unsynced keys to broadcast
  198. go self.syncUnsyncedKeys()
  199. return self, nil
  200. }
  201. // metadata serialisation
  202. func encodeSync(state *syncState) (*json.RawMessage, error) {
  203. data, err := json.MarshalIndent(state, "", " ")
  204. if err != nil {
  205. return nil, err
  206. }
  207. meta := json.RawMessage(data)
  208. return &meta, nil
  209. }
  210. func decodeSync(meta *json.RawMessage) (*syncState, error) {
  211. if meta == nil {
  212. return nil, fmt.Errorf("unable to deserialise sync state from <nil>")
  213. }
  214. data := []byte(*(meta))
  215. if len(data) == 0 {
  216. return nil, fmt.Errorf("unable to deserialise sync state from <nil>")
  217. }
  218. state := &syncState{DbSyncState: &storage.DbSyncState{}}
  219. err := json.Unmarshal(data, state)
  220. return state, err
  221. }
  222. /*
  223. sync implements the syncing script
  224. * first all items left in the request Db are replayed
  225. * type = StaleSync
  226. * Mode: by default once again via confirmation roundtrip
  227. * Priority: the items are replayed as the proirity specified for StaleSync
  228. * but within the order respects earlier priority level of request
  229. * after all items are consumed for a priority level, the the respective
  230. queue for delivery requests is open (this way new reqs not written to db)
  231. (TODO: this should be checked)
  232. * the sync state provided by the remote peer is used to sync history
  233. * all the backlog from earlier (aborted) syncing is completed starting from latest
  234. * if Last < LastSeenAt then all items in between then process all
  235. backlog from upto last disconnect
  236. * if Last > 0 &&
  237. sync is called from the syncer constructor and is not supposed to be used externally
  238. */
  239. func (self *syncer) sync() {
  240. state := self.state
  241. // sync finished
  242. defer close(self.syncStates)
  243. // 0. first replay stale requests from request db
  244. if state.SessionAt == 0 {
  245. log.Debug(fmt.Sprintf("syncer[%v]: nothing to sync", self.key.Log()))
  246. return
  247. }
  248. log.Debug(fmt.Sprintf("syncer[%v]: start replaying stale requests from request db", self.key.Log()))
  249. for p := priorities - 1; p >= 0; p-- {
  250. self.queues[p].dbRead(false, 0, self.replay())
  251. }
  252. log.Debug(fmt.Sprintf("syncer[%v]: done replaying stale requests from request db", self.key.Log()))
  253. // unless peer is synced sync unfinished history beginning on
  254. if !state.Synced {
  255. start := state.Start
  256. if !storage.IsZeroKey(state.Latest) {
  257. // 1. there is unfinished earlier sync
  258. state.Start = state.Latest
  259. log.Debug(fmt.Sprintf("syncer[%v]: start syncronising backlog (unfinished sync: %v)", self.key.Log(), state))
  260. // blocks while the entire history upto state is synced
  261. self.syncState(state)
  262. if state.Last < state.SessionAt {
  263. state.First = state.Last + 1
  264. }
  265. }
  266. state.Latest = storage.ZeroKey
  267. state.Start = start
  268. // 2. sync up to last disconnect1
  269. if state.First < state.LastSeenAt {
  270. state.Last = state.LastSeenAt
  271. log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history upto last disconnect at %v: %v", self.key.Log(), state.LastSeenAt, state))
  272. self.syncState(state)
  273. state.First = state.LastSeenAt
  274. }
  275. state.Latest = storage.ZeroKey
  276. } else {
  277. // synchronisation starts at end of last session
  278. state.First = state.LastSeenAt
  279. }
  280. // 3. sync up to current session start
  281. // if there have been new chunks since last session
  282. if state.LastSeenAt < state.SessionAt {
  283. state.Last = state.SessionAt
  284. log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history since last disconnect at %v up until session start at %v: %v", self.key.Log(), state.LastSeenAt, state.SessionAt, state))
  285. // blocks until state syncing is finished
  286. self.syncState(state)
  287. }
  288. log.Info(fmt.Sprintf("syncer[%v]: syncing all history complete", self.key.Log()))
  289. }
  290. // wait till syncronised block uptil state is synced
  291. func (self *syncer) syncState(state *syncState) {
  292. self.syncStates <- state
  293. select {
  294. case <-state.synced:
  295. case <-self.quit:
  296. }
  297. }
  298. // stop quits both request processor and saves the request cache to disk
  299. func (self *syncer) stop() {
  300. close(self.quit)
  301. log.Trace(fmt.Sprintf("syncer[%v]: stop and save sync request db backlog", self.key.Log()))
  302. for _, db := range self.queues {
  303. db.stop()
  304. }
  305. }
  306. // rlp serialisable sync request
  307. type syncRequest struct {
  308. Key storage.Key
  309. Priority uint
  310. }
  311. func (self *syncRequest) String() string {
  312. return fmt.Sprintf("<Key: %v, Priority: %v>", self.Key.Log(), self.Priority)
  313. }
  314. func (self *syncer) newSyncRequest(req interface{}, p int) (*syncRequest, error) {
  315. key, _, _, _, err := parseRequest(req)
  316. // TODO: if req has chunk, it should be put in a cache
  317. // create
  318. if err != nil {
  319. return nil, err
  320. }
  321. return &syncRequest{key, uint(p)}, nil
  322. }
  323. // serves historical items from the DB
  324. // * read is on demand, blocking unless history channel is read
  325. // * accepts sync requests (syncStates) to create new db iterator
  326. // * closes the channel one iteration finishes
  327. func (self *syncer) syncHistory(state *syncState) chan interface{} {
  328. var n uint
  329. history := make(chan interface{})
  330. log.Debug(fmt.Sprintf("syncer[%v]: syncing history between %v - %v for chunk addresses %v - %v", self.key.Log(), state.First, state.Last, state.Start, state.Stop))
  331. it := self.dbAccess.iterator(state)
  332. if it != nil {
  333. go func() {
  334. // signal end of the iteration ended
  335. defer close(history)
  336. IT:
  337. for {
  338. key := it.Next()
  339. if key == nil {
  340. break IT
  341. }
  342. select {
  343. // blocking until history channel is read from
  344. case history <- key:
  345. n++
  346. log.Trace(fmt.Sprintf("syncer[%v]: history: %v (%v keys)", self.key.Log(), key.Log(), n))
  347. state.Latest = key
  348. case <-self.quit:
  349. return
  350. }
  351. }
  352. log.Debug(fmt.Sprintf("syncer[%v]: finished syncing history between %v - %v for chunk addresses %v - %v (at %v) (chunks = %v)", self.key.Log(), state.First, state.Last, state.Start, state.Stop, state.Latest, n))
  353. }()
  354. }
  355. return history
  356. }
  357. // triggers key syncronisation
  358. func (self *syncer) sendUnsyncedKeys() {
  359. select {
  360. case self.deliveryRequest <- true:
  361. default:
  362. }
  363. }
  364. // assembles a new batch of unsynced keys
  365. // * keys are drawn from the key buffers in order of priority queue
  366. // * if the queues of priority for History (HistoryReq) or higher are depleted,
  367. // historical data is used so historical items are lower priority within
  368. // their priority group.
  369. // * Order of historical data is unspecified
  370. func (self *syncer) syncUnsyncedKeys() {
  371. // send out new
  372. var unsynced []*syncRequest
  373. var more, justSynced bool
  374. var keyCount, historyCnt int
  375. var history chan interface{}
  376. priority := High
  377. keys := self.keys[priority]
  378. var newUnsyncedKeys, deliveryRequest chan bool
  379. keyCounts := make([]int, priorities)
  380. histPrior := self.SyncPriorities[HistoryReq]
  381. syncStates := self.syncStates
  382. state := self.state
  383. LOOP:
  384. for {
  385. var req interface{}
  386. // select the highest priority channel to read from
  387. // keys channels are buffered so the highest priority ones
  388. // are checked first - integrity can only be guaranteed if writing
  389. // is locked while selecting
  390. if priority != High || len(keys) == 0 {
  391. // selection is not needed if the High priority queue has items
  392. keys = nil
  393. PRIORITIES:
  394. for priority = High; priority >= 0; priority-- {
  395. // the first priority channel that is non-empty will be assigned to keys
  396. if len(self.keys[priority]) > 0 {
  397. log.Trace(fmt.Sprintf("syncer[%v]: reading request with priority %v", self.key.Log(), priority))
  398. keys = self.keys[priority]
  399. break PRIORITIES
  400. }
  401. log.Trace(fmt.Sprintf("syncer[%v/%v]: queue: [%v, %v, %v]", self.key.Log(), priority, len(self.keys[High]), len(self.keys[Medium]), len(self.keys[Low])))
  402. // if the input queue is empty on this level, resort to history if there is any
  403. if uint(priority) == histPrior && history != nil {
  404. log.Trace(fmt.Sprintf("syncer[%v]: reading history for %v", self.key.Log(), self.key))
  405. keys = history
  406. break PRIORITIES
  407. }
  408. }
  409. }
  410. // if peer ready to receive but nothing to send
  411. if keys == nil && deliveryRequest == nil {
  412. // if no items left and switch to waiting mode
  413. log.Trace(fmt.Sprintf("syncer[%v]: buffers consumed. Waiting", self.key.Log()))
  414. newUnsyncedKeys = self.newUnsyncedKeys
  415. }
  416. // send msg iff
  417. // * peer is ready to receive keys AND (
  418. // * all queues and history are depleted OR
  419. // * batch full OR
  420. // * all history have been consumed, synced)
  421. if deliveryRequest == nil &&
  422. (justSynced ||
  423. len(unsynced) > 0 && keys == nil ||
  424. len(unsynced) == int(self.SyncBatchSize)) {
  425. justSynced = false
  426. // listen to requests
  427. deliveryRequest = self.deliveryRequest
  428. newUnsyncedKeys = nil // not care about data until next req comes in
  429. // set sync to current counter
  430. // (all nonhistorical outgoing traffic sheduled and persisted
  431. state.LastSeenAt = self.dbAccess.counter()
  432. state.Latest = storage.ZeroKey
  433. log.Trace(fmt.Sprintf("syncer[%v]: sending %v", self.key.Log(), unsynced))
  434. // send the unsynced keys
  435. stateCopy := *state
  436. err := self.unsyncedKeys(unsynced, &stateCopy)
  437. if err != nil {
  438. log.Warn(fmt.Sprintf("syncer[%v]: unable to send unsynced keys: %v", self.key.Log(), err))
  439. }
  440. self.state = state
  441. log.Debug(fmt.Sprintf("syncer[%v]: --> %v keys sent: (total: %v (%v), history: %v), sent sync state: %v", self.key.Log(), len(unsynced), keyCounts, keyCount, historyCnt, stateCopy))
  442. unsynced = nil
  443. keys = nil
  444. }
  445. // process item and add it to the batch
  446. select {
  447. case <-self.quit:
  448. break LOOP
  449. case req, more = <-keys:
  450. if keys == history && !more {
  451. log.Trace(fmt.Sprintf("syncer[%v]: syncing history segment complete", self.key.Log()))
  452. // history channel is closed, waiting for new state (called from sync())
  453. syncStates = self.syncStates
  454. state.Synced = true // this signals that the current segment is complete
  455. select {
  456. case state.synced <- false:
  457. case <-self.quit:
  458. break LOOP
  459. }
  460. justSynced = true
  461. history = nil
  462. }
  463. case <-deliveryRequest:
  464. log.Trace(fmt.Sprintf("syncer[%v]: peer ready to receive", self.key.Log()))
  465. // this 1 cap channel can wake up the loop
  466. // signaling that peer is ready to receive unsynced Keys
  467. // the channel is set to nil any further writes will be ignored
  468. deliveryRequest = nil
  469. case <-newUnsyncedKeys:
  470. log.Trace(fmt.Sprintf("syncer[%v]: new unsynced keys available", self.key.Log()))
  471. // this 1 cap channel can wake up the loop
  472. // signals that data is available to send if peer is ready to receive
  473. newUnsyncedKeys = nil
  474. keys = self.keys[High]
  475. case state, more = <-syncStates:
  476. // this resets the state
  477. if !more {
  478. state = self.state
  479. log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing complete upto %v)", self.key.Log(), priority, state))
  480. state.Synced = true
  481. syncStates = nil
  482. } else {
  483. log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing history upto %v priority %v)", self.key.Log(), priority, state, histPrior))
  484. state.Synced = false
  485. history = self.syncHistory(state)
  486. // only one history at a time, only allow another one once the
  487. // history channel is closed
  488. syncStates = nil
  489. }
  490. }
  491. if req == nil {
  492. continue LOOP
  493. }
  494. log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) added to unsynced keys: %v", self.key.Log(), priority, req))
  495. keyCounts[priority]++
  496. keyCount++
  497. if keys == history {
  498. log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) history item %v (synced = %v)", self.key.Log(), priority, req, state.Synced))
  499. historyCnt++
  500. }
  501. if sreq, err := self.newSyncRequest(req, priority); err == nil {
  502. // extract key from req
  503. log.Trace(fmt.Sprintf("syncer[%v]: (priority %v): request %v (synced = %v)", self.key.Log(), priority, req, state.Synced))
  504. unsynced = append(unsynced, sreq)
  505. } else {
  506. log.Warn(fmt.Sprintf("syncer[%v]: (priority %v): error creating request for %v: %v)", self.key.Log(), priority, req, err))
  507. }
  508. }
  509. }
  510. // delivery loop
  511. // takes into account priority, send store Requests with chunk (delivery)
  512. // idle blocking if no new deliveries in any of the queues
  513. func (self *syncer) syncDeliveries() {
  514. var req *storeRequestMsgData
  515. p := High
  516. var deliveries chan *storeRequestMsgData
  517. var msg *storeRequestMsgData
  518. var err error
  519. var c = [priorities]int{}
  520. var n = [priorities]int{}
  521. var total, success uint
  522. for {
  523. deliveries = self.deliveries[p]
  524. select {
  525. case req = <-deliveries:
  526. n[p]++
  527. c[p]++
  528. default:
  529. if p == Low {
  530. // blocking, depletion on all channels, no preference for priority
  531. select {
  532. case req = <-self.deliveries[High]:
  533. n[High]++
  534. case req = <-self.deliveries[Medium]:
  535. n[Medium]++
  536. case req = <-self.deliveries[Low]:
  537. n[Low]++
  538. case <-self.quit:
  539. return
  540. }
  541. p = High
  542. } else {
  543. p--
  544. continue
  545. }
  546. }
  547. total++
  548. msg, err = self.newStoreRequestMsgData(req)
  549. if err != nil {
  550. log.Warn(fmt.Sprintf("syncer[%v]: failed to create store request for %v: %v", self.key.Log(), req, err))
  551. } else {
  552. err = self.store(msg)
  553. if err != nil {
  554. log.Warn(fmt.Sprintf("syncer[%v]: failed to deliver %v: %v", self.key.Log(), req, err))
  555. } else {
  556. success++
  557. log.Trace(fmt.Sprintf("syncer[%v]: %v successfully delivered", self.key.Log(), req))
  558. }
  559. }
  560. if total%self.SyncBatchSize == 0 {
  561. log.Debug(fmt.Sprintf("syncer[%v]: deliver Total: %v, Success: %v, High: %v/%v, Medium: %v/%v, Low %v/%v", self.key.Log(), total, success, c[High], n[High], c[Medium], n[Medium], c[Low], n[Low]))
  562. }
  563. }
  564. }
  565. /*
  566. addRequest handles requests for delivery
  567. it accepts 4 types:
  568. * storeRequestMsgData: coming from netstore propagate response
  569. * chunk: coming from forwarding (questionable: id?)
  570. * key: from incoming syncRequest
  571. * syncDbEntry: key,id encoded in db
  572. If sync mode is on for the type of request, then
  573. it sends the request to the keys queue of the correct priority
  574. channel buffered with capacity (SyncBufferSize)
  575. If sync mode is off then, requests are directly sent to deliveries
  576. */
  577. func (self *syncer) addRequest(req interface{}, ty int) {
  578. // retrieve priority for request type name int8
  579. priority := self.SyncPriorities[ty]
  580. // sync mode for this type ON
  581. if self.syncF() || ty == DeliverReq {
  582. if self.SyncModes[ty] {
  583. self.addKey(req, priority, self.quit)
  584. } else {
  585. self.addDelivery(req, priority, self.quit)
  586. }
  587. }
  588. }
  589. // addKey queues sync request for sync confirmation with given priority
  590. // ie the key will go out in an unsyncedKeys message
  591. func (self *syncer) addKey(req interface{}, priority uint, quit chan bool) bool {
  592. select {
  593. case self.keys[priority] <- req:
  594. // this wakes up the unsynced keys loop if idle
  595. select {
  596. case self.newUnsyncedKeys <- true:
  597. default:
  598. }
  599. return true
  600. case <-quit:
  601. return false
  602. }
  603. }
  604. // addDelivery queues delivery request for with given priority
  605. // ie the chunk will be delivered ASAP mod priority queueing handled by syncdb
  606. // requests are persisted across sessions for correct sync
  607. func (self *syncer) addDelivery(req interface{}, priority uint, quit chan bool) bool {
  608. select {
  609. case self.queues[priority].buffer <- req:
  610. return true
  611. case <-quit:
  612. return false
  613. }
  614. }
  615. // doDelivery delivers the chunk for the request with given priority
  616. // without queuing
  617. func (self *syncer) doDelivery(req interface{}, priority uint, quit chan bool) bool {
  618. msgdata, err := self.newStoreRequestMsgData(req)
  619. if err != nil {
  620. log.Warn(fmt.Sprintf("unable to deliver request %v: %v", msgdata, err))
  621. return false
  622. }
  623. select {
  624. case self.deliveries[priority] <- msgdata:
  625. return true
  626. case <-quit:
  627. return false
  628. }
  629. }
  630. // returns the delivery function for given priority
  631. // passed on to syncDb
  632. func (self *syncer) deliver(priority uint) func(req interface{}, quit chan bool) bool {
  633. return func(req interface{}, quit chan bool) bool {
  634. return self.doDelivery(req, priority, quit)
  635. }
  636. }
  637. // returns the replay function passed on to syncDb
  638. // depending on sync mode settings for BacklogReq,
  639. // re play of request db backlog sends items via confirmation
  640. // or directly delivers
  641. func (self *syncer) replay() func(req interface{}, quit chan bool) bool {
  642. sync := self.SyncModes[BacklogReq]
  643. priority := self.SyncPriorities[BacklogReq]
  644. // sync mode for this type ON
  645. if sync {
  646. return func(req interface{}, quit chan bool) bool {
  647. return self.addKey(req, priority, quit)
  648. }
  649. } else {
  650. return func(req interface{}, quit chan bool) bool {
  651. return self.doDelivery(req, priority, quit)
  652. }
  653. }
  654. }
  655. // given a request, extends it to a full storeRequestMsgData
  656. // polimorphic: see addRequest for the types accepted
  657. func (self *syncer) newStoreRequestMsgData(req interface{}) (*storeRequestMsgData, error) {
  658. key, id, chunk, sreq, err := parseRequest(req)
  659. if err != nil {
  660. return nil, err
  661. }
  662. if sreq == nil {
  663. if chunk == nil {
  664. var err error
  665. chunk, err = self.dbAccess.get(key)
  666. if err != nil {
  667. return nil, err
  668. }
  669. }
  670. sreq = &storeRequestMsgData{
  671. Id: id,
  672. Key: chunk.Key,
  673. SData: chunk.SData,
  674. }
  675. }
  676. return sreq, nil
  677. }
  678. // parse request types and extracts, key, id, chunk, request if available
  679. // does not do chunk lookup !
  680. func parseRequest(req interface{}) (storage.Key, uint64, *storage.Chunk, *storeRequestMsgData, error) {
  681. var key storage.Key
  682. var entry *syncDbEntry
  683. var chunk *storage.Chunk
  684. var id uint64
  685. var ok bool
  686. var sreq *storeRequestMsgData
  687. var err error
  688. if key, ok = req.(storage.Key); ok {
  689. id = generateId()
  690. } else if entry, ok = req.(*syncDbEntry); ok {
  691. id = binary.BigEndian.Uint64(entry.val[32:])
  692. key = storage.Key(entry.val[:32])
  693. } else if chunk, ok = req.(*storage.Chunk); ok {
  694. key = chunk.Key
  695. id = generateId()
  696. } else if sreq, ok = req.(*storeRequestMsgData); ok {
  697. key = sreq.Key
  698. } else {
  699. err = fmt.Errorf("type not allowed: %v (%T)", req, req)
  700. }
  701. return key, id, chunk, sreq, err
  702. }