manifest.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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 api
  17. import (
  18. "bytes"
  19. "encoding/json"
  20. "fmt"
  21. "sync"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/logger"
  24. "github.com/ethereum/go-ethereum/logger/glog"
  25. "github.com/ethereum/go-ethereum/swarm/storage"
  26. )
  27. const (
  28. manifestType = "application/bzz-manifest+json"
  29. )
  30. type manifestTrie struct {
  31. dpa *storage.DPA
  32. entries [257]*manifestTrieEntry // indexed by first character of path, entries[256] is the empty path entry
  33. hash storage.Key // if hash != nil, it is stored
  34. }
  35. type manifestJSON struct {
  36. Entries []*manifestTrieEntry `json:"entries"`
  37. }
  38. type manifestTrieEntry struct {
  39. Path string `json:"path"`
  40. Hash string `json:"hash"` // for manifest content type, empty until subtrie is evaluated
  41. ContentType string `json:"contentType"`
  42. Status int `json:"status"`
  43. subtrie *manifestTrie
  44. }
  45. func loadManifest(dpa *storage.DPA, hash storage.Key, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand
  46. glog.V(logger.Detail).Infof("manifest lookup key: '%v'.", hash.Log())
  47. // retrieve manifest via DPA
  48. manifestReader := dpa.Retrieve(hash)
  49. return readManifest(manifestReader, hash, dpa, quitC)
  50. }
  51. func readManifest(manifestReader storage.LazySectionReader, hash storage.Key, dpa *storage.DPA, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand
  52. // TODO check size for oversized manifests
  53. size, err := manifestReader.Size(quitC)
  54. if err != nil { // size == 0
  55. // can't determine size means we don't have the root chunk
  56. err = fmt.Errorf("Manifest not Found")
  57. return
  58. }
  59. manifestData := make([]byte, size)
  60. read, err := manifestReader.Read(manifestData)
  61. if int64(read) < size {
  62. glog.V(logger.Detail).Infof("Manifest %v not found.", hash.Log())
  63. if err == nil {
  64. err = fmt.Errorf("Manifest retrieval cut short: read %v, expect %v", read, size)
  65. }
  66. return
  67. }
  68. glog.V(logger.Detail).Infof("Manifest %v retrieved", hash.Log())
  69. man := manifestJSON{}
  70. err = json.Unmarshal(manifestData, &man)
  71. if err != nil {
  72. err = fmt.Errorf("Manifest %v is malformed: %v", hash.Log(), err)
  73. glog.V(logger.Detail).Infof("%v", err)
  74. return
  75. }
  76. glog.V(logger.Detail).Infof("Manifest %v has %d entries.", hash.Log(), len(man.Entries))
  77. trie = &manifestTrie{
  78. dpa: dpa,
  79. }
  80. for _, entry := range man.Entries {
  81. trie.addEntry(entry, quitC)
  82. }
  83. return
  84. }
  85. func (self *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) {
  86. self.hash = nil // trie modified, hash needs to be re-calculated on demand
  87. if len(entry.Path) == 0 {
  88. self.entries[256] = entry
  89. return
  90. }
  91. b := byte(entry.Path[0])
  92. if (self.entries[b] == nil) || (self.entries[b].Path == entry.Path) {
  93. self.entries[b] = entry
  94. return
  95. }
  96. oldentry := self.entries[b]
  97. cpl := 0
  98. for (len(entry.Path) > cpl) && (len(oldentry.Path) > cpl) && (entry.Path[cpl] == oldentry.Path[cpl]) {
  99. cpl++
  100. }
  101. if (oldentry.ContentType == manifestType) && (cpl == len(oldentry.Path)) {
  102. if self.loadSubTrie(oldentry, quitC) != nil {
  103. return
  104. }
  105. entry.Path = entry.Path[cpl:]
  106. oldentry.subtrie.addEntry(entry, quitC)
  107. oldentry.Hash = ""
  108. return
  109. }
  110. commonPrefix := entry.Path[:cpl]
  111. subtrie := &manifestTrie{
  112. dpa: self.dpa,
  113. }
  114. entry.Path = entry.Path[cpl:]
  115. oldentry.Path = oldentry.Path[cpl:]
  116. subtrie.addEntry(entry, quitC)
  117. subtrie.addEntry(oldentry, quitC)
  118. self.entries[b] = &manifestTrieEntry{
  119. Path: commonPrefix,
  120. Hash: "",
  121. ContentType: manifestType,
  122. subtrie: subtrie,
  123. }
  124. }
  125. func (self *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) {
  126. for _, e := range self.entries {
  127. if e != nil {
  128. cnt++
  129. entry = e
  130. }
  131. }
  132. return
  133. }
  134. func (self *manifestTrie) deleteEntry(path string, quitC chan bool) {
  135. self.hash = nil // trie modified, hash needs to be re-calculated on demand
  136. if len(path) == 0 {
  137. self.entries[256] = nil
  138. return
  139. }
  140. b := byte(path[0])
  141. entry := self.entries[b]
  142. if entry == nil {
  143. return
  144. }
  145. if entry.Path == path {
  146. self.entries[b] = nil
  147. return
  148. }
  149. epl := len(entry.Path)
  150. if (entry.ContentType == manifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) {
  151. if self.loadSubTrie(entry, quitC) != nil {
  152. return
  153. }
  154. entry.subtrie.deleteEntry(path[epl:], quitC)
  155. entry.Hash = ""
  156. // remove subtree if it has less than 2 elements
  157. cnt, lastentry := entry.subtrie.getCountLast()
  158. if cnt < 2 {
  159. if lastentry != nil {
  160. lastentry.Path = entry.Path + lastentry.Path
  161. }
  162. self.entries[b] = lastentry
  163. }
  164. }
  165. }
  166. func (self *manifestTrie) recalcAndStore() error {
  167. if self.hash != nil {
  168. return nil
  169. }
  170. var buffer bytes.Buffer
  171. buffer.WriteString(`{"entries":[`)
  172. list := &manifestJSON{}
  173. for _, entry := range self.entries {
  174. if entry != nil {
  175. if entry.Hash == "" { // TODO: paralellize
  176. err := entry.subtrie.recalcAndStore()
  177. if err != nil {
  178. return err
  179. }
  180. entry.Hash = entry.subtrie.hash.String()
  181. }
  182. list.Entries = append(list.Entries, entry)
  183. }
  184. }
  185. manifest, err := json.Marshal(list)
  186. if err != nil {
  187. return err
  188. }
  189. sr := bytes.NewReader(manifest)
  190. wg := &sync.WaitGroup{}
  191. key, err2 := self.dpa.Store(sr, int64(len(manifest)), wg, nil)
  192. wg.Wait()
  193. self.hash = key
  194. return err2
  195. }
  196. func (self *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) {
  197. if entry.subtrie == nil {
  198. hash := common.Hex2Bytes(entry.Hash)
  199. entry.subtrie, err = loadManifest(self.dpa, hash, quitC)
  200. entry.Hash = "" // might not match, should be recalculated
  201. }
  202. return
  203. }
  204. func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error {
  205. plen := len(prefix)
  206. var start, stop int
  207. if plen == 0 {
  208. start = 0
  209. stop = 256
  210. } else {
  211. start = int(prefix[0])
  212. stop = start
  213. }
  214. for i := start; i <= stop; i++ {
  215. select {
  216. case <-quitC:
  217. return fmt.Errorf("aborted")
  218. default:
  219. }
  220. entry := self.entries[i]
  221. if entry != nil {
  222. epl := len(entry.Path)
  223. if entry.ContentType == manifestType {
  224. l := plen
  225. if epl < l {
  226. l = epl
  227. }
  228. if prefix[:l] == entry.Path[:l] {
  229. err := self.loadSubTrie(entry, quitC)
  230. if err != nil {
  231. return err
  232. }
  233. err = entry.subtrie.listWithPrefixInt(prefix[l:], rp+entry.Path[l:], quitC, cb)
  234. if err != nil {
  235. return err
  236. }
  237. }
  238. } else {
  239. if (epl >= plen) && (prefix == entry.Path[:plen]) {
  240. cb(entry, rp+entry.Path[plen:])
  241. }
  242. }
  243. }
  244. }
  245. return nil
  246. }
  247. func (self *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) {
  248. return self.listWithPrefixInt(prefix, "", quitC, cb)
  249. }
  250. func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) {
  251. glog.V(logger.Detail).Infof("findPrefixOf(%s)", path)
  252. if len(path) == 0 {
  253. return self.entries[256], 0
  254. }
  255. b := byte(path[0])
  256. entry = self.entries[b]
  257. if entry == nil {
  258. return self.entries[256], 0
  259. }
  260. epl := len(entry.Path)
  261. glog.V(logger.Detail).Infof("path = %v entry.Path = %v epl = %v", path, entry.Path, epl)
  262. if (len(path) >= epl) && (path[:epl] == entry.Path) {
  263. glog.V(logger.Detail).Infof("entry.ContentType = %v", entry.ContentType)
  264. if entry.ContentType == manifestType {
  265. err := self.loadSubTrie(entry, quitC)
  266. if err != nil {
  267. return nil, 0
  268. }
  269. entry, pos = entry.subtrie.findPrefixOf(path[epl:], quitC)
  270. if entry != nil {
  271. pos += epl
  272. }
  273. } else {
  274. pos = epl
  275. }
  276. }
  277. return
  278. }
  279. // file system manifest always contains regularized paths
  280. // no leading or trailing slashes, only single slashes inside
  281. func RegularSlashes(path string) (res string) {
  282. for i := 0; i < len(path); i++ {
  283. if (path[i] != '/') || ((i > 0) && (path[i-1] != '/')) {
  284. res = res + path[i:i+1]
  285. }
  286. }
  287. if (len(res) > 0) && (res[len(res)-1] == '/') {
  288. res = res[:len(res)-1]
  289. }
  290. return
  291. }
  292. func (self *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) {
  293. path := RegularSlashes(spath)
  294. var pos int
  295. quitC := make(chan bool)
  296. entry, pos = self.findPrefixOf(path, quitC)
  297. return entry, path[:pos]
  298. }