forwarding.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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. "fmt"
  19. "math/rand"
  20. "time"
  21. "github.com/ethereum/go-ethereum/log"
  22. "github.com/ethereum/go-ethereum/swarm/storage"
  23. )
  24. const requesterCount = 3
  25. /*
  26. forwarder implements the CloudStore interface (use by storage.NetStore)
  27. and serves as the cloud store backend orchestrating storage/retrieval/delivery
  28. via the native bzz protocol
  29. which uses an MSB logarithmic distance-based semi-permanent Kademlia table for
  30. * recursive forwarding style routing for retrieval
  31. * smart syncronisation
  32. */
  33. type forwarder struct {
  34. hive *Hive
  35. }
  36. func NewForwarder(hive *Hive) *forwarder {
  37. return &forwarder{hive: hive}
  38. }
  39. // generate a unique id uint64
  40. func generateId() uint64 {
  41. r := rand.New(rand.NewSource(time.Now().UnixNano()))
  42. return uint64(r.Int63())
  43. }
  44. var searchTimeout = 3 * time.Second
  45. // forwarding logic
  46. // logic propagating retrieve requests to peers given by the kademlia hive
  47. func (self *forwarder) Retrieve(chunk *storage.Chunk) {
  48. peers := self.hive.getPeers(chunk.Key, 0)
  49. log.Trace(fmt.Sprintf("forwarder.Retrieve: %v - received %d peers from KΛÐΞMLIΛ...", chunk.Key.Log(), len(peers)))
  50. OUT:
  51. for _, p := range peers {
  52. log.Trace(fmt.Sprintf("forwarder.Retrieve: sending retrieveRequest %v to peer [%v]", chunk.Key.Log(), p))
  53. for _, recipients := range chunk.Req.Requesters {
  54. for _, recipient := range recipients {
  55. req := recipient.(*retrieveRequestMsgData)
  56. if req.from.Addr() == p.Addr() {
  57. continue OUT
  58. }
  59. }
  60. }
  61. req := &retrieveRequestMsgData{
  62. Key: chunk.Key,
  63. Id: generateId(),
  64. }
  65. var err error
  66. if p.swap != nil {
  67. err = p.swap.Add(-1)
  68. }
  69. if err == nil {
  70. p.retrieve(req)
  71. break OUT
  72. }
  73. log.Warn(fmt.Sprintf("forwarder.Retrieve: unable to send retrieveRequest to peer [%v]: %v", chunk.Key.Log(), err))
  74. }
  75. }
  76. // requests to specific peers given by the kademlia hive
  77. // except for peers that the store request came from (if any)
  78. // delivery queueing taken care of by syncer
  79. func (self *forwarder) Store(chunk *storage.Chunk) {
  80. var n int
  81. msg := &storeRequestMsgData{
  82. Key: chunk.Key,
  83. SData: chunk.SData,
  84. }
  85. var source *peer
  86. if chunk.Source != nil {
  87. source = chunk.Source.(*peer)
  88. }
  89. for _, p := range self.hive.getPeers(chunk.Key, 0) {
  90. log.Trace(fmt.Sprintf("forwarder.Store: %v %v", p, chunk))
  91. if p.syncer != nil && (source == nil || p.Addr() != source.Addr()) {
  92. n++
  93. Deliver(p, msg, PropagateReq)
  94. }
  95. }
  96. log.Trace(fmt.Sprintf("forwarder.Store: sent to %v peers (chunk = %v)", n, chunk))
  97. }
  98. // once a chunk is found deliver it to its requesters unless timed out
  99. func (self *forwarder) Deliver(chunk *storage.Chunk) {
  100. // iterate over request entries
  101. for id, requesters := range chunk.Req.Requesters {
  102. counter := requesterCount
  103. msg := &storeRequestMsgData{
  104. Key: chunk.Key,
  105. SData: chunk.SData,
  106. }
  107. var n int
  108. var req *retrieveRequestMsgData
  109. // iterate over requesters with the same id
  110. for id, r := range requesters {
  111. req = r.(*retrieveRequestMsgData)
  112. if req.timeout == nil || req.timeout.After(time.Now()) {
  113. log.Trace(fmt.Sprintf("forwarder.Deliver: %v -> %v", req.Id, req.from))
  114. msg.Id = uint64(id)
  115. Deliver(req.from, msg, DeliverReq)
  116. n++
  117. counter--
  118. if counter <= 0 {
  119. break
  120. }
  121. }
  122. }
  123. log.Trace(fmt.Sprintf("forwarder.Deliver: submit chunk %v (request id %v) for delivery to %v peers", chunk.Key.Log(), id, n))
  124. }
  125. }
  126. // initiate delivery of a chunk to a particular peer via syncer#addRequest
  127. // depending on syncer mode and priority settings and sync request type
  128. // this either goes via confirmation roundtrip or queued or pushed directly
  129. func Deliver(p *peer, req interface{}, ty int) {
  130. p.syncer.addRequest(req, ty)
  131. }
  132. // push chunk over to peer
  133. func Push(p *peer, key storage.Key, priority uint) {
  134. p.syncer.doDelivery(key, priority, p.syncer.quit)
  135. }