implemented Api.Modify

This commit is contained in:
zsfelfoldi 2015-05-30 09:51:21 +02:00
parent a762134519
commit 3113b1cdc9
2 changed files with 64 additions and 23 deletions

View file

@ -122,6 +122,31 @@ func (self *Api) Put(content, contentType string) (string, error) {
return fmt.Sprintf("%064x", key), nil return fmt.Sprintf("%064x", key), nil
} }
func (self *Api) Modify(rootHash, path, contentHash, contentType string) (newRootHash string, err error) {
root := common.Hex2Bytes(rootHash)
trie, err := loadManifestTrie(self.dpa, root)
if err != nil {
return
}
if contentHash != "" {
entry := &manifestTrieEntry{
Path: path,
Hash: contentHash,
ContentType: contentType,
}
trie.addEntry(entry)
} else {
trie.deleteEntry(path)
}
err = trie.recalcAndStore()
if err != nil {
return
}
return fmt.Sprintf("%064x", trie.hash), nil
}
// Download replicates the manifest path structure on the local filesystem // Download replicates the manifest path structure on the local filesystem
// under localpath // under localpath
func (self *Api) Download(bzzpath, localpath string) (string, error) { func (self *Api) Download(bzzpath, localpath string) (string, error) {
@ -205,7 +230,9 @@ func (self *Api) Upload(lpath string) (string, error) {
dcnt++ dcnt++
} }
trie := &manifestTrie{} trie := &manifestTrie{
dpa: self.dpa,
}
for i, entry := range list { for i, entry := range list {
if errors[i] != nil { if errors[i] != nil {
return "", errors[i] return "", errors[i]
@ -214,7 +241,7 @@ func (self *Api) Upload(lpath string) (string, error) {
trie.addEntry(entry) trie.addEntry(entry)
} }
err2 := trie.recalcAndStore(self.dpa) err2 := trie.recalcAndStore()
var hs string var hs string
if err2 == nil { if err2 == nil {
hs = fmt.Sprintf("%064x", trie.hash) hs = fmt.Sprintf("%064x", trie.hash)
@ -290,7 +317,7 @@ func (self *Api) getPath(uri string) (reader SectionReader, mimeType string, sta
return return
} }
entry, _ := trie.getEntry(self.dpa, path) entry, _ := trie.getEntry(path)
if entry != nil { if entry != nil {
key = common.Hex2Bytes(entry.Hash) key = common.Hex2Bytes(entry.Hash)
status = entry.Status status = entry.Status

View file

@ -15,6 +15,7 @@ const (
) )
type manifestTrie struct { type manifestTrie struct {
dpa *DPA
entries [257]*manifestTrieEntry // indexed by first character of path, entries[256] is the empty path entry entries [257]*manifestTrieEntry // indexed by first character of path, entries[256] is the empty path entry
hash Key // if hash != nil, it is stored hash Key // if hash != nil, it is stored
} }
@ -31,7 +32,7 @@ type manifestTrieEntry struct {
subtrie *manifestTrie subtrie *manifestTrie
} }
func loadManifestTrie(dpa *DPA, hash Key) (trie *manifestTrie, err error) { func loadManifestTrie(dpa *DPA, hash Key) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand
dpaLogger.Debugf("Swarm: manifest lookup key: '%064x'.", hash) dpaLogger.Debugf("Swarm: manifest lookup key: '%064x'.", hash)
// retrieve manifest via DPA // retrieve manifest via DPA
@ -59,7 +60,9 @@ func loadManifestTrie(dpa *DPA, hash Key) (trie *manifestTrie, err error) {
dpaLogger.Debugf("Swarm: Manifest %064x has %d entries.", hash, len(man.Entries)) dpaLogger.Debugf("Swarm: Manifest %064x has %d entries.", hash, len(man.Entries))
trie = &manifestTrie{} trie = &manifestTrie{
dpa: dpa,
}
for _, entry := range man.Entries { for _, entry := range man.Entries {
trie.addEntry(entry) trie.addEntry(entry)
} }
@ -87,6 +90,9 @@ func (self *manifestTrie) addEntry(entry *manifestTrieEntry) {
} }
if (oldentry.ContentType == manifestType) && (cpl == len(oldentry.Path)) { if (oldentry.ContentType == manifestType) && (cpl == len(oldentry.Path)) {
if self.loadSubTrie(oldentry) != nil {
return
}
entry.Path = entry.Path[cpl:] entry.Path = entry.Path[cpl:]
oldentry.subtrie.addEntry(entry) oldentry.subtrie.addEntry(entry)
oldentry.Hash = "" oldentry.Hash = ""
@ -95,7 +101,9 @@ func (self *manifestTrie) addEntry(entry *manifestTrieEntry) {
commonPrefix := entry.Path[:cpl] commonPrefix := entry.Path[:cpl]
subtrie := &manifestTrie{} subtrie := &manifestTrie{
dpa: self.dpa,
}
entry.Path = entry.Path[cpl:] entry.Path = entry.Path[cpl:]
oldentry.Path = oldentry.Path[cpl:] oldentry.Path = oldentry.Path[cpl:]
subtrie.addEntry(entry) subtrie.addEntry(entry)
@ -136,6 +144,9 @@ func (self *manifestTrie) deleteEntry(path string) {
epl := len(entry.Path) epl := len(entry.Path)
if (entry.ContentType == manifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) { if (entry.ContentType == manifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) {
if self.loadSubTrie(entry) != nil {
return
}
entry.subtrie.deleteEntry(path[epl:]) entry.subtrie.deleteEntry(path[epl:])
entry.Hash = "" entry.Hash = ""
// remove subtree if it has less than 2 elements // remove subtree if it has less than 2 elements
@ -149,7 +160,7 @@ func (self *manifestTrie) deleteEntry(path string) {
} }
} }
func (self *manifestTrie) recalcAndStore(dpa *DPA) error { func (self *manifestTrie) recalcAndStore() error {
if self.hash != nil { if self.hash != nil {
return nil return nil
} }
@ -161,7 +172,7 @@ func (self *manifestTrie) recalcAndStore(dpa *DPA) error {
for _, entry := range self.entries { for _, entry := range self.entries {
if entry != nil { if entry != nil {
if entry.Hash == "" { // TODO: paralellize if entry.Hash == "" { // TODO: paralellize
err := entry.subtrie.recalcAndStore(dpa) err := entry.subtrie.recalcAndStore()
if err != nil { if err != nil {
return err return err
} }
@ -178,13 +189,22 @@ func (self *manifestTrie) recalcAndStore(dpa *DPA) error {
sr := io.NewSectionReader(bytes.NewReader(manifest), 0, int64(len(manifest))) sr := io.NewSectionReader(bytes.NewReader(manifest), 0, int64(len(manifest)))
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
key, err2 := dpa.Store(sr, wg) key, err2 := self.dpa.Store(sr, wg)
wg.Wait() wg.Wait()
self.hash = key self.hash = key
return err2 return err2
} }
func (self *manifestTrie) findPrefixOf(dpa *DPA, path string) (entry *manifestTrieEntry, pos int) { func (self *manifestTrie) loadSubTrie(entry *manifestTrieEntry) (err error) {
if entry.subtrie == nil {
hash := common.Hex2Bytes(entry.Hash)
entry.subtrie, err = loadManifestTrie(self.dpa, hash)
entry.Hash = "" // might not match, should be recalculated
}
return
}
func (self *manifestTrie) findPrefixOf(path string) (entry *manifestTrieEntry, pos int) {
if len(path) == 0 { if len(path) == 0 {
return self.entries[256], 0 return self.entries[256], 0
} }
@ -194,16 +214,10 @@ func (self *manifestTrie) findPrefixOf(dpa *DPA, path string) (entry *manifestTr
epl := len(entry.Path) epl := len(entry.Path)
if (len(path) >= epl) && (path[:epl] == entry.Path) { if (len(path) >= epl) && (path[:epl] == entry.Path) {
if entry.ContentType == manifestType { if entry.ContentType == manifestType {
if entry.subtrie == nil { if self.loadSubTrie(entry) != nil {
hash := common.Hex2Bytes(entry.Hash) return nil, 0
var err error
entry.subtrie, err = loadManifestTrie(dpa, hash)
if err != nil {
return nil, 0
}
entry.Hash = "" // might not match, should be recalculated
} }
entry, pos = entry.subtrie.findPrefixOf(dpa, path[epl:]) entry, pos = entry.subtrie.findPrefixOf(path[epl:])
if entry != nil { if entry != nil {
pos += epl pos += epl
} }
@ -216,8 +230,8 @@ func (self *manifestTrie) findPrefixOf(dpa *DPA, path string) (entry *manifestTr
return return
} }
func (self *manifestTrie) getEntryNLS(dpa *DPA, path string) (entry *manifestTrieEntry, pos int) { func (self *manifestTrie) getEntryNLS(path string) (entry *manifestTrieEntry, pos int) {
entry, pos = self.findPrefixOf(dpa, path) entry, pos = self.findPrefixOf(path)
if entry != nil { if entry != nil {
for (pos < len(path)) && (path[pos] == '/') { for (pos < len(path)) && (path[pos] == '/') {
pos++ pos++
@ -229,10 +243,10 @@ func (self *manifestTrie) getEntryNLS(dpa *DPA, path string) (entry *manifestTri
return return
} }
func (self *manifestTrie) getEntry(dpa *DPA, path string) (entry *manifestTrieEntry, pos int) { func (self *manifestTrie) getEntry(path string) (entry *manifestTrieEntry, pos int) {
var slash string var slash string
for { for {
entry, pos = self.getEntryNLS(dpa, slash+path) entry, pos = self.getEntryNLS(slash + path)
if pos < len(slash) { if pos < len(slash) {
dpaLogger.Debugf("Path '%s' on manifest not found.", path) dpaLogger.Debugf("Path '%s' on manifest not found.", path)
return nil, 0 return nil, 0