mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
Merge 8eeb64a578 into 577d375a0d
This commit is contained in:
commit
c3cd3f997a
42 changed files with 1176 additions and 1183 deletions
|
|
@ -46,7 +46,7 @@ var (
|
||||||
apiPutFail = metrics.NewRegisteredCounter("api.put.fail", nil)
|
apiPutFail = metrics.NewRegisteredCounter("api.put.fail", nil)
|
||||||
apiGetCount = metrics.NewRegisteredCounter("api.get.count", nil)
|
apiGetCount = metrics.NewRegisteredCounter("api.get.count", nil)
|
||||||
apiGetNotFound = metrics.NewRegisteredCounter("api.get.notfound", nil)
|
apiGetNotFound = metrics.NewRegisteredCounter("api.get.notfound", nil)
|
||||||
apiGetHttp300 = metrics.NewRegisteredCounter("api.get.http.300", nil)
|
apiGetHTTP300 = metrics.NewRegisteredCounter("api.get.http.300", nil)
|
||||||
apiModifyCount = metrics.NewRegisteredCounter("api.modify.count", nil)
|
apiModifyCount = metrics.NewRegisteredCounter("api.modify.count", nil)
|
||||||
apiModifyFail = metrics.NewRegisteredCounter("api.modify.fail", nil)
|
apiModifyFail = metrics.NewRegisteredCounter("api.modify.fail", nil)
|
||||||
apiAddFileCount = metrics.NewRegisteredCounter("api.addfile.count", nil)
|
apiAddFileCount = metrics.NewRegisteredCounter("api.addfile.count", nil)
|
||||||
|
|
@ -146,7 +146,7 @@ type Api struct {
|
||||||
dns Resolver
|
dns Resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
//the api constructor initialises
|
//NewApi constructor initialises
|
||||||
func NewApi(dpa *storage.DPA, dns Resolver) (self *Api) {
|
func NewApi(dpa *storage.DPA, dns Resolver) (self *Api) {
|
||||||
self = &Api{
|
self = &Api{
|
||||||
dpa: dpa,
|
dpa: dpa,
|
||||||
|
|
@ -155,26 +155,26 @@ func NewApi(dpa *storage.DPA, dns Resolver) (self *Api) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// to be used only in TEST
|
// Upload to be used only in TEST
|
||||||
func (self *Api) Upload(uploadDir, index string) (hash string, err error) {
|
func (api *Api) Upload(uploadDir, index string) (hash string, err error) {
|
||||||
fs := NewFileSystem(self)
|
fs := NewFileSystem(api)
|
||||||
hash, err = fs.Upload(uploadDir, index)
|
hash, err = fs.Upload(uploadDir, index)
|
||||||
return hash, err
|
return hash, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DPA reader API
|
// Retrieve implements DPA reader API
|
||||||
func (self *Api) Retrieve(key storage.Key) storage.LazySectionReader {
|
func (api *Api) Retrieve(key storage.Key) storage.LazySectionReader {
|
||||||
return self.dpa.Retrieve(key)
|
return api.dpa.Retrieve(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) Store(data io.Reader, size int64, wg *sync.WaitGroup) (key storage.Key, err error) {
|
func (api *Api) Store(data io.Reader, size int64, wg *sync.WaitGroup) (key storage.Key, err error) {
|
||||||
return self.dpa.Store(data, size, wg, nil)
|
return api.dpa.Store(data, size, wg, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrResolve error
|
type ErrResolve error
|
||||||
|
|
||||||
// DNS Resolver
|
// Resolve implements DNS Resolver
|
||||||
func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
func (api *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||||
apiResolveCount.Inc(1)
|
apiResolveCount.Inc(1)
|
||||||
log.Trace(fmt.Sprintf("Resolving : %v", uri.Addr))
|
log.Trace(fmt.Sprintf("Resolving : %v", uri.Addr))
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if DNS is not configured, check if the address is a hash
|
// if DNS is not configured, check if the address is a hash
|
||||||
if self.dns == nil {
|
if api.dns == nil {
|
||||||
if !isHash {
|
if !isHash {
|
||||||
apiResolveFail.Inc(1)
|
apiResolveFail.Inc(1)
|
||||||
return nil, fmt.Errorf("no DNS to resolve name: %q", uri.Addr)
|
return nil, fmt.Errorf("no DNS to resolve name: %q", uri.Addr)
|
||||||
|
|
@ -197,7 +197,7 @@ func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// try and resolve the address
|
// try and resolve the address
|
||||||
resolved, err := self.dns.Resolve(uri.Addr)
|
resolved, err := api.dns.Resolve(uri.Addr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return resolved[:], nil
|
return resolved[:], nil
|
||||||
} else if !isHash {
|
} else if !isHash {
|
||||||
|
|
@ -208,18 +208,18 @@ func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put provides singleton manifest creation on top of dpa store
|
// Put provides singleton manifest creation on top of dpa store
|
||||||
func (self *Api) Put(content, contentType string) (storage.Key, error) {
|
func (api *Api) Put(content, contentType string) (storage.Key, error) {
|
||||||
apiPutCount.Inc(1)
|
apiPutCount.Inc(1)
|
||||||
r := strings.NewReader(content)
|
r := strings.NewReader(content)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
key, err := self.dpa.Store(r, int64(len(content)), wg, nil)
|
key, err := api.dpa.Store(r, int64(len(content)), wg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiPutFail.Inc(1)
|
apiPutFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
|
manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
|
||||||
r = strings.NewReader(manifest)
|
r = strings.NewReader(manifest)
|
||||||
key, err = self.dpa.Store(r, int64(len(manifest)), wg, nil)
|
key, err = api.dpa.Store(r, int64(len(manifest)), wg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiPutFail.Inc(1)
|
apiPutFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -231,9 +231,9 @@ func (self *Api) Put(content, contentType string) (storage.Key, error) {
|
||||||
// Get uses iterative manifest retrieval and prefix matching
|
// Get uses iterative manifest retrieval and prefix matching
|
||||||
// to resolve basePath to content using dpa retrieve
|
// to resolve basePath to content using dpa retrieve
|
||||||
// it returns a section reader, mimeType, status and an error
|
// it returns a section reader, mimeType, status and an error
|
||||||
func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionReader, mimeType string, status int, err error) {
|
func (api *Api) Get(key storage.Key, path string) (reader storage.LazySectionReader, mimeType string, status int, err error) {
|
||||||
apiGetCount.Inc(1)
|
apiGetCount.Inc(1)
|
||||||
trie, err := loadManifest(self.dpa, key, nil)
|
trie, err := loadManifest(api.dpa, key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiGetNotFound.Inc(1)
|
apiGetNotFound.Inc(1)
|
||||||
status = http.StatusNotFound
|
status = http.StatusNotFound
|
||||||
|
|
@ -249,13 +249,12 @@ func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionRe
|
||||||
key = common.Hex2Bytes(entry.Hash)
|
key = common.Hex2Bytes(entry.Hash)
|
||||||
status = entry.Status
|
status = entry.Status
|
||||||
if status == http.StatusMultipleChoices {
|
if status == http.StatusMultipleChoices {
|
||||||
apiGetHttp300.Inc(1)
|
apiGetHTTP300.Inc(1)
|
||||||
return
|
return
|
||||||
} else {
|
}
|
||||||
mimeType = entry.ContentType
|
mimeType = entry.ContentType
|
||||||
log.Trace(fmt.Sprintf("content lookup key: '%v' (%v)", key, mimeType))
|
log.Trace(fmt.Sprintf("content lookup key: '%v' (%v)", key, mimeType))
|
||||||
reader = self.dpa.Retrieve(key)
|
reader = api.dpa.Retrieve(key)
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
status = http.StatusNotFound
|
status = http.StatusNotFound
|
||||||
apiGetNotFound.Inc(1)
|
apiGetNotFound.Inc(1)
|
||||||
|
|
@ -265,10 +264,10 @@ func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionRe
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) Modify(key storage.Key, path, contentHash, contentType string) (storage.Key, error) {
|
func (api *Api) Modify(key storage.Key, path, contentHash, contentType string) (storage.Key, error) {
|
||||||
apiModifyCount.Inc(1)
|
apiModifyCount.Inc(1)
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
trie, err := loadManifest(self.dpa, key, quitC)
|
trie, err := loadManifest(api.dpa, key, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiModifyFail.Inc(1)
|
apiModifyFail.Inc(1)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -291,7 +290,7 @@ func (self *Api) Modify(key storage.Key, path, contentHash, contentType string)
|
||||||
return trie.hash, nil
|
return trie.hash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver bool) (storage.Key, string, error) {
|
func (api *Api) AddFile(mhash, path, fname string, content []byte, nameresolver bool) (storage.Key, string, error) {
|
||||||
apiAddFileCount.Inc(1)
|
apiAddFileCount.Inc(1)
|
||||||
|
|
||||||
uri, err := Parse("bzz:/" + mhash)
|
uri, err := Parse("bzz:/" + mhash)
|
||||||
|
|
@ -299,7 +298,7 @@ func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver
|
||||||
apiAddFileFail.Inc(1)
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
mkey, err := self.Resolve(uri)
|
mkey, err := api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiAddFileFail.Inc(1)
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
@ -318,7 +317,7 @@ func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver
|
||||||
ModTime: time.Now(),
|
ModTime: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
mw, err := self.NewManifestWriter(mkey, nil)
|
mw, err := api.NewManifestWriter(mkey, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiAddFileFail.Inc(1)
|
apiAddFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
@ -341,7 +340,7 @@ func (self *Api) AddFile(mhash, path, fname string, content []byte, nameresolver
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (string, error) {
|
func (api *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (string, error) {
|
||||||
apiRmFileCount.Inc(1)
|
apiRmFileCount.Inc(1)
|
||||||
|
|
||||||
uri, err := Parse("bzz:/" + mhash)
|
uri, err := Parse("bzz:/" + mhash)
|
||||||
|
|
@ -349,7 +348,7 @@ func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (strin
|
||||||
apiRmFileFail.Inc(1)
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
mkey, err := self.Resolve(uri)
|
mkey, err := api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiRmFileFail.Inc(1)
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -360,7 +359,7 @@ func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (strin
|
||||||
path = path[1:]
|
path = path[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
mw, err := self.NewManifestWriter(mkey, nil)
|
mw, err := api.NewManifestWriter(mkey, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiRmFileFail.Inc(1)
|
apiRmFileFail.Inc(1)
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -382,7 +381,7 @@ func (self *Api) RemoveFile(mhash, path, fname string, nameresolver bool) (strin
|
||||||
return newMkey.String(), nil
|
return newMkey.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, content []byte, oldKey storage.Key, offset int64, addSize int64, nameresolver bool) (storage.Key, string, error) {
|
func (api *Api) AppendFile(mhash, path, fname string, existingSize int64, content []byte, oldKey storage.Key, offset int64, addSize int64, nameresolver bool) (storage.Key, string, error) {
|
||||||
apiAppendFileCount.Inc(1)
|
apiAppendFileCount.Inc(1)
|
||||||
|
|
||||||
buffSize := offset + addSize
|
buffSize := offset + addSize
|
||||||
|
|
@ -392,7 +391,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
|
|
||||||
buf := make([]byte, buffSize)
|
buf := make([]byte, buffSize)
|
||||||
|
|
||||||
oldReader := self.Retrieve(oldKey)
|
oldReader := api.Retrieve(oldKey)
|
||||||
io.ReadAtLeast(oldReader, buf, int(offset))
|
io.ReadAtLeast(oldReader, buf, int(offset))
|
||||||
|
|
||||||
newReader := bytes.NewReader(content)
|
newReader := bytes.NewReader(content)
|
||||||
|
|
@ -406,7 +405,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
totalSize := int64(len(buf))
|
totalSize := int64(len(buf))
|
||||||
|
|
||||||
// TODO(jmozah): to append using pyramid chunker when it is ready
|
// TODO(jmozah): to append using pyramid chunker when it is ready
|
||||||
//oldReader := self.Retrieve(oldKey)
|
//oldReader := api.Retrieve(oldKey)
|
||||||
//newReader := bytes.NewReader(content)
|
//newReader := bytes.NewReader(content)
|
||||||
//combinedReader := io.MultiReader(oldReader, newReader)
|
//combinedReader := io.MultiReader(oldReader, newReader)
|
||||||
|
|
||||||
|
|
@ -415,7 +414,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
apiAppendFileFail.Inc(1)
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
mkey, err := self.Resolve(uri)
|
mkey, err := api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiAppendFileFail.Inc(1)
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
@ -426,7 +425,7 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
path = path[1:]
|
path = path[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
mw, err := self.NewManifestWriter(mkey, nil)
|
mw, err := api.NewManifestWriter(mkey, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiAppendFileFail.Inc(1)
|
apiAppendFileFail.Inc(1)
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
|
|
@ -463,19 +462,19 @@ func (self *Api) AppendFile(mhash, path, fname string, existingSize int64, conte
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storage.Key, manifestEntryMap map[string]*manifestTrieEntry, err error) {
|
func (api *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storage.Key, manifestEntryMap map[string]*manifestTrieEntry, err error) {
|
||||||
|
|
||||||
uri, err := Parse("bzz:/" + mhash)
|
uri, err := Parse("bzz:/" + mhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
key, err = self.Resolve(uri)
|
key, err = api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
rootTrie, err := loadManifest(self.dpa, key, quitC)
|
rootTrie, err := loadManifest(api.dpa, key, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("can't load manifest %v: %v", key.String(), err)
|
return nil, nil, fmt.Errorf("can't load manifest %v: %v", key.String(), err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/swarm/storage"
|
"github.com/ethereum/go-ethereum/swarm/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testApi(t *testing.T, f func(*Api)) {
|
func testAPI(t *testing.T, f func(*Api)) {
|
||||||
datadir, err := ioutil.TempDir("", "bzz-test")
|
datadir, err := ioutil.TempDir("", "bzz-test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to create temp dir: %v", err)
|
t.Fatalf("unable to create temp dir: %v", err)
|
||||||
|
|
@ -106,7 +106,7 @@ func testGet(t *testing.T, api *Api, bzzhash, path string) *testResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApiPut(t *testing.T) {
|
func TestApiPut(t *testing.T) {
|
||||||
testApi(t, func(api *Api) {
|
testAPI(t, func(api *Api) {
|
||||||
content := "hello"
|
content := "hello"
|
||||||
exp := expResponse(content, "text/plain", 0)
|
exp := expResponse(content, "text/plain", 0)
|
||||||
// exp := expResponse([]byte(content), "text/plain", 0)
|
// exp := expResponse([]byte(content), "text/plain", 0)
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ const (
|
||||||
DefaultHTTPPort = "8500"
|
DefaultHTTPPort = "8500"
|
||||||
)
|
)
|
||||||
|
|
||||||
// separate bzz directories
|
// Config separates bzz directories
|
||||||
// allow several bzz nodes running in parallel
|
// allow several bzz nodes running in parallel
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// serialised/persisted fields
|
// serialised/persisted fields
|
||||||
|
|
@ -63,10 +63,10 @@ type Config struct {
|
||||||
BootNodes string
|
BootNodes string
|
||||||
}
|
}
|
||||||
|
|
||||||
//create a default config with all parameters to set to defaults
|
// NewDefaultConfig creates a default config with all parameters to set to defaults
|
||||||
func NewDefaultConfig() (self *Config) {
|
func NewDefaultConfig() (config *Config) {
|
||||||
|
|
||||||
self = &Config{
|
config = &Config{
|
||||||
StoreParams: storage.NewDefaultStoreParams(),
|
StoreParams: storage.NewDefaultStoreParams(),
|
||||||
ChunkerParams: storage.NewChunkerParams(),
|
ChunkerParams: storage.NewChunkerParams(),
|
||||||
HiveParams: network.NewDefaultHiveParams(),
|
HiveParams: network.NewDefaultHiveParams(),
|
||||||
|
|
@ -89,11 +89,11 @@ func NewDefaultConfig() (self *Config) {
|
||||||
|
|
||||||
//some config params need to be initialized after the complete
|
//some config params need to be initialized after the complete
|
||||||
//config building phase is completed (e.g. due to overriding flags)
|
//config building phase is completed (e.g. due to overriding flags)
|
||||||
func (self *Config) Init(prvKey *ecdsa.PrivateKey) {
|
func (config *Config) Init(prvKey *ecdsa.PrivateKey) {
|
||||||
|
|
||||||
address := crypto.PubkeyToAddress(prvKey.PublicKey)
|
address := crypto.PubkeyToAddress(prvKey.PublicKey)
|
||||||
self.Path = filepath.Join(self.Path, "bzz-"+common.Bytes2Hex(address.Bytes()))
|
config.Path = filepath.Join(config.Path, "bzz-"+common.Bytes2Hex(address.Bytes()))
|
||||||
err := os.MkdirAll(self.Path, os.ModePerm)
|
err := os.MkdirAll(config.Path, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(fmt.Sprintf("Error creating root swarm data directory: %v", err))
|
log.Error(fmt.Sprintf("Error creating root swarm data directory: %v", err))
|
||||||
return
|
return
|
||||||
|
|
@ -103,11 +103,11 @@ func (self *Config) Init(prvKey *ecdsa.PrivateKey) {
|
||||||
pubkeyhex := common.ToHex(pubkey)
|
pubkeyhex := common.ToHex(pubkey)
|
||||||
keyhex := crypto.Keccak256Hash(pubkey).Hex()
|
keyhex := crypto.Keccak256Hash(pubkey).Hex()
|
||||||
|
|
||||||
self.PublicKey = pubkeyhex
|
config.PublicKey = pubkeyhex
|
||||||
self.BzzKey = keyhex
|
config.BzzKey = keyhex
|
||||||
|
|
||||||
self.Swap.Init(self.Contract, prvKey)
|
config.Swap.Init(config.Contract, prvKey)
|
||||||
self.SyncParams.Init(self.Path)
|
config.SyncParams.Init(config.Path)
|
||||||
self.HiveParams.Init(self.Path)
|
config.HiveParams.Init(config.Path)
|
||||||
self.StoreParams.Init(self.Path)
|
config.StoreParams.Init(config.Path)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ func NewFileSystem(api *Api) *FileSystem {
|
||||||
// TODO: localpath should point to a manifest
|
// TODO: localpath should point to a manifest
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
func (self *FileSystem) Upload(lpath, index string) (string, error) {
|
func (fs *FileSystem) Upload(lpath, index string) (string, error) {
|
||||||
var list []*manifestTrieEntry
|
var list []*manifestTrieEntry
|
||||||
localpath, err := filepath.Abs(filepath.Clean(lpath))
|
localpath, err := filepath.Abs(filepath.Clean(lpath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -113,7 +113,7 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) {
|
||||||
stat, _ := f.Stat()
|
stat, _ := f.Stat()
|
||||||
var hash storage.Key
|
var hash storage.Key
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
hash, err = self.api.dpa.Store(f, stat.Size(), wg, nil)
|
hash, err = fs.api.dpa.Store(f, stat.Size(), wg, nil)
|
||||||
if hash != nil {
|
if hash != nil {
|
||||||
list[i].Hash = hash.String()
|
list[i].Hash = hash.String()
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +142,7 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
trie := &manifestTrie{
|
trie := &manifestTrie{
|
||||||
dpa: self.api.dpa,
|
dpa: fs.api.dpa,
|
||||||
}
|
}
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
for i, entry := range list {
|
for i, entry := range list {
|
||||||
|
|
@ -173,7 +173,7 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) {
|
||||||
// under localpath
|
// under localpath
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
func (self *FileSystem) Download(bzzpath, localpath string) error {
|
func (fs *FileSystem) Download(bzzpath, localpath string) error {
|
||||||
lpath, err := filepath.Abs(filepath.Clean(localpath))
|
lpath, err := filepath.Abs(filepath.Clean(localpath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -188,7 +188,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
key, err := self.api.Resolve(uri)
|
key, err := fs.api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +199,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
trie, err := loadManifest(self.api.dpa, key, quitC)
|
trie, err := loadManifest(fs.api.dpa, key, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("fs.Download: loadManifestTrie error: %v", err))
|
log.Warn(fmt.Sprintf("fs.Download: loadManifestTrie error: %v", err))
|
||||||
return err
|
return err
|
||||||
|
|
@ -244,7 +244,7 @@ func (self *FileSystem) Download(bzzpath, localpath string) error {
|
||||||
}
|
}
|
||||||
go func(i int, entry *downloadListEntry) {
|
go func(i int, entry *downloadListEntry) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
err := retrieveToFile(quitC, self.api.dpa, entry.key, entry.path)
|
err := retrieveToFile(quitC, fs.api.dpa, entry.key, entry.path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
select {
|
select {
|
||||||
case errC <- err:
|
case errC <- err:
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Show nicely (but simple) formatted HTML error pages (or respond with JSON
|
Package http shows nicely (but simple) formatted HTML error pages (or respond with JSON
|
||||||
if the appropriate `Accept` header is set)) for the http package.
|
if the appropriate `Accept` header is set)) for the http package.
|
||||||
*/
|
*/
|
||||||
package http
|
package http
|
||||||
|
|
@ -43,7 +43,7 @@ var (
|
||||||
jsonCounter = metrics.NewRegisteredCounter("api.http.errorpage.json.count", nil)
|
jsonCounter = metrics.NewRegisteredCounter("api.http.errorpage.json.count", nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
//parameters needed for formatting the correct HTML page
|
//ErrorParams needed for formatting the correct HTML page
|
||||||
type ErrorParams struct {
|
type ErrorParams struct {
|
||||||
Msg string
|
Msg string
|
||||||
Code int
|
Code int
|
||||||
|
|
@ -52,8 +52,8 @@ type ErrorParams struct {
|
||||||
Details template.HTML
|
Details template.HTML
|
||||||
}
|
}
|
||||||
|
|
||||||
//a custom error case struct that would be used to store validators and
|
//CaseError is a custom error case struct that would be used to store validators
|
||||||
//additional error info to display with client responses.
|
//and additional error info to display with client responses.
|
||||||
type CaseError struct {
|
type CaseError struct {
|
||||||
Validator func(*Request) bool
|
Validator func(*Request) bool
|
||||||
Msg func(*Request) string
|
Msg func(*Request) string
|
||||||
|
|
@ -107,7 +107,7 @@ func ValidateCaseErrors(r *Request) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
//ShowMultipeChoices is used when a user requests a resource in a manifest which results
|
//ShowMultipleChoices is used when a user requests a resource in a manifest which results
|
||||||
//in ambiguous results. It returns a HTML page with clickable links of each of the entry
|
//in ambiguous results. It returns a HTML page with clickable links of each of the entry
|
||||||
//in the manifest which fits the request URI ambiguity.
|
//in the manifest which fits the request URI ambiguity.
|
||||||
//For example, if the user requests bzz:/<hash>/read and that manifest contains entries
|
//For example, if the user requests bzz:/<hash>/read and that manifest contains entries
|
||||||
|
|
@ -164,14 +164,14 @@ func ShowError(w http.ResponseWriter, r *Request, msg string, code int) {
|
||||||
func respond(w http.ResponseWriter, r *http.Request, params *ErrorParams) {
|
func respond(w http.ResponseWriter, r *http.Request, params *ErrorParams) {
|
||||||
w.WriteHeader(params.Code)
|
w.WriteHeader(params.Code)
|
||||||
if r.Header.Get("Accept") == "application/json" {
|
if r.Header.Get("Accept") == "application/json" {
|
||||||
respondJson(w, params)
|
respondJSON(w, params)
|
||||||
} else {
|
} else {
|
||||||
respondHtml(w, params)
|
respondHTML(w, params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//return a HTML page
|
//return a HTML page
|
||||||
func respondHtml(w http.ResponseWriter, params *ErrorParams) {
|
func respondHTML(w http.ResponseWriter, params *ErrorParams) {
|
||||||
htmlCounter.Inc(1)
|
htmlCounter.Inc(1)
|
||||||
err := params.template.Execute(w, params)
|
err := params.template.Execute(w, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -180,7 +180,7 @@ func respondHtml(w http.ResponseWriter, params *ErrorParams) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//return JSON
|
//return JSON
|
||||||
func respondJson(w http.ResponseWriter, params *ErrorParams) {
|
func respondJSON(w http.ResponseWriter, params *ErrorParams) {
|
||||||
jsonCounter.Inc(1)
|
jsonCounter.Inc(1)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(params)
|
json.NewEncoder(w).Encode(params)
|
||||||
|
|
@ -190,7 +190,6 @@ func respondJson(w http.ResponseWriter, params *ErrorParams) {
|
||||||
func getTemplate(code int) *template.Template {
|
func getTemplate(code int) *template.Template {
|
||||||
if val, tmpl := templateMap[code]; tmpl {
|
if val, tmpl := templateMap[code]; tmpl {
|
||||||
return val
|
return val
|
||||||
} else {
|
}
|
||||||
return templateMap[0]
|
return templateMap[0]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,10 @@ they won't be found.
|
||||||
For this reason we resort to save the HTML error pages as strings, which then can be
|
For this reason we resort to save the HTML error pages as strings, which then can be
|
||||||
parsed by Go's html/template package
|
parsed by Go's html/template package
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package http
|
package http
|
||||||
|
|
||||||
//This returns the HTML for generic errors
|
// GetGenericErrorPage returns the HTML for generic errors
|
||||||
func GetGenericErrorPage() string {
|
func GetGenericErrorPage() string {
|
||||||
page := `
|
page := `
|
||||||
<html>
|
<html>
|
||||||
|
|
@ -206,7 +207,7 @@ func GetGenericErrorPage() string {
|
||||||
return page
|
return page
|
||||||
}
|
}
|
||||||
|
|
||||||
//This returns the HTML for a 404 Not Found error
|
// GetNotFoundErrorPage returns the HTML for a 404 Not Found error
|
||||||
func GetNotFoundErrorPage() string {
|
func GetNotFoundErrorPage() string {
|
||||||
page := `
|
page := `
|
||||||
<html>
|
<html>
|
||||||
|
|
@ -386,7 +387,7 @@ func GetNotFoundErrorPage() string {
|
||||||
return page
|
return page
|
||||||
}
|
}
|
||||||
|
|
||||||
//This returns the HTML for a page listing disambiguation options
|
//GetMultipleChoicesErrorPage returns the HTML for a page listing disambiguation options
|
||||||
//i.e. if user requested bzz:/<hash>/read and the manifest contains "readme.md" and "readinglist.txt",
|
//i.e. if user requested bzz:/<hash>/read and the manifest contains "readme.md" and "readinglist.txt",
|
||||||
//this page is returned with a clickable list the existing disambiguation links in the manifest
|
//this page is returned with a clickable list the existing disambiguation links in the manifest
|
||||||
func GetMultipleChoicesErrorPage() string {
|
func GetMultipleChoicesErrorPage() string {
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,12 @@ type RoundTripper struct {
|
||||||
Port string
|
Port string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
func (rt *RoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
||||||
host := self.Host
|
host := rt.Host
|
||||||
if len(host) == 0 {
|
if len(host) == 0 {
|
||||||
host = "localhost"
|
host = "localhost"
|
||||||
}
|
}
|
||||||
url := fmt.Sprintf("http://%s:%s/%s:/%s/%s", host, self.Port, req.Proto, req.URL.Host, req.URL.Path)
|
url := fmt.Sprintf("http://%s:%s/%s:/%s/%s", host, rt.Port, req.Proto, req.URL.Host, req.URL.Path)
|
||||||
log.Info(fmt.Sprintf("roundtripper: proxying request '%s' to '%s'", req.RequestURI, url))
|
log.Info(fmt.Sprintf("roundtripper: proxying request '%s' to '%s'", req.RequestURI, url))
|
||||||
reqProxy, err := http.NewRequest(req.Method, url, req.Body)
|
reqProxy, err := http.NewRequest(req.Method, url, req.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A simple http server interface to Swarm
|
Package http implements a simple http server interface to Swarm
|
||||||
*/
|
*/
|
||||||
package http
|
package http
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@ type ServerConfig struct {
|
||||||
// electron (chromium) api for registering bzz url scheme handlers:
|
// electron (chromium) api for registering bzz url scheme handlers:
|
||||||
// https://github.com/atom/electron/blob/master/docs/api/protocol.md
|
// https://github.com/atom/electron/blob/master/docs/api/protocol.md
|
||||||
|
|
||||||
// starts up http server
|
// StartHttpServer starts up http server
|
||||||
func StartHttpServer(api *api.Api, config *ServerConfig) {
|
func StartHttpServer(api *api.Api, config *ServerConfig) {
|
||||||
var allowedOrigins []string
|
var allowedOrigins []string
|
||||||
for _, domain := range strings.Split(config.CorsString, ",") {
|
for _, domain := range strings.Split(config.CorsString, ",") {
|
||||||
|
|
@ -695,9 +695,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
if uri.Raw() || uri.DeprecatedRaw() {
|
if uri.Raw() || uri.DeprecatedRaw() {
|
||||||
ShowError(w, req, fmt.Sprintf("No PUT to %s allowed.", uri), http.StatusBadRequest)
|
ShowError(w, req, fmt.Sprintf("No PUT to %s allowed.", uri), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
s.HandlePostFiles(w, req)
|
|
||||||
}
|
}
|
||||||
|
s.HandlePostFiles(w, req)
|
||||||
|
|
||||||
case "DELETE":
|
case "DELETE":
|
||||||
if uri.Raw() || uri.DeprecatedRaw() {
|
if uri.Raw() || uri.DeprecatedRaw() {
|
||||||
|
|
|
||||||
|
|
@ -230,18 +230,18 @@ func readManifest(manifestReader storage.LazySectionReader, hash storage.Key, dp
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) {
|
func (mtrie *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) {
|
||||||
self.hash = nil // trie modified, hash needs to be re-calculated on demand
|
mtrie.hash = nil // trie modified, hash needs to be re-calculated on demand
|
||||||
|
|
||||||
if len(entry.Path) == 0 {
|
if len(entry.Path) == 0 {
|
||||||
self.entries[256] = entry
|
mtrie.entries[256] = entry
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
b := entry.Path[0]
|
b := entry.Path[0]
|
||||||
oldentry := self.entries[b]
|
oldentry := mtrie.entries[b]
|
||||||
if (oldentry == nil) || (oldentry.Path == entry.Path && oldentry.ContentType != ManifestType) {
|
if (oldentry == nil) || (oldentry.Path == entry.Path && oldentry.ContentType != ManifestType) {
|
||||||
self.entries[b] = entry
|
mtrie.entries[b] = entry
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,7 +251,7 @@ func (self *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldentry.ContentType == ManifestType) && (cpl == len(oldentry.Path)) {
|
if (oldentry.ContentType == ManifestType) && (cpl == len(oldentry.Path)) {
|
||||||
if self.loadSubTrie(oldentry, quitC) != nil {
|
if mtrie.loadSubTrie(oldentry, quitC) != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entry.Path = entry.Path[cpl:]
|
entry.Path = entry.Path[cpl:]
|
||||||
|
|
@ -263,21 +263,21 @@ func (self *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) {
|
||||||
commonPrefix := entry.Path[:cpl]
|
commonPrefix := entry.Path[:cpl]
|
||||||
|
|
||||||
subtrie := &manifestTrie{
|
subtrie := &manifestTrie{
|
||||||
dpa: self.dpa,
|
dpa: mtrie.dpa,
|
||||||
}
|
}
|
||||||
entry.Path = entry.Path[cpl:]
|
entry.Path = entry.Path[cpl:]
|
||||||
oldentry.Path = oldentry.Path[cpl:]
|
oldentry.Path = oldentry.Path[cpl:]
|
||||||
subtrie.addEntry(entry, quitC)
|
subtrie.addEntry(entry, quitC)
|
||||||
subtrie.addEntry(oldentry, quitC)
|
subtrie.addEntry(oldentry, quitC)
|
||||||
|
|
||||||
self.entries[b] = newManifestTrieEntry(&ManifestEntry{
|
mtrie.entries[b] = newManifestTrieEntry(&ManifestEntry{
|
||||||
Path: commonPrefix,
|
Path: commonPrefix,
|
||||||
ContentType: ManifestType,
|
ContentType: ManifestType,
|
||||||
}, subtrie)
|
}, subtrie)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) {
|
func (mtrie *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) {
|
||||||
for _, e := range self.entries {
|
for _, e := range mtrie.entries {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
cnt++
|
cnt++
|
||||||
entry = e
|
entry = e
|
||||||
|
|
@ -286,27 +286,27 @@ func (self *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) deleteEntry(path string, quitC chan bool) {
|
func (mtrie *manifestTrie) deleteEntry(path string, quitC chan bool) {
|
||||||
self.hash = nil // trie modified, hash needs to be re-calculated on demand
|
mtrie.hash = nil // trie modified, hash needs to be re-calculated on demand
|
||||||
|
|
||||||
if len(path) == 0 {
|
if len(path) == 0 {
|
||||||
self.entries[256] = nil
|
mtrie.entries[256] = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
b := path[0]
|
b := path[0]
|
||||||
entry := self.entries[b]
|
entry := mtrie.entries[b]
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if entry.Path == path {
|
if entry.Path == path {
|
||||||
self.entries[b] = nil
|
mtrie.entries[b] = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
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, quitC) != nil {
|
if mtrie.loadSubTrie(entry, quitC) != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entry.subtrie.deleteEntry(path[epl:], quitC)
|
entry.subtrie.deleteEntry(path[epl:], quitC)
|
||||||
|
|
@ -317,13 +317,13 @@ func (self *manifestTrie) deleteEntry(path string, quitC chan bool) {
|
||||||
if lastentry != nil {
|
if lastentry != nil {
|
||||||
lastentry.Path = entry.Path + lastentry.Path
|
lastentry.Path = entry.Path + lastentry.Path
|
||||||
}
|
}
|
||||||
self.entries[b] = lastentry
|
mtrie.entries[b] = lastentry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) recalcAndStore() error {
|
func (mtrie *manifestTrie) recalcAndStore() error {
|
||||||
if self.hash != nil {
|
if mtrie.hash != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,7 +331,7 @@ func (self *manifestTrie) recalcAndStore() error {
|
||||||
buffer.WriteString(`{"entries":[`)
|
buffer.WriteString(`{"entries":[`)
|
||||||
|
|
||||||
list := &Manifest{}
|
list := &Manifest{}
|
||||||
for _, entry := range self.entries {
|
for _, entry := range mtrie.entries {
|
||||||
if entry != nil {
|
if entry != nil {
|
||||||
if entry.Hash == "" { // TODO: paralellize
|
if entry.Hash == "" { // TODO: paralellize
|
||||||
err := entry.subtrie.recalcAndStore()
|
err := entry.subtrie.recalcAndStore()
|
||||||
|
|
@ -352,22 +352,22 @@ func (self *manifestTrie) recalcAndStore() error {
|
||||||
|
|
||||||
sr := bytes.NewReader(manifest)
|
sr := bytes.NewReader(manifest)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
key, err2 := self.dpa.Store(sr, int64(len(manifest)), wg, nil)
|
key, err2 := mtrie.dpa.Store(sr, int64(len(manifest)), wg, nil)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
self.hash = key
|
mtrie.hash = key
|
||||||
return err2
|
return err2
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) {
|
func (mtrie *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) {
|
||||||
if entry.subtrie == nil {
|
if entry.subtrie == nil {
|
||||||
hash := common.Hex2Bytes(entry.Hash)
|
hash := common.Hex2Bytes(entry.Hash)
|
||||||
entry.subtrie, err = loadManifest(self.dpa, hash, quitC)
|
entry.subtrie, err = loadManifest(mtrie.dpa, hash, quitC)
|
||||||
entry.Hash = "" // might not match, should be recalculated
|
entry.Hash = "" // might not match, should be recalculated
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error {
|
func (mtrie *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error {
|
||||||
plen := len(prefix)
|
plen := len(prefix)
|
||||||
var start, stop int
|
var start, stop int
|
||||||
if plen == 0 {
|
if plen == 0 {
|
||||||
|
|
@ -384,7 +384,7 @@ func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool,
|
||||||
return fmt.Errorf("aborted")
|
return fmt.Errorf("aborted")
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
entry := self.entries[i]
|
entry := mtrie.entries[i]
|
||||||
if entry != nil {
|
if entry != nil {
|
||||||
epl := len(entry.Path)
|
epl := len(entry.Path)
|
||||||
if entry.ContentType == ManifestType {
|
if entry.ContentType == ManifestType {
|
||||||
|
|
@ -393,7 +393,7 @@ func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool,
|
||||||
l = epl
|
l = epl
|
||||||
}
|
}
|
||||||
if prefix[:l] == entry.Path[:l] {
|
if prefix[:l] == entry.Path[:l] {
|
||||||
err := self.loadSubTrie(entry, quitC)
|
err := mtrie.loadSubTrie(entry, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -412,23 +412,23 @@ func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) {
|
func (mtrie *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) {
|
||||||
return self.listWithPrefixInt(prefix, "", quitC, cb)
|
return mtrie.listWithPrefixInt(prefix, "", quitC, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) {
|
func (mtrie *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) {
|
||||||
|
|
||||||
log.Trace(fmt.Sprintf("findPrefixOf(%s)", path))
|
log.Trace(fmt.Sprintf("findPrefixOf(%s)", path))
|
||||||
|
|
||||||
if len(path) == 0 {
|
if len(path) == 0 {
|
||||||
return self.entries[256], 0
|
return mtrie.entries[256], 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//see if first char is in manifest entries
|
//see if first char is in manifest entries
|
||||||
b := path[0]
|
b := path[0]
|
||||||
entry = self.entries[b]
|
entry = mtrie.entries[b]
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
return self.entries[256], 0
|
return mtrie.entries[256], 0
|
||||||
}
|
}
|
||||||
|
|
||||||
epl := len(entry.Path)
|
epl := len(entry.Path)
|
||||||
|
|
@ -436,7 +436,7 @@ func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *man
|
||||||
if len(path) <= epl {
|
if len(path) <= epl {
|
||||||
if entry.Path[:len(path)] == path {
|
if entry.Path[:len(path)] == path {
|
||||||
if entry.ContentType == ManifestType {
|
if entry.ContentType == ManifestType {
|
||||||
err := self.loadSubTrie(entry, quitC)
|
err := mtrie.loadSubTrie(entry, quitC)
|
||||||
if err == nil && entry.subtrie != nil {
|
if err == nil && entry.subtrie != nil {
|
||||||
subentries := entry.subtrie.entries
|
subentries := entry.subtrie.entries
|
||||||
for i := 0; i < len(subentries); i++ {
|
for i := 0; i < len(subentries); i++ {
|
||||||
|
|
@ -457,7 +457,7 @@ func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *man
|
||||||
log.Trace(fmt.Sprintf("entry.ContentType = %v", entry.ContentType))
|
log.Trace(fmt.Sprintf("entry.ContentType = %v", entry.ContentType))
|
||||||
//the subentry is a manifest, load subtrie
|
//the subentry is a manifest, load subtrie
|
||||||
if entry.ContentType == ManifestType && (strings.Contains(entry.Path, path) || strings.Contains(path, entry.Path)) {
|
if entry.ContentType == ManifestType && (strings.Contains(entry.Path, path) || strings.Contains(path, entry.Path)) {
|
||||||
err := self.loadSubTrie(entry, quitC)
|
err := mtrie.loadSubTrie(entry, quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
|
|
@ -495,10 +495,10 @@ func RegularSlashes(path string) (res string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) {
|
func (mtrie *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) {
|
||||||
path := RegularSlashes(spath)
|
path := RegularSlashes(spath)
|
||||||
var pos int
|
var pos int
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
entry, pos = self.findPrefixOf(path, quitC)
|
entry, pos = mtrie.findPrefixOf(path, quitC)
|
||||||
return entry, path[:pos]
|
return entry, path[:pos]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ type Response struct {
|
||||||
Content string
|
Content string
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements a service
|
// Storage implements a service
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
|
|
@ -41,8 +41,8 @@ func NewStorage(api *Api) *Storage {
|
||||||
// its content type
|
// its content type
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
func (self *Storage) Put(content, contentType string) (string, error) {
|
func (s *Storage) Put(content, contentType string) (string, error) {
|
||||||
key, err := self.api.Put(content, contentType)
|
key, err := s.api.Put(content, contentType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -57,16 +57,16 @@ func (self *Storage) Put(content, contentType string) (string, error) {
|
||||||
// size is resp.Size
|
// size is resp.Size
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
func (self *Storage) Get(bzzpath string) (*Response, error) {
|
func (s *Storage) Get(bzzpath string) (*Response, error) {
|
||||||
uri, err := Parse(path.Join("bzz:/", bzzpath))
|
uri, err := Parse(path.Join("bzz:/", bzzpath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
key, err := self.api.Resolve(uri)
|
key, err := s.api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reader, mimeType, status, err := self.api.Get(key, uri.Path)
|
reader, mimeType, status, err := s.api.Get(key, uri.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -83,20 +83,20 @@ func (self *Storage) Get(bzzpath string) (*Response, error) {
|
||||||
return &Response{mimeType, status, expsize, string(body[:size])}, err
|
return &Response{mimeType, status, expsize, string(body[:size])}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modify(rootHash, basePath, contentHash, contentType) takes th e manifest trie rooted in rootHash,
|
// Modify takes the manifest trie rooted in rootHash,
|
||||||
// and merge on to it. creating an entry w conentType (mime)
|
// and merge on to it. creating an entry w conentType (mime)
|
||||||
//
|
//
|
||||||
// DEPRECATED: Use the HTTP API instead
|
// DEPRECATED: Use the HTTP API instead
|
||||||
func (self *Storage) Modify(rootHash, path, contentHash, contentType string) (newRootHash string, err error) {
|
func (s *Storage) Modify(rootHash, path, contentHash, contentType string) (newRootHash string, err error) {
|
||||||
uri, err := Parse("bzz:/" + rootHash)
|
uri, err := Parse("bzz:/" + rootHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
key, err := self.api.Resolve(uri)
|
key, err := s.api.Resolve(uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
key, err = self.api.Modify(key, path, contentHash, contentType)
|
key, err = s.api.Modify(key, path, contentHash, contentType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,18 +29,18 @@ func NewControl(api *Api, hive *network.Hive) *Control {
|
||||||
return &Control{api, hive}
|
return &Control{api, hive}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Control) BlockNetworkRead(on bool) {
|
func (c *Control) BlockNetworkRead(on bool) {
|
||||||
self.hive.BlockNetworkRead(on)
|
c.hive.BlockNetworkRead(on)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Control) SyncEnabled(on bool) {
|
func (c *Control) SyncEnabled(on bool) {
|
||||||
self.hive.SyncEnabled(on)
|
c.hive.SyncEnabled(on)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Control) SwapEnabled(on bool) {
|
func (c *Control) SwapEnabled(on bool) {
|
||||||
self.hive.SwapEnabled(on)
|
c.hive.SwapEnabled(on)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Control) Hive() string {
|
func (c *Control) Hive() string {
|
||||||
return self.hive.String()
|
return c.hive.String()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,50 +94,50 @@ func (file *SwarmFile) Attr(ctx context.Context, a *fuse.Attr) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sf *SwarmFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
|
func (file *SwarmFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
|
||||||
|
|
||||||
sf.lock.RLock()
|
file.lock.RLock()
|
||||||
defer sf.lock.RUnlock()
|
defer file.lock.RUnlock()
|
||||||
if sf.reader == nil {
|
if file.reader == nil {
|
||||||
sf.reader = sf.mountInfo.swarmApi.Retrieve(sf.key)
|
file.reader = file.mountInfo.swarmApi.Retrieve(file.key)
|
||||||
}
|
}
|
||||||
buf := make([]byte, req.Size)
|
buf := make([]byte, req.Size)
|
||||||
n, err := sf.reader.ReadAt(buf, req.Offset)
|
n, err := file.reader.ReadAt(buf, req.Offset)
|
||||||
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
resp.Data = buf[:n]
|
resp.Data = buf[:n]
|
||||||
sf.reader = nil
|
file.reader = nil
|
||||||
return err
|
return err
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sf *SwarmFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
|
func (file *SwarmFile) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
|
||||||
|
|
||||||
if sf.fileSize == 0 && req.Offset == 0 {
|
if file.fileSize == 0 && req.Offset == 0 {
|
||||||
|
|
||||||
// A new file is created
|
// A new file is created
|
||||||
err := addFileToSwarm(sf, req.Data, len(req.Data))
|
err := addFileToSwarm(file, req.Data, len(req.Data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resp.Size = len(req.Data)
|
resp.Size = len(req.Data)
|
||||||
|
|
||||||
} else if req.Offset <= sf.fileSize {
|
} else if req.Offset <= file.fileSize {
|
||||||
|
|
||||||
totalSize := sf.fileSize + int64(len(req.Data))
|
totalSize := file.fileSize + int64(len(req.Data))
|
||||||
if totalSize > MaxAppendFileSize {
|
if totalSize > MaxAppendFileSize {
|
||||||
log.Warn("Append file size reached (%v) : (%v)", sf.fileSize, len(req.Data))
|
log.Warn("Append file size reached (%v) : (%v)", file.fileSize, len(req.Data))
|
||||||
return errFileSizeMaxLimixReached
|
return errFileSizeMaxLimixReached
|
||||||
}
|
}
|
||||||
|
|
||||||
err := appendToExistingFileInSwarm(sf, req.Data, req.Offset, int64(len(req.Data)))
|
err := appendToExistingFileInSwarm(file, req.Data, req.Offset, int64(len(req.Data)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resp.Size = len(req.Data)
|
resp.Size = len(req.Data)
|
||||||
} else {
|
} else {
|
||||||
log.Warn("Invalid write request size(%v) : off(%v)", sf.fileSize, req.Offset)
|
log.Warn("Invalid write request size(%v) : off(%v)", file.fileSize, req.Offset)
|
||||||
return errInvalidOffset
|
return errInvalidOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type SwarmFS struct {
|
type SwarmFS struct {
|
||||||
swarmApi *api.Api
|
swarmAPI *api.Api
|
||||||
activeMounts map[string]*MountInfo
|
activeMounts map[string]*MountInfo
|
||||||
swarmFsLock *sync.RWMutex
|
swarmFsLock *sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +47,7 @@ type SwarmFS struct {
|
||||||
func NewSwarmFS(api *api.Api) *SwarmFS {
|
func NewSwarmFS(api *api.Api) *SwarmFS {
|
||||||
swarmfsLock.Do(func() {
|
swarmfsLock.Do(func() {
|
||||||
swarmfs = &SwarmFS{
|
swarmfs = &SwarmFS{
|
||||||
swarmApi: api,
|
swarmAPI: api,
|
||||||
swarmFsLock: &sync.RWMutex{},
|
swarmFsLock: &sync.RWMutex{},
|
||||||
activeMounts: map[string]*MountInfo{},
|
activeMounts: map[string]*MountInfo{},
|
||||||
}
|
}
|
||||||
|
|
@ -56,10 +56,10 @@ func NewSwarmFS(api *api.Api) *SwarmFS {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inode numbers need to be unique, they are used for caching inside fuse
|
// NewInode numbers need to be unique, they are used for caching inside fuse
|
||||||
func NewInode() uint64 {
|
func NewInode() uint64 {
|
||||||
inodeLock.Lock()
|
inodeLock.Lock()
|
||||||
defer inodeLock.Unlock()
|
defer inodeLock.Unlock()
|
||||||
inode += 1
|
inode++
|
||||||
return inode
|
return inode
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,18 +34,18 @@ type MountInfo struct {
|
||||||
LatestManifest string
|
LatestManifest string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
func (sf *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
||||||
return nil, errNoFUSE
|
return nil, errNoFUSE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Unmount(mountpoint string) (bool, error) {
|
func (sf *SwarmFS) Unmount(mountpoint string) (bool, error) {
|
||||||
return false, errNoFUSE
|
return false, errNoFUSE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Listmounts() ([]*MountInfo, error) {
|
func (sf *SwarmFS) Listmounts() ([]*MountInfo, error) {
|
||||||
return nil, errNoFUSE
|
return nil, errNoFUSE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Stop() error {
|
func (sf *SwarmFS) Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,14 +48,14 @@ func isFUSEUnsupportedError(err error) bool {
|
||||||
return err == fuse.ErrOSXFUSENotFound
|
return err == fuse.ErrOSXFUSENotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// information about every active mount
|
// MountInfo is information about every active mount
|
||||||
type MountInfo struct {
|
type MountInfo struct {
|
||||||
MountPoint string
|
MountPoint string
|
||||||
StartManifest string
|
StartManifest string
|
||||||
LatestManifest string
|
LatestManifest string
|
||||||
rootDir *SwarmDir
|
rootDir *SwarmDir
|
||||||
fuseConnection *fuse.Conn
|
fuseConnection *fuse.Conn
|
||||||
swarmApi *api.Api
|
swarmAPI *api.Api
|
||||||
lock *sync.RWMutex
|
lock *sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,13 +66,13 @@ func NewMountInfo(mhash, mpoint string, sapi *api.Api) *MountInfo {
|
||||||
LatestManifest: mhash,
|
LatestManifest: mhash,
|
||||||
rootDir: nil,
|
rootDir: nil,
|
||||||
fuseConnection: nil,
|
fuseConnection: nil,
|
||||||
swarmApi: sapi,
|
swarmAPI: sapi,
|
||||||
lock: &sync.RWMutex{},
|
lock: &sync.RWMutex{},
|
||||||
}
|
}
|
||||||
return newMountInfo
|
return newMountInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
func (sf *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
||||||
|
|
||||||
if mountpoint == "" {
|
if mountpoint == "" {
|
||||||
return nil, errEmptyMountPoint
|
return nil, errEmptyMountPoint
|
||||||
|
|
@ -82,25 +82,25 @@ func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
self.swarmFsLock.Lock()
|
sf.swarmFsLock.Lock()
|
||||||
defer self.swarmFsLock.Unlock()
|
defer sf.swarmFsLock.Unlock()
|
||||||
|
|
||||||
noOfActiveMounts := len(self.activeMounts)
|
noOfActiveMounts := len(sf.activeMounts)
|
||||||
if noOfActiveMounts >= maxFuseMounts {
|
if noOfActiveMounts >= maxFuseMounts {
|
||||||
return nil, errMaxMountCount
|
return nil, errMaxMountCount
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := self.activeMounts[cleanedMountPoint]; ok {
|
if _, ok := sf.activeMounts[cleanedMountPoint]; ok {
|
||||||
return nil, errAlreadyMounted
|
return nil, errAlreadyMounted
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info(fmt.Sprintf("Attempting to mount %s ", cleanedMountPoint))
|
log.Info(fmt.Sprintf("Attempting to mount %s ", cleanedMountPoint))
|
||||||
_, manifestEntryMap, err := self.swarmApi.BuildDirectoryTree(mhash, true)
|
_, manifestEntryMap, err := sf.swarmAPI.BuildDirectoryTree(mhash, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mi := NewMountInfo(mhash, cleanedMountPoint, self.swarmApi)
|
mi := NewMountInfo(mhash, cleanedMountPoint, sf.swarmAPI)
|
||||||
|
|
||||||
dirTree := map[string]*SwarmDir{}
|
dirTree := map[string]*SwarmDir{}
|
||||||
rootDir := NewSwarmDir("/", mi)
|
rootDir := NewSwarmDir("/", mi)
|
||||||
|
|
@ -174,21 +174,21 @@ func (self *SwarmFS) Mount(mhash, mountpoint string) (*MountInfo, error) {
|
||||||
log.Info("Now serving swarm FUSE FS", "manifest", mhash, "mountpoint", cleanedMountPoint)
|
log.Info("Now serving swarm FUSE FS", "manifest", mhash, "mountpoint", cleanedMountPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.activeMounts[cleanedMountPoint] = mi
|
sf.activeMounts[cleanedMountPoint] = mi
|
||||||
return mi, nil
|
return mi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) {
|
func (sf *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) {
|
||||||
|
|
||||||
self.swarmFsLock.Lock()
|
sf.swarmFsLock.Lock()
|
||||||
defer self.swarmFsLock.Unlock()
|
defer sf.swarmFsLock.Unlock()
|
||||||
|
|
||||||
cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint))
|
cleanedMountPoint, err := filepath.Abs(filepath.Clean(mountpoint))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mountInfo := self.activeMounts[cleanedMountPoint]
|
mountInfo := sf.activeMounts[cleanedMountPoint]
|
||||||
|
|
||||||
if mountInfo == nil || mountInfo.MountPoint != cleanedMountPoint {
|
if mountInfo == nil || mountInfo.MountPoint != cleanedMountPoint {
|
||||||
return nil, fmt.Errorf("%s is not mounted", cleanedMountPoint)
|
return nil, fmt.Errorf("%s is not mounted", cleanedMountPoint)
|
||||||
|
|
@ -204,7 +204,7 @@ func (self *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mountInfo.fuseConnection.Close()
|
mountInfo.fuseConnection.Close()
|
||||||
delete(self.activeMounts, cleanedMountPoint)
|
delete(sf.activeMounts, cleanedMountPoint)
|
||||||
|
|
||||||
succString := fmt.Sprintf("UnMounting %v succeeded", cleanedMountPoint)
|
succString := fmt.Sprintf("UnMounting %v succeeded", cleanedMountPoint)
|
||||||
log.Info(succString)
|
log.Info(succString)
|
||||||
|
|
@ -212,21 +212,21 @@ func (self *SwarmFS) Unmount(mountpoint string) (*MountInfo, error) {
|
||||||
return mountInfo, nil
|
return mountInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Listmounts() []*MountInfo {
|
func (sf *SwarmFS) Listmounts() []*MountInfo {
|
||||||
self.swarmFsLock.RLock()
|
sf.swarmFsLock.RLock()
|
||||||
defer self.swarmFsLock.RUnlock()
|
defer sf.swarmFsLock.RUnlock()
|
||||||
|
|
||||||
rows := make([]*MountInfo, 0, len(self.activeMounts))
|
rows := make([]*MountInfo, 0, len(sf.activeMounts))
|
||||||
for _, mi := range self.activeMounts {
|
for _, mi := range sf.activeMounts {
|
||||||
rows = append(rows, mi)
|
rows = append(rows, mi)
|
||||||
}
|
}
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwarmFS) Stop() bool {
|
func (sf *SwarmFS) Stop() bool {
|
||||||
for mp := range self.activeMounts {
|
for mp := range sf.activeMounts {
|
||||||
mountInfo := self.activeMounts[mp]
|
mountInfo := sf.activeMounts[mp]
|
||||||
self.Unmount(mountInfo.MountPoint)
|
sf.Unmount(mountInfo.MountPoint)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ var (
|
||||||
syncSendNotFound = metrics.NewRegisteredCounter("network.sync.send.notfound", nil)
|
syncSendNotFound = metrics.NewRegisteredCounter("network.sync.send.notfound", nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler for storage/retrieval related protocol requests
|
// Depo is a handler for storage/retrieval related protocol requests
|
||||||
// implements the StorageHandler interface used by the bzz protocol
|
// implements the StorageHandler interface used by the bzz protocol
|
||||||
type Depo struct {
|
type Depo struct {
|
||||||
hashfunc storage.SwarmHasher
|
hashfunc storage.SwarmHasher
|
||||||
|
|
@ -52,20 +52,20 @@ func NewDepo(hash storage.SwarmHasher, localStore, remoteStore storage.ChunkStor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles UnsyncedKeysMsg after msg decoding - unsynced hashes upto sync state
|
// HandleUnsyncedKeysMsg after msg decoding - unsynced hashes upto sync state
|
||||||
// * the remote sync state is just stored and handled in protocol
|
// * the remote sync state is just stored and handled in protocol
|
||||||
// * filters through the new syncRequests and send the ones missing
|
// * filters through the new syncRequests and send the ones missing
|
||||||
// * back immediately as a deliveryRequest message
|
// * back immediately as a deliveryRequest message
|
||||||
// * empty message just pings back for more (is this needed?)
|
// * empty message just pings back for more (is this needed?)
|
||||||
// * strict signed sync states may be needed.
|
// * strict signed sync states may be needed.
|
||||||
func (self *Depo) HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error {
|
func (depo *Depo) HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error {
|
||||||
unsynced := req.Unsynced
|
unsynced := req.Unsynced
|
||||||
var missing []*syncRequest
|
var missing []*syncRequest
|
||||||
var chunk *storage.Chunk
|
var chunk *storage.Chunk
|
||||||
var err error
|
var err error
|
||||||
for _, req := range unsynced {
|
for _, req := range unsynced {
|
||||||
// skip keys that are found,
|
// skip keys that are found,
|
||||||
chunk, err = self.localStore.Get(req.Key[:])
|
chunk, err = depo.localStore.Get(req.Key[:])
|
||||||
if err != nil || chunk.SData == nil {
|
if err != nil || chunk.SData == nil {
|
||||||
missing = append(missing, req)
|
missing = append(missing, req)
|
||||||
}
|
}
|
||||||
|
|
@ -82,13 +82,13 @@ func (self *Depo) HandleUnsyncedKeysMsg(req *unsyncedKeysMsgData, p *peer) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles deliveryRequestMsg
|
// HandleDeliveryRequestMsg does the following:
|
||||||
// * serves actual chunks asked by the remote peer
|
// * serves actual chunks asked by the remote peer
|
||||||
// by pushing to the delivery queue (sync db) of the correct priority
|
// by pushing to the delivery queue (sync db) of the correct priority
|
||||||
// (remote peer is free to reprioritize)
|
// (remote peer is free to reprioritize)
|
||||||
// * the message implies remote peer wants more, so trigger for
|
// * the message implies remote peer wants more, so trigger for
|
||||||
// * new outgoing unsynced keys message is fired
|
// * new outgoing unsynced keys message is fired
|
||||||
func (self *Depo) HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer) error {
|
func (depo *Depo) HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer) error {
|
||||||
deliver := req.Deliver
|
deliver := req.Deliver
|
||||||
// queue the actual delivery of a chunk ()
|
// queue the actual delivery of a chunk ()
|
||||||
log.Trace(fmt.Sprintf("Depo.HandleDeliveryRequestMsg: received %v delivery requests: %v", len(deliver), deliver))
|
log.Trace(fmt.Sprintf("Depo.HandleDeliveryRequestMsg: received %v delivery requests: %v", len(deliver), deliver))
|
||||||
|
|
@ -96,7 +96,7 @@ func (self *Depo) HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer)
|
||||||
// TODO: look up in cache here or in deliveries
|
// TODO: look up in cache here or in deliveries
|
||||||
// priorities are taken from the message so the remote party can
|
// priorities are taken from the message so the remote party can
|
||||||
// reprioritise to at their leisure
|
// reprioritise to at their leisure
|
||||||
// r = self.pullCached(sreq.Key) // pulls and deletes from cache
|
// r = depo.pullCached(sreq.Key) // pulls and deletes from cache
|
||||||
Push(p, sreq.Key, sreq.Priority)
|
Push(p, sreq.Key, sreq.Priority)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,10 +108,10 @@ func (self *Depo) HandleDeliveryRequestMsg(req *deliveryRequestMsgData, p *peer)
|
||||||
// the entrypoint for store requests coming from the bzz wire protocol
|
// the entrypoint for store requests coming from the bzz wire protocol
|
||||||
// if key found locally, return. otherwise
|
// if key found locally, return. otherwise
|
||||||
// remote is untrusted, so hash is verified and chunk passed on to NetStore
|
// remote is untrusted, so hash is verified and chunk passed on to NetStore
|
||||||
func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
|
func (depo *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
|
||||||
var islocal bool
|
var islocal bool
|
||||||
req.from = p
|
req.from = p
|
||||||
chunk, err := self.localStore.Get(req.Key)
|
chunk, err := depo.localStore.Get(req.Key)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
log.Trace(fmt.Sprintf("Depo.handleStoreRequest: %v not found locally. create new chunk/request", req.Key))
|
log.Trace(fmt.Sprintf("Depo.handleStoreRequest: %v not found locally. create new chunk/request", req.Key))
|
||||||
|
|
@ -133,7 +133,7 @@ func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
|
||||||
//return
|
//return
|
||||||
}
|
}
|
||||||
|
|
||||||
hasher := self.hashfunc()
|
hasher := depo.hashfunc()
|
||||||
hasher.Write(req.SData)
|
hasher.Write(req.SData)
|
||||||
if !bytes.Equal(hasher.Sum(nil), req.Key) {
|
if !bytes.Equal(hasher.Sum(nil), req.Key) {
|
||||||
// data does not validate, ignore
|
// data does not validate, ignore
|
||||||
|
|
@ -150,12 +150,12 @@ func (self *Depo) HandleStoreRequestMsg(req *storeRequestMsgData, p *peer) {
|
||||||
chunk.Size = int64(binary.LittleEndian.Uint64(req.SData[0:8]))
|
chunk.Size = int64(binary.LittleEndian.Uint64(req.SData[0:8]))
|
||||||
log.Trace(fmt.Sprintf("delivery of %v from %v", chunk, p))
|
log.Trace(fmt.Sprintf("delivery of %v from %v", chunk, p))
|
||||||
chunk.Source = p
|
chunk.Source = p
|
||||||
self.netStore.Put(chunk)
|
depo.netStore.Put(chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
// entrypoint for retrieve requests coming from the bzz wire protocol
|
// entrypoint for retrieve requests coming from the bzz wire protocol
|
||||||
// checks swap balance - return if peer has no credit
|
// checks swap balance - return if peer has no credit
|
||||||
func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer) {
|
func (depo *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer) {
|
||||||
req.from = p
|
req.from = p
|
||||||
// swap - record credit for 1 request
|
// swap - record credit for 1 request
|
||||||
// note that only charge actual reqsearches
|
// note that only charge actual reqsearches
|
||||||
|
|
@ -171,8 +171,8 @@ func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer)
|
||||||
// call storage.NetStore#Get which
|
// call storage.NetStore#Get which
|
||||||
// blocks until local retrieval finished
|
// blocks until local retrieval finished
|
||||||
// launches cloud retrieval
|
// launches cloud retrieval
|
||||||
chunk, _ := self.netStore.Get(req.Key)
|
chunk, _ := depo.netStore.Get(req.Key)
|
||||||
req = self.strategyUpdateRequest(chunk.Req, req)
|
req = depo.strategyUpdateRequest(chunk.Req, req)
|
||||||
// check if we can immediately deliver
|
// check if we can immediately deliver
|
||||||
if chunk.SData != nil {
|
if chunk.SData != nil {
|
||||||
log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content found, delivering...", req.Key.Log()))
|
log.Trace(fmt.Sprintf("Depo.HandleRetrieveRequest: %v - content found, delivering...", req.Key.Log()))
|
||||||
|
|
@ -197,27 +197,26 @@ func (self *Depo) HandleRetrieveRequestMsg(req *retrieveRequestMsgData, p *peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add peer request the chunk and decides the timeout for the response if still searching
|
// add peer request the chunk and decides the timeout for the response if still searching
|
||||||
func (self *Depo) strategyUpdateRequest(rs *storage.RequestStatus, origReq *retrieveRequestMsgData) (req *retrieveRequestMsgData) {
|
func (depo *Depo) strategyUpdateRequest(rs *storage.RequestStatus, origReq *retrieveRequestMsgData) (req *retrieveRequestMsgData) {
|
||||||
log.Trace(fmt.Sprintf("Depo.strategyUpdateRequest: key %v", origReq.Key.Log()))
|
log.Trace(fmt.Sprintf("Depo.strategyUpdateRequest: key %v", origReq.Key.Log()))
|
||||||
// we do not create an alternative one
|
// we do not create an alternative one
|
||||||
req = origReq
|
req = origReq
|
||||||
if rs != nil {
|
if rs != nil {
|
||||||
self.addRequester(rs, req)
|
depo.addRequester(rs, req)
|
||||||
req.setTimeout(self.searchTimeout(rs, req))
|
req.setTimeout(depo.searchTimeout(rs, req))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// decides the timeout promise sent with the immediate peers response to a retrieve request
|
// decides the timeout promise sent with the immediate peers response to a retrieve request
|
||||||
// if timeout is explicitly set and expired
|
// if timeout is explicitly set and expired
|
||||||
func (self *Depo) searchTimeout(rs *storage.RequestStatus, req *retrieveRequestMsgData) (timeout *time.Time) {
|
func (depo *Depo) searchTimeout(rs *storage.RequestStatus, req *retrieveRequestMsgData) (timeout *time.Time) {
|
||||||
reqt := req.getTimeout()
|
reqt := req.getTimeout()
|
||||||
t := time.Now().Add(searchTimeout)
|
t := time.Now().Add(searchTimeout)
|
||||||
if reqt != nil && reqt.Before(t) {
|
if reqt != nil && reqt.Before(t) {
|
||||||
return reqt
|
return reqt
|
||||||
} else {
|
|
||||||
return &t
|
|
||||||
}
|
}
|
||||||
|
return &t
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -225,7 +224,7 @@ adds a new peer to an existing open request
|
||||||
only add if less than requesterCount peers forwarded the same request id so far
|
only add if less than requesterCount peers forwarded the same request id so far
|
||||||
note this is done irrespective of status (searching or found)
|
note this is done irrespective of status (searching or found)
|
||||||
*/
|
*/
|
||||||
func (self *Depo) addRequester(rs *storage.RequestStatus, req *retrieveRequestMsgData) {
|
func (depo *Depo) addRequester(rs *storage.RequestStatus, req *retrieveRequestMsgData) {
|
||||||
log.Trace(fmt.Sprintf("Depo.addRequester: key %v - add peer to req.Id %v", req.Key.Log(), req.Id))
|
log.Trace(fmt.Sprintf("Depo.addRequester: key %v - add peer to req.Id %v", req.Key.Log(), req.Id))
|
||||||
list := rs.Requesters[req.Id]
|
list := rs.Requesters[req.Id]
|
||||||
rs.Requesters[req.Id] = append(list, req)
|
rs.Requesters[req.Id] = append(list, req)
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func NewForwarder(hive *Hive) *forwarder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate a unique id uint64
|
// generate a unique id uint64
|
||||||
func generateId() uint64 {
|
func generateID() uint64 {
|
||||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
return uint64(r.Int63())
|
return uint64(r.Int63())
|
||||||
}
|
}
|
||||||
|
|
@ -54,8 +54,8 @@ var searchTimeout = 3 * time.Second
|
||||||
|
|
||||||
// forwarding logic
|
// forwarding logic
|
||||||
// logic propagating retrieve requests to peers given by the kademlia hive
|
// logic propagating retrieve requests to peers given by the kademlia hive
|
||||||
func (self *forwarder) Retrieve(chunk *storage.Chunk) {
|
func (f *forwarder) Retrieve(chunk *storage.Chunk) {
|
||||||
peers := self.hive.getPeers(chunk.Key, 0)
|
peers := f.hive.getPeers(chunk.Key, 0)
|
||||||
log.Trace(fmt.Sprintf("forwarder.Retrieve: %v - received %d peers from KΛÐΞMLIΛ...", chunk.Key.Log(), len(peers)))
|
log.Trace(fmt.Sprintf("forwarder.Retrieve: %v - received %d peers from KΛÐΞMLIΛ...", chunk.Key.Log(), len(peers)))
|
||||||
OUT:
|
OUT:
|
||||||
for _, p := range peers {
|
for _, p := range peers {
|
||||||
|
|
@ -70,7 +70,7 @@ OUT:
|
||||||
}
|
}
|
||||||
req := &retrieveRequestMsgData{
|
req := &retrieveRequestMsgData{
|
||||||
Key: chunk.Key,
|
Key: chunk.Key,
|
||||||
Id: generateId(),
|
Id: generateID(),
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if p.swap != nil {
|
if p.swap != nil {
|
||||||
|
|
@ -87,7 +87,7 @@ OUT:
|
||||||
// requests to specific peers given by the kademlia hive
|
// requests to specific peers given by the kademlia hive
|
||||||
// except for peers that the store request came from (if any)
|
// except for peers that the store request came from (if any)
|
||||||
// delivery queueing taken care of by syncer
|
// delivery queueing taken care of by syncer
|
||||||
func (self *forwarder) Store(chunk *storage.Chunk) {
|
func (f *forwarder) Store(chunk *storage.Chunk) {
|
||||||
var n int
|
var n int
|
||||||
msg := &storeRequestMsgData{
|
msg := &storeRequestMsgData{
|
||||||
Key: chunk.Key,
|
Key: chunk.Key,
|
||||||
|
|
@ -97,7 +97,7 @@ func (self *forwarder) Store(chunk *storage.Chunk) {
|
||||||
if chunk.Source != nil {
|
if chunk.Source != nil {
|
||||||
source = chunk.Source.(*peer)
|
source = chunk.Source.(*peer)
|
||||||
}
|
}
|
||||||
for _, p := range self.hive.getPeers(chunk.Key, 0) {
|
for _, p := range f.hive.getPeers(chunk.Key, 0) {
|
||||||
log.Trace(fmt.Sprintf("forwarder.Store: %v %v", p, chunk))
|
log.Trace(fmt.Sprintf("forwarder.Store: %v %v", p, chunk))
|
||||||
|
|
||||||
if p.syncer != nil && (source == nil || p.Addr() != source.Addr()) {
|
if p.syncer != nil && (source == nil || p.Addr() != source.Addr()) {
|
||||||
|
|
@ -109,7 +109,7 @@ func (self *forwarder) Store(chunk *storage.Chunk) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// once a chunk is found deliver it to its requesters unless timed out
|
// once a chunk is found deliver it to its requesters unless timed out
|
||||||
func (self *forwarder) Deliver(chunk *storage.Chunk) {
|
func (f *forwarder) Deliver(chunk *storage.Chunk) {
|
||||||
// iterate over request entries
|
// iterate over request entries
|
||||||
for id, requesters := range chunk.Req.Requesters {
|
for id, requesters := range chunk.Req.Requesters {
|
||||||
counter := requesterCount
|
counter := requesterCount
|
||||||
|
|
@ -137,14 +137,14 @@ func (self *forwarder) Deliver(chunk *storage.Chunk) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initiate delivery of a chunk to a particular peer via syncer#addRequest
|
// Deliver initiates delivery of a chunk to a particular peer via syncer#addRequest
|
||||||
// depending on syncer mode and priority settings and sync request type
|
// depending on syncer mode and priority settings and sync request type
|
||||||
// this either goes via confirmation roundtrip or queued or pushed directly
|
// this either goes via confirmation roundtrip or queued or pushed directly
|
||||||
func Deliver(p *peer, req interface{}, ty int) {
|
func Deliver(p *peer, req interface{}, ty int) {
|
||||||
p.syncer.addRequest(req, ty)
|
p.syncer.addRequest(req, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// push chunk over to peer
|
// Push chunk over to peer
|
||||||
func Push(p *peer, key storage.Key, priority uint) {
|
func Push(p *peer, key storage.Key, priority uint) {
|
||||||
p.syncer.doDelivery(key, priority, p.syncer.quit)
|
p.syncer.doDelivery(key, priority, p.syncer.quit)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ type HiveParams struct {
|
||||||
*kademlia.KadParams
|
*kademlia.KadParams
|
||||||
}
|
}
|
||||||
|
|
||||||
//create default params
|
// NewDefaultHiveParams creates default params
|
||||||
func NewDefaultHiveParams() *HiveParams {
|
func NewDefaultHiveParams() *HiveParams {
|
||||||
kad := kademlia.NewDefaultKadParams()
|
kad := kademlia.NewDefaultKadParams()
|
||||||
// kad.BucketSize = bucketSize
|
// kad.BucketSize = bucketSize
|
||||||
|
|
@ -92,8 +92,8 @@ func NewDefaultHiveParams() *HiveParams {
|
||||||
|
|
||||||
//this can only finally be set after all config options (file, cmd line, env vars)
|
//this can only finally be set after all config options (file, cmd line, env vars)
|
||||||
//have been evaluated
|
//have been evaluated
|
||||||
func (self *HiveParams) Init(path string) {
|
func (params *HiveParams) Init(path string) {
|
||||||
self.KadDbPath = filepath.Join(path, "bzz-peers.json")
|
params.KadDbPath = filepath.Join(path, "bzz-peers.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHive(addr common.Hash, params *HiveParams, swapEnabled, syncEnabled bool) *Hive {
|
func NewHive(addr common.Hash, params *HiveParams, swapEnabled, syncEnabled bool) *Hive {
|
||||||
|
|
@ -108,53 +108,53 @@ func NewHive(addr common.Hash, params *HiveParams, swapEnabled, syncEnabled bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) SyncEnabled(on bool) {
|
func (hive *Hive) SyncEnabled(on bool) {
|
||||||
self.syncEnabled = on
|
hive.syncEnabled = on
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) SwapEnabled(on bool) {
|
func (hive *Hive) SwapEnabled(on bool) {
|
||||||
self.swapEnabled = on
|
hive.swapEnabled = on
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) BlockNetworkRead(on bool) {
|
func (hive *Hive) BlockNetworkRead(on bool) {
|
||||||
self.blockRead = on
|
hive.blockRead = on
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) BlockNetworkWrite(on bool) {
|
func (hive *Hive) BlockNetworkWrite(on bool) {
|
||||||
self.blockWrite = on
|
hive.blockWrite = on
|
||||||
}
|
}
|
||||||
|
|
||||||
// public accessor to the hive base address
|
// Addr is the public accessor to the hive base address
|
||||||
func (self *Hive) Addr() kademlia.Address {
|
func (hive *Hive) Addr() kademlia.Address {
|
||||||
return self.addr
|
return hive.addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start receives network info only at startup
|
// Start receives network info only at startup
|
||||||
// listedAddr is a function to retrieve listening address to advertise to peers
|
// listedAddr is a function to retrieve listening address to advertise to peers
|
||||||
// connectPeer is a function to connect to a peer based on its NodeID or enode URL
|
// connectPeer is a function to connect to a peer based on its NodeID or enode URL
|
||||||
// there are called on the p2p.Server which runs on the node
|
// there are called on the p2p.Server which runs on the node
|
||||||
func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPeer func(string) error) (err error) {
|
func (hive *Hive) Start(id discover.NodeID, listenAddr func() string, connectPeer func(string) error) (err error) {
|
||||||
self.toggle = make(chan bool)
|
hive.toggle = make(chan bool)
|
||||||
self.more = make(chan bool)
|
hive.more = make(chan bool)
|
||||||
self.quit = make(chan bool)
|
hive.quit = make(chan bool)
|
||||||
self.id = id
|
hive.id = id
|
||||||
self.listenAddr = listenAddr
|
hive.listenAddr = listenAddr
|
||||||
err = self.kad.Load(self.path, nil)
|
err = hive.kad.Load(hive.path, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("Warning: error reading kaddb '%s' (skipping): %v", self.path, err))
|
log.Warn(fmt.Sprintf("Warning: error reading kaddb '%s' (skipping): %v", hive.path, err))
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
// this loop is doing bootstrapping and maintains a healthy table
|
// this loop is doing bootstrapping and maintains a healthy table
|
||||||
go self.keepAlive()
|
go hive.keepAlive()
|
||||||
go func() {
|
go func() {
|
||||||
// whenever toggled ask kademlia about most preferred peer
|
// whenever toggled ask kademlia about most preferred peer
|
||||||
for alive := range self.more {
|
for alive := range hive.more {
|
||||||
if !alive {
|
if !alive {
|
||||||
// receiving false closes the loop while allowing parallel routines
|
// receiving false closes the loop while allowing parallel routines
|
||||||
// to attempt to write to more (remove Peer when shutting down)
|
// to attempt to write to more (remove Peer when shutting down)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
node, need, proxLimit := self.kad.Suggest()
|
node, need, proxLimit := hive.kad.Suggest()
|
||||||
|
|
||||||
if node != nil && len(node.Url) > 0 {
|
if node != nil && len(node.Url) > 0 {
|
||||||
log.Trace(fmt.Sprintf("call known bee %v", node.Url))
|
log.Trace(fmt.Sprintf("call known bee %v", node.Url))
|
||||||
|
|
@ -164,10 +164,10 @@ func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPee
|
||||||
}
|
}
|
||||||
if need {
|
if need {
|
||||||
// a random peer is taken from the table
|
// a random peer is taken from the table
|
||||||
peers := self.kad.FindClosest(kademlia.RandomAddressAt(self.addr, rand.Intn(self.kad.MaxProx)), 1)
|
peers := hive.kad.FindClosest(kademlia.RandomAddressAt(hive.addr, rand.Intn(hive.kad.MaxProx)), 1)
|
||||||
if len(peers) > 0 {
|
if len(peers) > 0 {
|
||||||
// a random address at prox bin 0 is sent for lookup
|
// a random address at prox bin 0 is sent for lookup
|
||||||
randAddr := kademlia.RandomAddressAt(self.addr, proxLimit)
|
randAddr := kademlia.RandomAddressAt(hive.addr, proxLimit)
|
||||||
req := &retrieveRequestMsgData{
|
req := &retrieveRequestMsgData{
|
||||||
Key: storage.Key(randAddr[:]),
|
Key: storage.Key(randAddr[:]),
|
||||||
}
|
}
|
||||||
|
|
@ -181,11 +181,11 @@ func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPee
|
||||||
log.Info(fmt.Sprintf("no need for more bees"))
|
log.Info(fmt.Sprintf("no need for more bees"))
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case self.toggle <- need:
|
case hive.toggle <- need:
|
||||||
case <-self.quit:
|
case <-hive.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("queen's address: %v, population: %d (%d)", self.addr, self.kad.Count(), self.kad.DBCount()))
|
log.Debug(fmt.Sprintf("queen's address: %v, population: %d (%d)", hive.addr, hive.kad.Count(), hive.kad.DBCount()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return
|
return
|
||||||
|
|
@ -193,60 +193,60 @@ func (self *Hive) Start(id discover.NodeID, listenAddr func() string, connectPee
|
||||||
|
|
||||||
// keepAlive is a forever loop
|
// keepAlive is a forever loop
|
||||||
// in its awake state it periodically triggers connection attempts
|
// in its awake state it periodically triggers connection attempts
|
||||||
// by writing to self.more until Kademlia Table is saturated
|
// by writing to hive.more until Kademlia Table is saturated
|
||||||
// wake state is toggled by writing to self.toggle
|
// wake state is toggled by writing to hive.toggle
|
||||||
// it restarts if the table becomes non-full again due to disconnections
|
// it restarts if the table becomes non-full again due to disconnections
|
||||||
func (self *Hive) keepAlive() {
|
func (hive *Hive) keepAlive() {
|
||||||
alarm := time.NewTicker(time.Duration(self.callInterval)).C
|
alarm := time.NewTicker(time.Duration(hive.callInterval)).C
|
||||||
for {
|
for {
|
||||||
peersNumGauge.Update(int64(self.kad.Count()))
|
peersNumGauge.Update(int64(hive.kad.Count()))
|
||||||
select {
|
select {
|
||||||
case <-alarm:
|
case <-alarm:
|
||||||
if self.kad.DBCount() > 0 {
|
if hive.kad.DBCount() > 0 {
|
||||||
select {
|
select {
|
||||||
case self.more <- true:
|
case hive.more <- true:
|
||||||
log.Debug(fmt.Sprintf("buzz wakeup"))
|
log.Debug(fmt.Sprintf("buzz wakeup"))
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case need := <-self.toggle:
|
case need := <-hive.toggle:
|
||||||
if alarm == nil && need {
|
if alarm == nil && need {
|
||||||
alarm = time.NewTicker(time.Duration(self.callInterval)).C
|
alarm = time.NewTicker(time.Duration(hive.callInterval)).C
|
||||||
}
|
}
|
||||||
if alarm != nil && !need {
|
if alarm != nil && !need {
|
||||||
alarm = nil
|
alarm = nil
|
||||||
|
|
||||||
}
|
}
|
||||||
case <-self.quit:
|
case <-hive.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) Stop() error {
|
func (hive *Hive) Stop() error {
|
||||||
// closing toggle channel quits the updateloop
|
// closing toggle channel quits the updateloop
|
||||||
close(self.quit)
|
close(hive.quit)
|
||||||
return self.kad.Save(self.path, saveSync)
|
return hive.kad.Save(hive.path, saveSync)
|
||||||
}
|
}
|
||||||
|
|
||||||
// called at the end of a successful protocol handshake
|
// called at the end of a successful protocol handshake
|
||||||
func (self *Hive) addPeer(p *peer) error {
|
func (hive *Hive) addPeer(p *peer) error {
|
||||||
addPeerCounter.Inc(1)
|
addPeerCounter.Inc(1)
|
||||||
defer func() {
|
defer func() {
|
||||||
select {
|
select {
|
||||||
case self.more <- true:
|
case hive.more <- true:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
log.Trace(fmt.Sprintf("hi new bee %v", p))
|
log.Trace(fmt.Sprintf("hi new bee %v", p))
|
||||||
err := self.kad.On(p, loadSync)
|
err := hive.kad.On(p, loadSync)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// self lookup (can be encoded as nil/zero key since peers addr known) + no id ()
|
// hive lookup (can be encoded as nil/zero key since peers addr known) + no id ()
|
||||||
// the most common way of saying hi in bzz is initiation of gossip
|
// the most common way of saying hi in bzz is initiation of gossip
|
||||||
// let me know about anyone new from my hood , here is the storageradius
|
// let me know about anyone new from my hood , here is the storageradius
|
||||||
// to send the 6 byte self lookup
|
// to send the 6 byte hive lookup
|
||||||
// we do not record as request or forward it, just reply with peers
|
// we do not record as request or forward it, just reply with peers
|
||||||
p.retrieve(&retrieveRequestMsgData{})
|
p.retrieve(&retrieveRequestMsgData{})
|
||||||
log.Trace(fmt.Sprintf("'whatsup wheresdaparty' sent to %v", p))
|
log.Trace(fmt.Sprintf("'whatsup wheresdaparty' sent to %v", p))
|
||||||
|
|
@ -255,33 +255,33 @@ func (self *Hive) addPeer(p *peer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// called after peer disconnected
|
// called after peer disconnected
|
||||||
func (self *Hive) removePeer(p *peer) {
|
func (hive *Hive) removePeer(p *peer) {
|
||||||
removePeerCounter.Inc(1)
|
removePeerCounter.Inc(1)
|
||||||
log.Debug(fmt.Sprintf("bee %v removed", p))
|
log.Debug(fmt.Sprintf("bee %v removed", p))
|
||||||
self.kad.Off(p, saveSync)
|
hive.kad.Off(p, saveSync)
|
||||||
select {
|
select {
|
||||||
case self.more <- true:
|
case hive.more <- true:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
if self.kad.Count() == 0 {
|
if hive.kad.Count() == 0 {
|
||||||
log.Debug(fmt.Sprintf("empty, all bees gone"))
|
log.Debug(fmt.Sprintf("empty, all bees gone"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve a list of live peers that are closer to target than us
|
// Retrieve a list of live peers that are closer to target than us
|
||||||
func (self *Hive) getPeers(target storage.Key, max int) (peers []*peer) {
|
func (hive *Hive) getPeers(target storage.Key, max int) (peers []*peer) {
|
||||||
var addr kademlia.Address
|
var addr kademlia.Address
|
||||||
copy(addr[:], target[:])
|
copy(addr[:], target[:])
|
||||||
for _, node := range self.kad.FindClosest(addr, max) {
|
for _, node := range hive.kad.FindClosest(addr, max) {
|
||||||
peers = append(peers, node.(*peer))
|
peers = append(peers, node.(*peer))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// disconnects all the peers
|
// DropAll disconnects all the peers
|
||||||
func (self *Hive) DropAll() {
|
func (hive *Hive) DropAll() {
|
||||||
log.Info(fmt.Sprintf("dropping all bees"))
|
log.Info(fmt.Sprintf("dropping all bees"))
|
||||||
for _, node := range self.kad.FindClosest(kademlia.Address{}, 0) {
|
for _, node := range hive.kad.FindClosest(kademlia.Address{}, 0) {
|
||||||
node.Drop()
|
node.Drop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -298,10 +298,10 @@ func newNodeRecord(addr *peerAddr) *kademlia.NodeRecord {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// called by the protocol when receiving peerset (for target address)
|
// HandlePeersMsg called by the protocol when receiving peerset (for target address)
|
||||||
// peersMsgData is converted to a slice of NodeRecords for Kademlia
|
// peersMsgData is converted to a slice of NodeRecords for Kademlia
|
||||||
// this is to store all thats needed
|
// this is to store all thats needed
|
||||||
func (self *Hive) HandlePeersMsg(req *peersMsgData, from *peer) {
|
func (hive *Hive) HandlePeersMsg(req *peersMsgData, from *peer) {
|
||||||
var nrs []*kademlia.NodeRecord
|
var nrs []*kademlia.NodeRecord
|
||||||
for _, p := range req.Peers {
|
for _, p := range req.Peers {
|
||||||
if err := netutil.CheckRelayIP(from.remoteAddr.IP, p.IP); err != nil {
|
if err := netutil.CheckRelayIP(from.remoteAddr.IP, p.IP); err != nil {
|
||||||
|
|
@ -310,7 +310,7 @@ func (self *Hive) HandlePeersMsg(req *peersMsgData, from *peer) {
|
||||||
}
|
}
|
||||||
nrs = append(nrs, newNodeRecord(p))
|
nrs = append(nrs, newNodeRecord(p))
|
||||||
}
|
}
|
||||||
self.kad.Add(nrs)
|
hive.kad.Add(nrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// peer wraps the protocol instance to represent a connected peer
|
// peer wraps the protocol instance to represent a connected peer
|
||||||
|
|
@ -320,17 +320,17 @@ type peer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// protocol instance implements kademlia.Node interface (embedded peer)
|
// protocol instance implements kademlia.Node interface (embedded peer)
|
||||||
func (self *peer) Addr() kademlia.Address {
|
func (p *peer) Addr() kademlia.Address {
|
||||||
return self.remoteAddr.Addr
|
return p.remoteAddr.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *peer) Url() string {
|
func (p *peer) Url() string {
|
||||||
return self.remoteAddr.String()
|
return p.remoteAddr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO take into account traffic
|
// TODO take into account traffic
|
||||||
func (self *peer) LastActive() time.Time {
|
func (p *peer) LastActive() time.Time {
|
||||||
return self.lastActive
|
return p.lastActive
|
||||||
}
|
}
|
||||||
|
|
||||||
// reads the serialised form of sync state persisted as the 'Meta' attribute
|
// reads the serialised form of sync state persisted as the 'Meta' attribute
|
||||||
|
|
@ -370,19 +370,19 @@ func saveSync(record *kademlia.NodeRecord, node kademlia.Node) {
|
||||||
// the immediate response to a retrieve request,
|
// the immediate response to a retrieve request,
|
||||||
// sends relevant peer data given by the kademlia hive to the requester
|
// sends relevant peer data given by the kademlia hive to the requester
|
||||||
// TODO: remember peers sent for duration of the session, only new peers sent
|
// TODO: remember peers sent for duration of the session, only new peers sent
|
||||||
func (self *Hive) peers(req *retrieveRequestMsgData) {
|
func (hive *Hive) peers(req *retrieveRequestMsgData) {
|
||||||
if req != nil {
|
if req != nil {
|
||||||
var addrs []*peerAddr
|
var addrs []*peerAddr
|
||||||
if req.timeout == nil || time.Now().Before(*(req.timeout)) {
|
if req.timeout == nil || time.Now().Before(*(req.timeout)) {
|
||||||
key := req.Key
|
key := req.Key
|
||||||
// self lookup from remote peer
|
// hive lookup from remote peer
|
||||||
if storage.IsZeroKey(key) {
|
if storage.IsZeroKey(key) {
|
||||||
addr := req.from.Addr()
|
addr := req.from.Addr()
|
||||||
key = storage.Key(addr[:])
|
key = storage.Key(addr[:])
|
||||||
req.Key = nil
|
req.Key = nil
|
||||||
}
|
}
|
||||||
// get peer addresses from hive
|
// get peer addresses from hive
|
||||||
for _, peer := range self.getPeers(key, int(req.MaxPeers)) {
|
for _, peer := range hive.getPeers(key, int(req.MaxPeers)) {
|
||||||
addrs = append(addrs, peer.remoteAddr)
|
addrs = append(addrs, peer.remoteAddr)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("Hive sending %d peer addresses to %v. req.Id: %v, req.Key: %v", len(addrs), req.from, req.Id, req.Key.Log()))
|
log.Debug(fmt.Sprintf("Hive sending %d peer addresses to %v. req.Id: %v, req.Key: %v", len(addrs), req.from, req.Id, req.Key.Log()))
|
||||||
|
|
@ -398,6 +398,6 @@ func (self *Hive) peers(req *retrieveRequestMsgData) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Hive) String() string {
|
func (hive *Hive) String() string {
|
||||||
return self.kad.String()
|
return hive.kad.String()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func (a *Address) UnmarshalJSON(value []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// the string form of the binary representation of an address (only first 8 bits)
|
// Bin returns the string form of the binary representation of an address (only first 8 bits)
|
||||||
func (a Address) Bin() string {
|
func (a Address) Bin() string {
|
||||||
var bs []string
|
var bs []string
|
||||||
for _, b := range a[:] {
|
for _, b := range a[:] {
|
||||||
|
|
@ -75,7 +75,7 @@ func proximity(one, other Address) (ret int) {
|
||||||
return len(one) * 8
|
return len(one) * 8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address.ProxCmp compares the distances a->target and b->target.
|
// ProxCmp compares the distances a->target and b->target.
|
||||||
// Returns -1 if a is closer to target, 1 if b is closer to target
|
// Returns -1 if a is closer to target, 1 if b is closer to target
|
||||||
// and 0 if they are equal.
|
// and 0 if they are equal.
|
||||||
func (target Address) ProxCmp(a, b Address) int {
|
func (target Address) ProxCmp(a, b Address) int {
|
||||||
|
|
@ -91,7 +91,7 @@ func (target Address) ProxCmp(a, b Address) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// randomAddressAt(address, prox) generates a random address
|
// RandomAddressAt generates a random address
|
||||||
// at proximity order prox relative to address
|
// at proximity order prox relative to address
|
||||||
// if prox is negative a random address is generated
|
// if prox is negative a random address is generated
|
||||||
func RandomAddressAt(self Address, prox int) (addr Address) {
|
func RandomAddressAt(self Address, prox int) (addr Address) {
|
||||||
|
|
@ -116,7 +116,7 @@ func RandomAddressAt(self Address, prox int) (addr Address) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyRange(a0, a1, proxLimit) returns the address inclusive address
|
// KeyRange returns the address inclusive address
|
||||||
// range that contain addresses closer to one than other
|
// range that contain addresses closer to one than other
|
||||||
func KeyRange(one, other Address, proxLimit int) (start, stop Address) {
|
func KeyRange(one, other Address, proxLimit int) (start, stop Address) {
|
||||||
prox := proximity(one, other)
|
prox := proximity(one, other)
|
||||||
|
|
@ -167,7 +167,7 @@ func CommonBitsAddrByte(self, other Address, b byte, prox int) (addr Address) {
|
||||||
return CommonBitsAddrF(self, other, func() byte { return b }, prox)
|
return CommonBitsAddrF(self, other, func() byte { return b }, prox)
|
||||||
}
|
}
|
||||||
|
|
||||||
// randomAddressAt() generates a random address
|
// RandomAddress generates a random address
|
||||||
func RandomAddress() Address {
|
func RandomAddress() Address {
|
||||||
return RandomAddressAt(Address{}, -1)
|
return RandomAddressAt(Address{}, -1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,17 +43,17 @@ type NodeRecord struct {
|
||||||
node Node
|
node Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *NodeRecord) setSeen() {
|
func (nr *NodeRecord) setSeen() {
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
self.Seen = t
|
nr.Seen = t
|
||||||
self.After = t
|
nr.After = t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *NodeRecord) String() string {
|
func (nr *NodeRecord) String() string {
|
||||||
return fmt.Sprintf("<%v>", self.Addr)
|
return fmt.Sprintf("<%v>", nr.Addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// persisted node record database ()
|
// KadDb is a persisted node record database ()
|
||||||
type KadDb struct {
|
type KadDb struct {
|
||||||
Address Address
|
Address Address
|
||||||
Nodes [][]*NodeRecord
|
Nodes [][]*NodeRecord
|
||||||
|
|
@ -77,11 +77,11 @@ func newKadDb(addr Address, params *KadParams) *KadDb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord {
|
func (kdb *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord {
|
||||||
defer self.lock.Unlock()
|
defer kdb.lock.Unlock()
|
||||||
self.lock.Lock()
|
kdb.lock.Lock()
|
||||||
|
|
||||||
record, found := self.index[a]
|
record, found := kdb.index[a]
|
||||||
if !found {
|
if !found {
|
||||||
record = &NodeRecord{
|
record = &NodeRecord{
|
||||||
Addr: a,
|
Addr: a,
|
||||||
|
|
@ -89,8 +89,8 @@ func (self *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord {
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("add new record %v to kaddb", record))
|
log.Info(fmt.Sprintf("add new record %v to kaddb", record))
|
||||||
// insert in kaddb
|
// insert in kaddb
|
||||||
self.index[a] = record
|
kdb.index[a] = record
|
||||||
self.Nodes[index] = append(self.Nodes[index], record)
|
kdb.Nodes[index] = append(kdb.Nodes[index], record)
|
||||||
} else {
|
} else {
|
||||||
log.Info(fmt.Sprintf("found record %v in kaddb", record))
|
log.Info(fmt.Sprintf("found record %v in kaddb", record))
|
||||||
}
|
}
|
||||||
|
|
@ -102,26 +102,26 @@ func (self *KadDb) findOrCreate(index int, a Address, url string) *NodeRecord {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add adds node records to kaddb (persisted node record db)
|
// add adds node records to kaddb (persisted node record db)
|
||||||
func (self *KadDb) add(nrs []*NodeRecord, proximityBin func(Address) int) {
|
func (kdb *KadDb) add(nrs []*NodeRecord, proximityBin func(Address) int) {
|
||||||
defer self.lock.Unlock()
|
defer kdb.lock.Unlock()
|
||||||
self.lock.Lock()
|
kdb.lock.Lock()
|
||||||
var n int
|
var n int
|
||||||
var nodes []*NodeRecord
|
var nodes []*NodeRecord
|
||||||
for _, node := range nrs {
|
for _, node := range nrs {
|
||||||
_, found := self.index[node.Addr]
|
_, found := kdb.index[node.Addr]
|
||||||
if !found && node.Addr != self.Address {
|
if !found && node.Addr != kdb.Address {
|
||||||
node.setSeen()
|
node.setSeen()
|
||||||
self.index[node.Addr] = node
|
kdb.index[node.Addr] = node
|
||||||
index := proximityBin(node.Addr)
|
index := proximityBin(node.Addr)
|
||||||
dbcursor := self.cursors[index]
|
dbcursor := kdb.cursors[index]
|
||||||
nodes = self.Nodes[index]
|
nodes = kdb.Nodes[index]
|
||||||
// this is inefficient for allocation, need to just append then shift
|
// this is inefficient for allocation, need to just append then shift
|
||||||
newnodes := make([]*NodeRecord, len(nodes)+1)
|
newnodes := make([]*NodeRecord, len(nodes)+1)
|
||||||
copy(newnodes[:], nodes[:dbcursor])
|
copy(newnodes[:], nodes[:dbcursor])
|
||||||
newnodes[dbcursor] = node
|
newnodes[dbcursor] = node
|
||||||
copy(newnodes[dbcursor+1:], nodes[dbcursor:])
|
copy(newnodes[dbcursor+1:], nodes[dbcursor:])
|
||||||
log.Trace(fmt.Sprintf("new nodes: %v, nodes: %v", newnodes, nodes))
|
log.Trace(fmt.Sprintf("new nodes: %v, nodes: %v", newnodes, nodes))
|
||||||
self.Nodes[index] = newnodes
|
kdb.Nodes[index] = newnodes
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -168,10 +168,10 @@ offline past peer)
|
||||||
|
|
||||||
The second argument returned names the first missing slot found
|
The second argument returned names the first missing slot found
|
||||||
*/
|
*/
|
||||||
func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRecord, need bool, proxLimit int) {
|
func (kdb *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRecord, need bool, proxLimit int) {
|
||||||
// return nil, proxLimit indicates that all buckets are filled
|
// return nil, proxLimit indicates that all buckets are filled
|
||||||
defer self.lock.Unlock()
|
defer kdb.lock.Unlock()
|
||||||
self.lock.Lock()
|
kdb.lock.Lock()
|
||||||
|
|
||||||
var interval time.Duration
|
var interval time.Duration
|
||||||
var found bool
|
var found bool
|
||||||
|
|
@ -185,7 +185,7 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
|
||||||
for rounds := 1; rounds <= maxBinSize; rounds++ {
|
for rounds := 1; rounds <= maxBinSize; rounds++ {
|
||||||
ROUND:
|
ROUND:
|
||||||
// iterate over rows from PO 0 upto MaxProx
|
// iterate over rows from PO 0 upto MaxProx
|
||||||
for po, dbrow := range self.Nodes {
|
for po, dbrow := range kdb.Nodes {
|
||||||
// if row has rounds connected peers, then take the next
|
// if row has rounds connected peers, then take the next
|
||||||
if binSize(po) >= rounds {
|
if binSize(po) >= rounds {
|
||||||
continue ROUND
|
continue ROUND
|
||||||
|
|
@ -200,7 +200,7 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
|
||||||
// there is a missing slot - finding a node to connect to
|
// there is a missing slot - finding a node to connect to
|
||||||
// select a node record from the relavant kaddb row (of identical prox order)
|
// select a node record from the relavant kaddb row (of identical prox order)
|
||||||
ROW:
|
ROW:
|
||||||
for cursor = self.cursors[po]; !found && count < len(dbrow); cursor = (cursor + 1) % len(dbrow) {
|
for cursor = kdb.cursors[po]; !found && count < len(dbrow); cursor = (cursor + 1) % len(dbrow) {
|
||||||
count++
|
count++
|
||||||
node = dbrow[cursor]
|
node = dbrow[cursor]
|
||||||
|
|
||||||
|
|
@ -217,10 +217,10 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
|
||||||
}
|
}
|
||||||
|
|
||||||
delta = time.Since(node.Seen)
|
delta = time.Since(node.Seen)
|
||||||
if delta < self.initialRetryInterval {
|
if delta < kdb.initialRetryInterval {
|
||||||
delta = self.initialRetryInterval
|
delta = kdb.initialRetryInterval
|
||||||
}
|
}
|
||||||
if delta > self.purgeInterval {
|
if delta > kdb.purgeInterval {
|
||||||
// remove node
|
// remove node
|
||||||
purge[cursor] = true
|
purge[cursor] = true
|
||||||
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) unreachable since %v. Removed", node.Addr, po, cursor, node.Seen))
|
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) unreachable since %v. Removed", node.Addr, po, cursor, node.Seen))
|
||||||
|
|
@ -230,15 +230,15 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
|
||||||
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) ready to be tried. seen at %v (%v ago), scheduled at %v", node.Addr, po, cursor, node.Seen, delta, node.After))
|
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) ready to be tried. seen at %v (%v ago), scheduled at %v", node.Addr, po, cursor, node.Seen, delta, node.After))
|
||||||
|
|
||||||
// scheduling next check
|
// scheduling next check
|
||||||
interval = delta * time.Duration(self.connRetryExp)
|
interval = delta * time.Duration(kdb.connRetryExp)
|
||||||
after = time.Now().Add(interval)
|
after = time.Now().Add(interval)
|
||||||
|
|
||||||
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) selected as candidate connection %v. seen at %v (%v ago), selectable since %v, retry after %v (in %v)", node.Addr, po, cursor, rounds, node.Seen, delta, node.After, after, interval))
|
log.Debug(fmt.Sprintf("kaddb record %v (PO%03d:%d) selected as candidate connection %v. seen at %v (%v ago), selectable since %v, retry after %v (in %v)", node.Addr, po, cursor, rounds, node.Seen, delta, node.After, after, interval))
|
||||||
node.After = after
|
node.After = after
|
||||||
found = true
|
found = true
|
||||||
} // ROW
|
} // ROW
|
||||||
self.cursors[po] = cursor
|
kdb.cursors[po] = cursor
|
||||||
self.delete(po, purge)
|
kdb.delete(po, purge)
|
||||||
if found {
|
if found {
|
||||||
return node, need, proxLimit
|
return node, need, proxLimit
|
||||||
}
|
}
|
||||||
|
|
@ -251,33 +251,33 @@ func (self *KadDb) findBest(maxBinSize int, binSize func(int) int) (node *NodeRe
|
||||||
// deletes the noderecords of a kaddb row corresponding to the indexes
|
// deletes the noderecords of a kaddb row corresponding to the indexes
|
||||||
// caller must hold the dblock
|
// caller must hold the dblock
|
||||||
// the call is unsafe, no index checks
|
// the call is unsafe, no index checks
|
||||||
func (self *KadDb) delete(row int, purge []bool) {
|
func (kdb *KadDb) delete(row int, purge []bool) {
|
||||||
var nodes []*NodeRecord
|
var nodes []*NodeRecord
|
||||||
dbrow := self.Nodes[row]
|
dbrow := kdb.Nodes[row]
|
||||||
for i, del := range purge {
|
for i, del := range purge {
|
||||||
if i == self.cursors[row] {
|
if i == kdb.cursors[row] {
|
||||||
//reset cursor
|
//reset cursor
|
||||||
self.cursors[row] = len(nodes)
|
kdb.cursors[row] = len(nodes)
|
||||||
}
|
}
|
||||||
// delete the entry to be purged
|
// delete the entry to be purged
|
||||||
if del {
|
if del {
|
||||||
delete(self.index, dbrow[i].Addr)
|
delete(kdb.index, dbrow[i].Addr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// otherwise append to new list
|
// otherwise append to new list
|
||||||
nodes = append(nodes, dbrow[i])
|
nodes = append(nodes, dbrow[i])
|
||||||
}
|
}
|
||||||
self.Nodes[row] = nodes
|
kdb.Nodes[row] = nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
// save persists kaddb on disk (written to file on path in json format.
|
// save persists kaddb on disk (written to file on path in json format.
|
||||||
func (self *KadDb) save(path string, cb func(*NodeRecord, Node)) error {
|
func (kdb *KadDb) save(path string, cb func(*NodeRecord, Node)) error {
|
||||||
defer self.lock.Unlock()
|
defer kdb.lock.Unlock()
|
||||||
self.lock.Lock()
|
kdb.lock.Lock()
|
||||||
|
|
||||||
var n int
|
var n int
|
||||||
|
|
||||||
for _, b := range self.Nodes {
|
for _, b := range kdb.Nodes {
|
||||||
for _, node := range b {
|
for _, node := range b {
|
||||||
n++
|
n++
|
||||||
node.After = time.Now()
|
node.After = time.Now()
|
||||||
|
|
@ -288,7 +288,7 @@ func (self *KadDb) save(path string, cb func(*NodeRecord, Node)) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.MarshalIndent(self, "", " ")
|
data, err := json.MarshalIndent(kdb, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -302,9 +302,9 @@ func (self *KadDb) save(path string, cb func(*NodeRecord, Node)) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load(path) loads the node record database (kaddb) from file on path.
|
// Load(path) loads the node record database (kaddb) from file on path.
|
||||||
func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err error) {
|
func (kdb *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err error) {
|
||||||
defer self.lock.Unlock()
|
defer kdb.lock.Unlock()
|
||||||
self.lock.Lock()
|
kdb.lock.Lock()
|
||||||
|
|
||||||
var data []byte
|
var data []byte
|
||||||
data, err = ioutil.ReadFile(path)
|
data, err = ioutil.ReadFile(path)
|
||||||
|
|
@ -312,13 +312,13 @@ func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err erro
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(data, self)
|
err = json.Unmarshal(data, kdb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var n int
|
var n int
|
||||||
var purge []bool
|
var purge []bool
|
||||||
for po, b := range self.Nodes {
|
for po, b := range kdb.Nodes {
|
||||||
purge = make([]bool, len(b))
|
purge = make([]bool, len(b))
|
||||||
ROW:
|
ROW:
|
||||||
for i, node := range b {
|
for i, node := range b {
|
||||||
|
|
@ -333,9 +333,9 @@ func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err erro
|
||||||
if node.After.IsZero() {
|
if node.After.IsZero() {
|
||||||
node.After = time.Now()
|
node.After = time.Now()
|
||||||
}
|
}
|
||||||
self.index[node.Addr] = node
|
kdb.index[node.Addr] = node
|
||||||
}
|
}
|
||||||
self.delete(po, purge)
|
kdb.delete(po, purge)
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("loaded kaddb with %v nodes from %v", n, path))
|
log.Info(fmt.Sprintf("loaded kaddb with %v nodes from %v", n, path))
|
||||||
|
|
||||||
|
|
@ -343,8 +343,8 @@ func (self *KadDb) load(path string, cb func(*NodeRecord, Node) error) (err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor for KAD offline db count
|
// accessor for KAD offline db count
|
||||||
func (self *KadDb) count() int {
|
func (kdb *KadDb) count() int {
|
||||||
defer self.lock.Unlock()
|
defer kdb.lock.Unlock()
|
||||||
self.lock.Lock()
|
kdb.lock.Lock()
|
||||||
return len(self.index)
|
return len(kdb.index)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,25 +109,25 @@ func New(addr Address, params *KadParams) *Kademlia {
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor for KAD base address
|
// accessor for KAD base address
|
||||||
func (self *Kademlia) Addr() Address {
|
func (k *Kademlia) Addr() Address {
|
||||||
return self.addr
|
return self.addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor for KAD active node count
|
// accessor for KAD active node count
|
||||||
func (self *Kademlia) Count() int {
|
func (k *Kademlia) Count() int {
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
return self.count
|
return self.count
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor for KAD active node count
|
// accessor for KAD active node count
|
||||||
func (self *Kademlia) DBCount() int {
|
func (k *Kademlia) DBCount() int {
|
||||||
return self.db.count()
|
return self.db.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
// On is the entry point called when a new nodes is added
|
// On is the entry point called when a new nodes is added
|
||||||
// unsafe in that node is not checked to be already active node (to be called once)
|
// unsafe in that node is not checked to be already active node (to be called once)
|
||||||
func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error) {
|
func (k *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error) {
|
||||||
log.Debug(fmt.Sprintf("%v", self))
|
log.Debug(fmt.Sprintf("%v", self))
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
|
|
@ -186,7 +186,7 @@ func (self *Kademlia) On(node Node, cb func(*NodeRecord, Node) error) (err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Off is the called when a node is taken offline (from the protocol main loop exit)
|
// Off is the called when a node is taken offline (from the protocol main loop exit)
|
||||||
func (self *Kademlia) Off(node Node, cb func(*NodeRecord, Node)) (err error) {
|
func (k *Kademlia) Off(node Node, cb func(*NodeRecord, Node)) (err error) {
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
|
|
||||||
|
|
@ -218,23 +218,23 @@ func (self *Kademlia) Off(node Node, cb func(*NodeRecord, Node)) (err error) {
|
||||||
// 2) the sum of all items are the minimum possible but higher than ProxBinSize
|
// 2) the sum of all items are the minimum possible but higher than ProxBinSize
|
||||||
// adjust Prox (proxLimit and proxSize after an insertion/removal of nodes)
|
// adjust Prox (proxLimit and proxSize after an insertion/removal of nodes)
|
||||||
// caller holds the lock
|
// caller holds the lock
|
||||||
func (self *Kademlia) setProxLimit(r int, on bool) {
|
func (k *Kademlia) setProxLimit(r int, on bool) {
|
||||||
// if the change is outside the core (PO lower)
|
// if the change is outside the core (PO lower)
|
||||||
// and the change does not leave a bucket empty then
|
// and the change does not leave a bucket empty then
|
||||||
// no adjustment needed
|
// no adjustment needed
|
||||||
if r < self.proxLimit && len(self.buckets[r]) > 0 {
|
if r < self.proxLimit && len(k.buckets[r]) > 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// if on=a node was added, then r must be within prox limit so increment cardinality
|
// if on=a node was added, then r must be within prox limit so increment cardinality
|
||||||
if on {
|
if on {
|
||||||
self.proxSize++
|
self.proxSize++
|
||||||
curr := len(self.buckets[self.proxLimit])
|
curr := len(k.buckets[self.proxLimit])
|
||||||
// if now core is big enough without the furthest bucket, then contract
|
// if now core is big enough without the furthest bucket, then contract
|
||||||
// this can result in more than one bucket change
|
// this can result in more than one bucket change
|
||||||
for self.proxSize >= self.ProxBinSize+curr && curr > 0 {
|
for self.proxSize >= self.ProxBinSize+curr && curr > 0 {
|
||||||
self.proxSize -= curr
|
self.proxSize -= curr
|
||||||
self.proxLimit++
|
self.proxLimit++
|
||||||
curr = len(self.buckets[self.proxLimit])
|
curr = len(k.buckets[self.proxLimit])
|
||||||
|
|
||||||
log.Trace(fmt.Sprintf("proxbin contraction (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r))
|
log.Trace(fmt.Sprintf("proxbin contraction (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r))
|
||||||
}
|
}
|
||||||
|
|
@ -245,21 +245,21 @@ func (self *Kademlia) setProxLimit(r int, on bool) {
|
||||||
self.proxSize--
|
self.proxSize--
|
||||||
}
|
}
|
||||||
// expand core by lowering prox limit until hit zero or cover the empty bucket or reached target cardinality
|
// expand core by lowering prox limit until hit zero or cover the empty bucket or reached target cardinality
|
||||||
for (self.proxSize < self.ProxBinSize || r < self.proxLimit) &&
|
for (k.proxSize < self.ProxBinSize || r < self.proxLimit) &&
|
||||||
self.proxLimit > 0 {
|
self.proxLimit > 0 {
|
||||||
//
|
//
|
||||||
self.proxLimit--
|
self.proxLimit--
|
||||||
self.proxSize += len(self.buckets[self.proxLimit])
|
self.proxSize += len(k.buckets[self.proxLimit])
|
||||||
log.Trace(fmt.Sprintf("proxbin expansion (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r))
|
log.Trace(fmt.Sprintf("proxbin expansion (size: %v, limit: %v, bin: %v)", self.proxSize, self.proxLimit, r))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
returns the list of nodes belonging to the same proximity bin
|
FindClosest returns the list of nodes belonging to the same proximity bin
|
||||||
as the target. The most proximate bin will be the union of the bins between
|
as the target. The most proximate bin will be the union of the bins between
|
||||||
proxLimit and MaxProx.
|
proxLimit and MaxProx.
|
||||||
*/
|
*/
|
||||||
func (self *Kademlia) FindClosest(target Address, max int) []Node {
|
func (k *Kademlia) FindClosest(target Address, max int) []Node {
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
|
|
||||||
|
|
@ -289,7 +289,7 @@ func (self *Kademlia) FindClosest(target Address, max int) []Node {
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
// terminate if index reached the bottom or enough peers > min
|
// terminate if index reached the bottom or enough peers > min
|
||||||
log.Trace(fmt.Sprintf("add %v -> %v (PO%02d, PO%03d)", len(self.buckets[index]), n, index, po))
|
log.Trace(fmt.Sprintf("add %v -> %v (PO%02d, PO%03d)", len(k.buckets[index]), n, index, po))
|
||||||
if n >= min && (step < 0 || max == 0) {
|
if n >= min && (step < 0 || max == 0) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -304,14 +304,14 @@ func (self *Kademlia) FindClosest(target Address, max int) []Node {
|
||||||
return r.nodes
|
return r.nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Kademlia) Suggest() (*NodeRecord, bool, int) {
|
func (k *Kademlia) Suggest() (*NodeRecord, bool, int) {
|
||||||
defer self.lock.RUnlock()
|
defer self.lock.RUnlock()
|
||||||
self.lock.RLock()
|
self.lock.RLock()
|
||||||
return self.db.findBest(self.BucketSize, func(i int) int { return len(self.buckets[i]) })
|
return self.db.findBest(k.BucketSize, func(i int) int { return len(k.buckets[i]) })
|
||||||
}
|
}
|
||||||
|
|
||||||
// adds node records to kaddb (persisted node record db)
|
// Add node records to kaddb (persisted node record db)
|
||||||
func (self *Kademlia) Add(nrs []*NodeRecord) {
|
func (k *Kademlia) Add(nrs []*NodeRecord) {
|
||||||
self.db.add(nrs, self.proximityBin)
|
self.db.add(nrs, self.proximityBin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -369,8 +369,8 @@ a guaranteed constant maximum limit on the number of hops needed to reach one
|
||||||
node from the other.
|
node from the other.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (self *Kademlia) proximityBin(other Address) (ret int) {
|
func (k *Kademlia) proximityBin(other Address) (ret int) {
|
||||||
ret = proximity(self.addr, other)
|
ret = proximity(k.addr, other)
|
||||||
if ret > self.MaxProx {
|
if ret > self.MaxProx {
|
||||||
ret = self.MaxProx
|
ret = self.MaxProx
|
||||||
}
|
}
|
||||||
|
|
@ -378,24 +378,24 @@ func (self *Kademlia) proximityBin(other Address) (ret int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// provides keyrange for chunk db iteration
|
// provides keyrange for chunk db iteration
|
||||||
func (self *Kademlia) KeyRange(other Address) (start, stop Address) {
|
func (k *Kademlia) KeyRange(other Address) (start, stop Address) {
|
||||||
defer self.lock.RUnlock()
|
defer self.lock.RUnlock()
|
||||||
self.lock.RLock()
|
self.lock.RLock()
|
||||||
return KeyRange(self.addr, other, self.proxLimit)
|
return KeyRange(k.addr, other, self.proxLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// save persists kaddb on disk (written to file on path in json format.
|
// save persists kaddb on disk (written to file on path in json format.
|
||||||
func (self *Kademlia) Save(path string, cb func(*NodeRecord, Node)) error {
|
func (k *Kademlia) Save(path string, cb func(*NodeRecord, Node)) error {
|
||||||
return self.db.save(path, cb)
|
return self.db.save(path, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load(path) loads the node record database (kaddb) from file on path.
|
// Load(path) loads the node record database (kaddb) from file on path.
|
||||||
func (self *Kademlia) Load(path string, cb func(*NodeRecord, Node) error) (err error) {
|
func (k *Kademlia) Load(path string, cb func(*NodeRecord, Node) error) (err error) {
|
||||||
return self.db.load(path, cb)
|
return self.db.load(path, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// kademlia table + kaddb table displayed with ascii
|
// kademlia table + kaddb table displayed with ascii
|
||||||
func (self *Kademlia) String() string {
|
func (k *Kademlia) String() string {
|
||||||
defer self.lock.RUnlock()
|
defer self.lock.RUnlock()
|
||||||
self.lock.RLock()
|
self.lock.RLock()
|
||||||
defer self.db.lock.RUnlock()
|
defer self.db.lock.RUnlock()
|
||||||
|
|
@ -404,7 +404,7 @@ func (self *Kademlia) String() string {
|
||||||
var rows []string
|
var rows []string
|
||||||
rows = append(rows, "=========================================================================")
|
rows = append(rows, "=========================================================================")
|
||||||
rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %v", time.Now().UTC().Format(time.UnixDate), self.addr.String()[:6]))
|
rows = append(rows, fmt.Sprintf("%v KΛÐΞMLIΛ hive: queen's address: %v", time.Now().UTC().Format(time.UnixDate), self.addr.String()[:6]))
|
||||||
rows = append(rows, fmt.Sprintf("population: %d (%d), proxLimit: %d, proxSize: %d", self.count, len(self.db.index), self.proxLimit, self.proxSize))
|
rows = append(rows, fmt.Sprintf("population: %d (%d), proxLimit: %d, proxSize: %d", self.count, len(k.db.index), self.proxLimit, self.proxSize))
|
||||||
rows = append(rows, fmt.Sprintf("MaxProx: %d, ProxBinSize: %d, BucketSize: %d", self.MaxProx, self.ProxBinSize, self.BucketSize))
|
rows = append(rows, fmt.Sprintf("MaxProx: %d, ProxBinSize: %d, BucketSize: %d", self.MaxProx, self.ProxBinSize, self.BucketSize))
|
||||||
|
|
||||||
for i, bucket := range self.buckets {
|
for i, bucket := range self.buckets {
|
||||||
|
|
@ -425,7 +425,7 @@ func (self *Kademlia) String() string {
|
||||||
for ; k < 4; k++ {
|
for ; k < 4; k++ {
|
||||||
row = append(row, " ")
|
row = append(row, " ")
|
||||||
}
|
}
|
||||||
row = append(row, fmt.Sprintf("| %2d %2d", len(self.db.Nodes[i]), self.db.cursors[i]))
|
row = append(row, fmt.Sprintf("| %2d %2d", len(k.db.Nodes[i]), self.db.cursors[i]))
|
||||||
|
|
||||||
for j, p := range self.db.Nodes[i] {
|
for j, p := range self.db.Nodes[i] {
|
||||||
row = append(row, p.Addr.String()[:6])
|
row = append(row, p.Addr.String()[:6])
|
||||||
|
|
@ -442,12 +442,12 @@ func (self *Kademlia) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
//We have to build up the array of counters for each index
|
//We have to build up the array of counters for each index
|
||||||
func (self *Kademlia) initMetricsVariables() {
|
func (k *Kademlia) initMetricsVariables() {
|
||||||
//create the arrays
|
//create the arrays
|
||||||
bucketAddIndexCount = make([]metrics.Counter, self.MaxProx+1)
|
bucketAddIndexCount = make([]metrics.Counter, self.MaxProx+1)
|
||||||
bucketRmIndexCount = make([]metrics.Counter, self.MaxProx+1)
|
bucketRmIndexCount = make([]metrics.Counter, self.MaxProx+1)
|
||||||
//at each index create a metrics counter
|
//at each index create a metrics counter
|
||||||
for i := 0; i < (self.KadParams.MaxProx + 1); i++ {
|
for i := 0; i < (k.KadParams.MaxProx + 1); i++ {
|
||||||
bucketAddIndexCount[i] = metrics.NewRegisteredCounter(fmt.Sprintf("network.kademlia.bucket.add.%d.index", i), nil)
|
bucketAddIndexCount[i] = metrics.NewRegisteredCounter(fmt.Sprintf("network.kademlia.bucket.add.%d.index", i), nil)
|
||||||
bucketRmIndexCount[i] = metrics.NewRegisteredCounter(fmt.Sprintf("network.kademlia.bucket.rm.%d.index", i), nil)
|
bucketRmIndexCount[i] = metrics.NewRegisteredCounter(fmt.Sprintf("network.kademlia.bucket.rm.%d.index", i), nil)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -272,31 +272,31 @@ func TestSaveLoad(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Kademlia) proxCheck(t *testing.T) bool {
|
func (k *Kademlia) proxCheck(t *testing.T) bool {
|
||||||
var sum int
|
var sum int
|
||||||
for i, b := range self.buckets {
|
for i, b := range k.buckets {
|
||||||
l := len(b)
|
l := len(b)
|
||||||
// if we are in the high prox multibucket
|
// if we are in the high prox multibucket
|
||||||
if i >= self.proxLimit {
|
if i >= k.proxLimit {
|
||||||
sum += l
|
sum += l
|
||||||
} else if l == 0 {
|
} else if l == 0 {
|
||||||
t.Errorf("bucket %d empty, yet proxLimit is %d\n%v", len(b), self.proxLimit, self)
|
t.Errorf("bucket %d empty, yet proxLimit is %d\n%v", len(b), k.proxLimit, k)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check if merged high prox bucket does not exceed size
|
// check if merged high prox bucket does not exceed size
|
||||||
if sum > 0 {
|
if sum > 0 {
|
||||||
if sum != self.proxSize {
|
if sum != k.proxSize {
|
||||||
t.Errorf("proxSize incorrect, expected %v, got %v", sum, self.proxSize)
|
t.Errorf("proxSize incorrect, expected %v, got %v", sum, k.proxSize)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
last := len(self.buckets[self.proxLimit])
|
last := len(k.buckets[k.proxLimit])
|
||||||
if last > 0 && sum >= self.ProxBinSize+last {
|
if last > 0 && sum >= k.ProxBinSize+last {
|
||||||
t.Errorf("proxLimit %v incorrect, redundant non-empty bucket %d added to proxBin with %v (target %v)\n%v", self.proxLimit, last, sum-last, self.ProxBinSize, self)
|
t.Errorf("proxLimit %v incorrect, redundant non-empty bucket %d added to proxBin with %v (target %v)\n%v", k.proxLimit, last, sum-last, k.ProxBinSize, k)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if self.proxLimit > 0 && sum < self.ProxBinSize {
|
if k.proxLimit > 0 && sum < k.ProxBinSize {
|
||||||
t.Errorf("proxLimit %v incorrect. proxSize %v is less than target %v, yet there is more peers", self.proxLimit, sum, self.ProxBinSize)
|
t.Errorf("proxLimit %v incorrect. proxSize %v is less than target %v, yet there is more peers", k.proxLimit, sum, k.ProxBinSize)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ type statusMsgData struct {
|
||||||
NetworkId uint64
|
NetworkId uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *statusMsgData) String() string {
|
func (data *statusMsgData) String() string {
|
||||||
return fmt.Sprintf("Status: Version: %v, ID: %v, Addr: %v, Swap: %v, NetworkId: %v", self.Version, self.ID, self.Addr, self.Swap, self.NetworkId)
|
return fmt.Sprintf("Status: Version: %v, ID: %v, Addr: %v, Swap: %v, NetworkId: %v", data.Version, data.ID, data.Addr, data.Swap, data.NetworkId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -86,18 +86,18 @@ type storeRequestMsgData struct {
|
||||||
from *peer // [not serialised] protocol registers the requester
|
from *peer // [not serialised] protocol registers the requester
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self storeRequestMsgData) String() string {
|
func (data storeRequestMsgData) String() string {
|
||||||
var from string
|
var from string
|
||||||
if self.from == nil {
|
if data.from == nil {
|
||||||
from = "self"
|
from = "data"
|
||||||
} else {
|
} else {
|
||||||
from = self.from.Addr().String()
|
from = data.from.Addr().String()
|
||||||
}
|
}
|
||||||
end := len(self.SData)
|
end := len(data.SData)
|
||||||
if len(self.SData) > 10 {
|
if len(data.SData) > 10 {
|
||||||
end = 10
|
end = 10
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("from: %v, Key: %v; ID: %v, requestTimeout: %v, storageTimeout: %v, SData %x", from, self.Key, self.Id, self.requestTimeout, self.storageTimeout, self.SData[:end])
|
return fmt.Sprintf("from: %v, Key: %v; ID: %v, requestTimeout: %v, storageTimeout: %v, SData %x", from, data.Key, data.Id, data.requestTimeout, data.storageTimeout, data.SData[:end])
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -118,7 +118,7 @@ prompting a peers response but not launching a search. Lookup requests are meant
|
||||||
to be used to bootstrap kademlia tables.
|
to be used to bootstrap kademlia tables.
|
||||||
|
|
||||||
In the special case that the key is the zero value as well, the remote peer's
|
In the special case that the key is the zero value as well, the remote peer's
|
||||||
address is assumed (the message is to be handled as a self lookup request).
|
address is assumed (the message is to be handled as a data lookup request).
|
||||||
The response is a PeersMsg with the peers in the kademlia proximity bin
|
The response is a PeersMsg with the peers in the kademlia proximity bin
|
||||||
corresponding to the address.
|
corresponding to the address.
|
||||||
*/
|
*/
|
||||||
|
|
@ -133,40 +133,40 @@ type retrieveRequestMsgData struct {
|
||||||
from *peer //
|
from *peer //
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *retrieveRequestMsgData) String() string {
|
func (data *retrieveRequestMsgData) String() string {
|
||||||
var from string
|
var from string
|
||||||
if self.from == nil {
|
if data.from == nil {
|
||||||
from = "ourselves"
|
from = "ourselves"
|
||||||
} else {
|
} else {
|
||||||
from = self.from.Addr().String()
|
from = data.from.Addr().String()
|
||||||
}
|
}
|
||||||
var target []byte
|
var target []byte
|
||||||
if len(self.Key) > 3 {
|
if len(data.Key) > 3 {
|
||||||
target = self.Key[:4]
|
target = data.Key[:4]
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("from: %v, Key: %x; ID: %v, MaxSize: %v, MaxPeers: %d", from, target, self.Id, self.MaxSize, self.MaxPeers)
|
return fmt.Sprintf("from: %v, Key: %x; ID: %v, MaxSize: %v, MaxPeers: %d", from, target, data.Id, data.MaxSize, data.MaxPeers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookups are encoded by missing request ID
|
// lookups are encoded by missing request ID
|
||||||
func (self *retrieveRequestMsgData) isLookup() bool {
|
func (data *retrieveRequestMsgData) isLookup() bool {
|
||||||
return self.Id == 0
|
return data.Id == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets timeout fields
|
// sets timeout fields
|
||||||
func (self *retrieveRequestMsgData) setTimeout(t *time.Time) {
|
func (data *retrieveRequestMsgData) setTimeout(t *time.Time) {
|
||||||
self.timeout = t
|
data.timeout = t
|
||||||
if t != nil {
|
if t != nil {
|
||||||
self.Timeout = uint64(t.UnixNano())
|
data.Timeout = uint64(t.UnixNano())
|
||||||
} else {
|
} else {
|
||||||
self.Timeout = 0
|
data.Timeout = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *retrieveRequestMsgData) getTimeout() (t *time.Time) {
|
func (data *retrieveRequestMsgData) getTimeout() (t *time.Time) {
|
||||||
if self.Timeout > 0 && self.timeout == nil {
|
if data.Timeout > 0 && data.timeout == nil {
|
||||||
timeout := time.Unix(int64(self.Timeout), 0)
|
timeout := time.Unix(int64(data.Timeout), 0)
|
||||||
t = &timeout
|
t = &timeout
|
||||||
self.timeout = t
|
data.timeout = t
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -180,10 +180,10 @@ type peerAddr struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// peerAddr pretty prints as enode
|
// peerAddr pretty prints as enode
|
||||||
func (self *peerAddr) String() string {
|
func (addr *peerAddr) String() string {
|
||||||
var nodeid discover.NodeID
|
var nodeid discover.NodeID
|
||||||
copy(nodeid[:], self.ID)
|
copy(nodeid[:], addr.ID)
|
||||||
return discover.NewNode(nodeid, self.IP, 0, self.Port).String()
|
return discover.NewNode(nodeid, addr.IP, 0, addr.Port).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -199,7 +199,7 @@ the timeout or not.
|
||||||
NodeID serves as the owner of payment contracts and signer of proofs of transfer.
|
NodeID serves as the owner of payment contracts and signer of proofs of transfer.
|
||||||
|
|
||||||
The Key is the target (if response to a retrieval request) or missing (zero value)
|
The Key is the target (if response to a retrieval request) or missing (zero value)
|
||||||
peers address (hash of NodeID) if retrieval request was a self lookup.
|
peers address (hash of NodeID) if retrieval request was a data lookup.
|
||||||
|
|
||||||
Peers message is requested by retrieval requests with a missing or zero value request ID
|
Peers message is requested by retrieval requests with a missing or zero value request ID
|
||||||
*/
|
*/
|
||||||
|
|
@ -213,26 +213,26 @@ type peersMsgData struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// peers msg pretty printer
|
// peers msg pretty printer
|
||||||
func (self *peersMsgData) String() string {
|
func (data *peersMsgData) String() string {
|
||||||
var from string
|
var from string
|
||||||
if self.from == nil {
|
if data.from == nil {
|
||||||
from = "ourselves"
|
from = "ourselves"
|
||||||
} else {
|
} else {
|
||||||
from = self.from.Addr().String()
|
from = data.from.Addr().String()
|
||||||
}
|
}
|
||||||
var target []byte
|
var target []byte
|
||||||
if len(self.Key) > 3 {
|
if len(data.Key) > 3 {
|
||||||
target = self.Key[:4]
|
target = data.Key[:4]
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("from: %v, Key: %x; ID: %v, Peers: %v", from, target, self.Id, self.Peers)
|
return fmt.Sprintf("from: %v, Key: %x; ID: %v, Peers: %v", from, target, data.Id, data.Peers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *peersMsgData) setTimeout(t *time.Time) {
|
func (data *peersMsgData) setTimeout(t *time.Time) {
|
||||||
self.timeout = t
|
data.timeout = t
|
||||||
if t != nil {
|
if t != nil {
|
||||||
self.Timeout = uint64(t.UnixNano())
|
data.Timeout = uint64(t.UnixNano())
|
||||||
} else {
|
} else {
|
||||||
self.Timeout = 0
|
data.Timeout = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,8 +248,8 @@ type syncRequestMsgData struct {
|
||||||
SyncState *syncState `rlp:"nil"`
|
SyncState *syncState `rlp:"nil"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *syncRequestMsgData) String() string {
|
func (data *syncRequestMsgData) String() string {
|
||||||
return fmt.Sprintf("%v", self.SyncState)
|
return fmt.Sprintf("%v", data.SyncState)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -265,8 +265,8 @@ type deliveryRequestMsgData struct {
|
||||||
Deliver []*syncRequest
|
Deliver []*syncRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *deliveryRequestMsgData) String() string {
|
func (data *deliveryRequestMsgData) String() string {
|
||||||
return fmt.Sprintf("sync request for new chunks\ndelivery request for %v chunks", len(self.Deliver))
|
return fmt.Sprintf("sync request for new chunks\ndelivery request for %v chunks", len(data.Deliver))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -287,8 +287,8 @@ type unsyncedKeysMsgData struct {
|
||||||
State *syncState
|
State *syncState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *unsyncedKeysMsgData) String() string {
|
func (data *unsyncedKeysMsgData) String() string {
|
||||||
return fmt.Sprintf("sync: keys of %d new chunks (state %v) => synced: %v", len(self.Unsynced), self.State, self.State.Synced)
|
return fmt.Sprintf("sync: keys of %d new chunks (state %v) => synced: %v", len(data.Unsynced), data.State, data.State.Synced)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -303,6 +303,6 @@ type paymentMsgData struct {
|
||||||
Promise *chequebook.Cheque // payment with cheque
|
Promise *chequebook.Cheque // payment with cheque
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *paymentMsgData) String() string {
|
func (data *paymentMsgData) String() string {
|
||||||
return fmt.Sprintf("payment for %d units: %v", self.Units, self.Promise)
|
return fmt.Sprintf("payment for %d units: %v", data.Units, data.Promise)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -193,13 +193,13 @@ func run(requestDb *storage.LDBDatabase, depo StorageHandler, backend chequebook
|
||||||
|
|
||||||
// TODO: may need to implement protocol drop only? don't want to kick off the peer
|
// TODO: may need to implement protocol drop only? don't want to kick off the peer
|
||||||
// if they are useful for other protocols
|
// if they are useful for other protocols
|
||||||
func (self *bzz) Drop() {
|
func (bzz *bzz) Drop() {
|
||||||
self.peer.Disconnect(p2p.DiscSubprotocolError)
|
bzz.peer.Disconnect(p2p.DiscSubprotocolError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// one cycle of the main forever loop that handles and dispatches incoming messages
|
// one cycle of the main forever loop that handles and dispatches incoming messages
|
||||||
func (self *bzz) handle() error {
|
func (bzz *bzz) handle() error {
|
||||||
msg, err := self.rw.ReadMsg()
|
msg, err := bzz.rw.ReadMsg()
|
||||||
log.Debug(fmt.Sprintf("<- %v", msg))
|
log.Debug(fmt.Sprintf("<- %v", msg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -232,7 +232,7 @@ func (self *bzz) handle() error {
|
||||||
self.lastActive = time.Now()
|
self.lastActive = time.Now()
|
||||||
log.Trace(fmt.Sprintf("incoming store request: %s", req.String()))
|
log.Trace(fmt.Sprintf("incoming store request: %s", req.String()))
|
||||||
// swap accounting is done within forwarding
|
// swap accounting is done within forwarding
|
||||||
self.storage.HandleStoreRequestMsg(&req, &peer{bzz: self})
|
bzz.storage.HandleStoreRequestMsg(&req, &peer{bzz: bzz})
|
||||||
|
|
||||||
case retrieveRequestMsg:
|
case retrieveRequestMsg:
|
||||||
// retrieve Requests are dispatched to netStore
|
// retrieve Requests are dispatched to netStore
|
||||||
|
|
@ -241,7 +241,7 @@ func (self *bzz) handle() error {
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
req.from = &peer{bzz: self}
|
req.from = &peer{bzz: bzz}
|
||||||
// if request is lookup and not to be delivered
|
// if request is lookup and not to be delivered
|
||||||
if req.isLookup() {
|
if req.isLookup() {
|
||||||
log.Trace(fmt.Sprintf("self lookup for %v: responding with peers only...", req.from))
|
log.Trace(fmt.Sprintf("self lookup for %v: responding with peers only...", req.from))
|
||||||
|
|
@ -249,10 +249,10 @@ func (self *bzz) handle() error {
|
||||||
return fmt.Errorf("protocol handler: req.Key == nil || req.Timeout == nil")
|
return fmt.Errorf("protocol handler: req.Key == nil || req.Timeout == nil")
|
||||||
} else {
|
} else {
|
||||||
// swap accounting is done within netStore
|
// swap accounting is done within netStore
|
||||||
self.storage.HandleRetrieveRequestMsg(&req, &peer{bzz: self})
|
bzz.storage.HandleRetrieveRequestMsg(&req, &peer{bzz: bzz})
|
||||||
}
|
}
|
||||||
// direct response with peers, TODO: sort this out
|
// direct response with peers, TODO: sort this out
|
||||||
self.hive.peers(&req)
|
bzz.hive.peers(&req)
|
||||||
|
|
||||||
case peersMsg:
|
case peersMsg:
|
||||||
// response to lookups and immediate response to retrieve requests
|
// response to lookups and immediate response to retrieve requests
|
||||||
|
|
@ -262,9 +262,9 @@ func (self *bzz) handle() error {
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
req.from = &peer{bzz: self}
|
req.from = &peer{bzz: bzz}
|
||||||
log.Trace(fmt.Sprintf("<- peer addresses: %v", req))
|
log.Trace(fmt.Sprintf("<- peer addresses: %v", req))
|
||||||
self.hive.HandlePeersMsg(&req, &peer{bzz: self})
|
bzz.hive.HandlePeersMsg(&req, &peer{bzz: bzz})
|
||||||
|
|
||||||
case syncRequestMsg:
|
case syncRequestMsg:
|
||||||
syncRequestMsgCounter.Inc(1)
|
syncRequestMsgCounter.Inc(1)
|
||||||
|
|
@ -273,8 +273,8 @@ func (self *bzz) handle() error {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("<- sync request: %v", req))
|
log.Debug(fmt.Sprintf("<- sync request: %v", req))
|
||||||
self.lastActive = time.Now()
|
bzz.lastActive = time.Now()
|
||||||
self.sync(req.SyncState)
|
bzz.sync(req.SyncState)
|
||||||
|
|
||||||
case unsyncedKeysMsg:
|
case unsyncedKeysMsg:
|
||||||
// coming from parent node offering
|
// coming from parent node offering
|
||||||
|
|
@ -284,8 +284,8 @@ func (self *bzz) handle() error {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("<- unsynced keys : %s", req.String()))
|
log.Debug(fmt.Sprintf("<- unsynced keys : %s", req.String()))
|
||||||
err := self.storage.HandleUnsyncedKeysMsg(&req, &peer{bzz: self})
|
err := bzz.storage.HandleUnsyncedKeysMsg(&req, &peer{bzz: bzz})
|
||||||
self.lastActive = time.Now()
|
bzz.lastActive = time.Now()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
|
|
@ -299,8 +299,8 @@ func (self *bzz) handle() error {
|
||||||
return fmt.Errorf("<-msg %v: %v", msg, err)
|
return fmt.Errorf("<-msg %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("<- delivery request: %s", req.String()))
|
log.Debug(fmt.Sprintf("<- delivery request: %s", req.String()))
|
||||||
err := self.storage.HandleDeliveryRequestMsg(&req, &peer{bzz: self})
|
err := bzz.storage.HandleDeliveryRequestMsg(&req, &peer{bzz: bzz})
|
||||||
self.lastActive = time.Now()
|
bzz.lastActive = time.Now()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
|
|
@ -308,13 +308,13 @@ func (self *bzz) handle() error {
|
||||||
case paymentMsg:
|
case paymentMsg:
|
||||||
// swap protocol message for payment, Units paid for, Cheque paid with
|
// swap protocol message for payment, Units paid for, Cheque paid with
|
||||||
paymentMsgCounter.Inc(1)
|
paymentMsgCounter.Inc(1)
|
||||||
if self.swapEnabled {
|
if bzz.swapEnabled {
|
||||||
var req paymentMsgData
|
var req paymentMsgData
|
||||||
if err := msg.Decode(&req); err != nil {
|
if err := msg.Decode(&req); err != nil {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("<- payment: %s", req.String()))
|
log.Debug(fmt.Sprintf("<- payment: %s", req.String()))
|
||||||
self.swap.Receive(int(req.Units), req.Promise)
|
bzz.swap.Receive(int(req.Units), req.Promise)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
@ -325,27 +325,27 @@ func (self *bzz) handle() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *bzz) handleStatus() (err error) {
|
func (bzz *bzz) handleStatus() (err error) {
|
||||||
|
|
||||||
handshake := &statusMsgData{
|
handshake := &statusMsgData{
|
||||||
Version: uint64(Version),
|
Version: uint64(Version),
|
||||||
ID: "honey",
|
ID: "honey",
|
||||||
Addr: self.selfAddr(),
|
Addr: bzz.selfAddr(),
|
||||||
NetworkId: self.NetworkId,
|
NetworkId: bzz.NetworkId,
|
||||||
Swap: &bzzswap.SwapProfile{
|
Swap: &bzzswap.SwapProfile{
|
||||||
Profile: self.swapParams.Profile,
|
Profile: bzz.swapParams.Profile,
|
||||||
PayProfile: self.swapParams.PayProfile,
|
PayProfile: bzz.swapParams.PayProfile,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p2p.Send(self.rw, statusMsg, handshake)
|
err = p2p.Send(bzz.rw, statusMsg, handshake)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// read and handle remote status
|
// read and handle remote status
|
||||||
var msg p2p.Msg
|
var msg p2p.Msg
|
||||||
msg, err = self.rw.ReadMsg()
|
msg, err = bzz.rw.ReadMsg()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -365,52 +365,52 @@ func (self *bzz) handleStatus() (err error) {
|
||||||
return fmt.Errorf("<- %v: %v", msg, err)
|
return fmt.Errorf("<- %v: %v", msg, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if status.NetworkId != self.NetworkId {
|
if status.NetworkId != bzz.NetworkId {
|
||||||
return fmt.Errorf("network id mismatch: %d (!= %d)", status.NetworkId, self.NetworkId)
|
return fmt.Errorf("network id mismatch: %d (!= %d)", status.NetworkId, bzz.NetworkId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if Version != status.Version {
|
if Version != status.Version {
|
||||||
return fmt.Errorf("protocol version mismatch: %d (!= %d)", status.Version, Version)
|
return fmt.Errorf("protocol version mismatch: %d (!= %d)", status.Version, Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.remoteAddr = self.peerAddr(status.Addr)
|
bzz.remoteAddr = bzz.peerAddr(status.Addr)
|
||||||
log.Trace(fmt.Sprintf("self: advertised IP: %v, peer advertised: %v, local address: %v\npeer: advertised IP: %v, remote address: %v\n", self.selfAddr(), self.remoteAddr, self.peer.LocalAddr(), status.Addr.IP, self.peer.RemoteAddr()))
|
log.Trace(fmt.Sprintf("bzz: advertised IP: %v, peer advertised: %v, local address: %v\npeer: advertised IP: %v, remote address: %v\n", bzz.selfAddr(), bzz.remoteAddr, bzz.peer.LocalAddr(), status.Addr.IP, bzz.peer.RemoteAddr()))
|
||||||
|
|
||||||
if self.swapEnabled {
|
if bzz.swapEnabled {
|
||||||
// set remote profile for accounting
|
// set remote profile for accounting
|
||||||
self.swap, err = bzzswap.NewSwap(self.swapParams, status.Swap, self.backend, self)
|
bzz.swap, err = bzzswap.NewSwap(bzz.swapParams, status.Swap, bzz.backend, bzz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info(fmt.Sprintf("Peer %08x is capable (%d/%d)", self.remoteAddr.Addr[:4], status.Version, status.NetworkId))
|
log.Info(fmt.Sprintf("Peer %08x is capable (%d/%d)", bzz.remoteAddr.Addr[:4], status.Version, status.NetworkId))
|
||||||
err = self.hive.addPeer(&peer{bzz: self})
|
err = bzz.hive.addPeer(&peer{bzz: bzz})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// hive sets syncstate so sync should start after node added
|
// hive sets syncstate so sync should start after node added
|
||||||
log.Info(fmt.Sprintf("syncronisation request sent with %v", self.syncState))
|
log.Info(fmt.Sprintf("syncronisation request sent with %v", bzz.syncState))
|
||||||
self.syncRequest()
|
bzz.syncRequest()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *bzz) sync(state *syncState) error {
|
func (bzz *bzz) sync(state *syncState) error {
|
||||||
// syncer setup
|
// syncer setup
|
||||||
if self.syncer != nil {
|
if bzz.syncer != nil {
|
||||||
return errors.New("sync request can only be sent once")
|
return errors.New("sync request can only be sent once")
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt := self.dbAccess.counter()
|
cnt := bzz.dbAccess.counter()
|
||||||
remoteaddr := self.remoteAddr.Addr
|
remoteaddr := bzz.remoteAddr.Addr
|
||||||
start, stop := self.hive.kad.KeyRange(remoteaddr)
|
start, stop := bzz.hive.kad.KeyRange(remoteaddr)
|
||||||
|
|
||||||
// an explicitly received nil syncstate disables syncronisation
|
// an explicitly received nil syncstate disables syncronisation
|
||||||
if state == nil {
|
if state == nil {
|
||||||
self.syncEnabled = false
|
bzz.syncEnabled = false
|
||||||
log.Warn(fmt.Sprintf("syncronisation disabled for peer %v", self))
|
log.Warn(fmt.Sprintf("syncronisation disabled for peer %v", bzz))
|
||||||
state = &syncState{DbSyncState: &storage.DbSyncState{}, Synced: true}
|
state = &syncState{DbSyncState: &storage.DbSyncState{}, Synced: true}
|
||||||
} else {
|
} else {
|
||||||
state.synced = make(chan bool)
|
state.synced = make(chan bool)
|
||||||
|
|
@ -419,31 +419,31 @@ func (self *bzz) sync(state *syncState) error {
|
||||||
state.Start = storage.Key(start[:])
|
state.Start = storage.Key(start[:])
|
||||||
state.Stop = storage.Key(stop[:])
|
state.Stop = storage.Key(stop[:])
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("syncronisation requested by peer %v at state %v", self, state))
|
log.Debug(fmt.Sprintf("syncronisation requested by peer %v at state %v", bzz, state))
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
self.syncer, err = newSyncer(
|
bzz.syncer, err = newSyncer(
|
||||||
self.requestDb,
|
bzz.requestDb,
|
||||||
storage.Key(remoteaddr[:]),
|
storage.Key(remoteaddr[:]),
|
||||||
self.dbAccess,
|
bzz.dbAccess,
|
||||||
self.unsyncedKeys, self.store,
|
bzz.unsyncedKeys, bzz.store,
|
||||||
self.syncParams, state, func() bool { return self.syncEnabled },
|
bzz.syncParams, state, func() bool { return bzz.syncEnabled },
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("syncer set for peer %v", self))
|
log.Trace(fmt.Sprintf("syncer set for peer %v", bzz))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *bzz) String() string {
|
func (bzz *bzz) String() string {
|
||||||
return self.remoteAddr.String()
|
return bzz.remoteAddr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// repair reported address if IP missing
|
// repair reported address if IP missing
|
||||||
func (self *bzz) peerAddr(base *peerAddr) *peerAddr {
|
func (bzz *bzz) peerAddr(base *peerAddr) *peerAddr {
|
||||||
if base.IP.IsUnspecified() {
|
if base.IP.IsUnspecified() {
|
||||||
host, _, _ := net.SplitHostPort(self.peer.RemoteAddr().String())
|
host, _, _ := net.SplitHostPort(bzz.peer.RemoteAddr().String())
|
||||||
base.IP = net.ParseIP(host)
|
base.IP = net.ParseIP(host)
|
||||||
}
|
}
|
||||||
return base
|
return base
|
||||||
|
|
@ -452,12 +452,12 @@ func (self *bzz) peerAddr(base *peerAddr) *peerAddr {
|
||||||
// returns self advertised node connection info (listening address w enodes)
|
// returns self advertised node connection info (listening address w enodes)
|
||||||
// IP will get repaired on the other end if missing
|
// IP will get repaired on the other end if missing
|
||||||
// or resolved via ID by discovery at dialout
|
// or resolved via ID by discovery at dialout
|
||||||
func (self *bzz) selfAddr() *peerAddr {
|
func (bzz *bzz) selfAddr() *peerAddr {
|
||||||
id := self.hive.id
|
id := bzz.hive.id
|
||||||
host, port, _ := net.SplitHostPort(self.hive.listenAddr())
|
host, port, _ := net.SplitHostPort(bzz.hive.listenAddr())
|
||||||
intport, _ := strconv.Atoi(port)
|
intport, _ := strconv.Atoi(port)
|
||||||
addr := &peerAddr{
|
addr := &peerAddr{
|
||||||
Addr: self.hive.addr,
|
Addr: bzz.hive.addr,
|
||||||
ID: id[:],
|
ID: id[:],
|
||||||
IP: net.ParseIP(host),
|
IP: net.ParseIP(host),
|
||||||
Port: uint16(intport),
|
Port: uint16(intport),
|
||||||
|
|
@ -467,68 +467,68 @@ func (self *bzz) selfAddr() *peerAddr {
|
||||||
|
|
||||||
// outgoing messages
|
// outgoing messages
|
||||||
// send retrieveRequestMsg
|
// send retrieveRequestMsg
|
||||||
func (self *bzz) retrieve(req *retrieveRequestMsgData) error {
|
func (bzz *bzz) retrieve(req *retrieveRequestMsgData) error {
|
||||||
return self.send(retrieveRequestMsg, req)
|
return bzz.send(retrieveRequestMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send storeRequestMsg
|
// send storeRequestMsg
|
||||||
func (self *bzz) store(req *storeRequestMsgData) error {
|
func (bzz *bzz) store(req *storeRequestMsgData) error {
|
||||||
return self.send(storeRequestMsg, req)
|
return bzz.send(storeRequestMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *bzz) syncRequest() error {
|
func (bzz *bzz) syncRequest() error {
|
||||||
req := &syncRequestMsgData{}
|
req := &syncRequestMsgData{}
|
||||||
if self.hive.syncEnabled {
|
if bzz.hive.syncEnabled {
|
||||||
log.Debug(fmt.Sprintf("syncronisation request to peer %v at state %v", self, self.syncState))
|
log.Debug(fmt.Sprintf("syncronisation request to peer %v at state %v", bzz, bzz.syncState))
|
||||||
req.SyncState = self.syncState
|
req.SyncState = bzz.syncState
|
||||||
}
|
}
|
||||||
if self.syncState == nil {
|
if bzz.syncState == nil {
|
||||||
log.Warn(fmt.Sprintf("syncronisation disabled for peer %v at state %v", self, self.syncState))
|
log.Warn(fmt.Sprintf("syncronisation disabled for peer %v at state %v", bzz, bzz.syncState))
|
||||||
}
|
}
|
||||||
return self.send(syncRequestMsg, req)
|
return bzz.send(syncRequestMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// queue storeRequestMsg in request db
|
// queue storeRequestMsg in request db
|
||||||
func (self *bzz) deliveryRequest(reqs []*syncRequest) error {
|
func (bzz *bzz) deliveryRequest(reqs []*syncRequest) error {
|
||||||
req := &deliveryRequestMsgData{
|
req := &deliveryRequestMsgData{
|
||||||
Deliver: reqs,
|
Deliver: reqs,
|
||||||
}
|
}
|
||||||
return self.send(deliveryRequestMsg, req)
|
return bzz.send(deliveryRequestMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// batch of syncRequests to send off
|
// batch of syncRequests to send off
|
||||||
func (self *bzz) unsyncedKeys(reqs []*syncRequest, state *syncState) error {
|
func (bzz *bzz) unsyncedKeys(reqs []*syncRequest, state *syncState) error {
|
||||||
req := &unsyncedKeysMsgData{
|
req := &unsyncedKeysMsgData{
|
||||||
Unsynced: reqs,
|
Unsynced: reqs,
|
||||||
State: state,
|
State: state,
|
||||||
}
|
}
|
||||||
return self.send(unsyncedKeysMsg, req)
|
return bzz.send(unsyncedKeysMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send paymentMsg
|
// send paymentMsg
|
||||||
func (self *bzz) Pay(units int, promise swap.Promise) {
|
func (bzz *bzz) Pay(units int, promise swap.Promise) {
|
||||||
req := &paymentMsgData{uint(units), promise.(*chequebook.Cheque)}
|
req := &paymentMsgData{uint(units), promise.(*chequebook.Cheque)}
|
||||||
self.payment(req)
|
bzz.payment(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// send paymentMsg
|
// send paymentMsg
|
||||||
func (self *bzz) payment(req *paymentMsgData) error {
|
func (bzz *bzz) payment(req *paymentMsgData) error {
|
||||||
return self.send(paymentMsg, req)
|
return bzz.send(paymentMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sends peersMsg
|
// sends peersMsg
|
||||||
func (self *bzz) peers(req *peersMsgData) error {
|
func (bzz *bzz) peers(req *peersMsgData) error {
|
||||||
return self.send(peersMsg, req)
|
return bzz.send(peersMsg, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *bzz) send(msg uint64, data interface{}) error {
|
func (bzz *bzz) send(msg uint64, data interface{}) error {
|
||||||
if self.hive.blockWrite {
|
if bzz.hive.blockWrite {
|
||||||
return fmt.Errorf("network write blocked")
|
return fmt.Errorf("network write blocked")
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("-> %v: %v (%T) to %v", msg, data, data, self))
|
log.Trace(fmt.Sprintf("-> %v: %v (%T) to %v", msg, data, data, bzz))
|
||||||
err := p2p.Send(self.rw, msg, data)
|
err := p2p.Send(bzz.rw, msg, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Drop()
|
bzz.Drop()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ It is automatically started when syncdb is initialised.
|
||||||
|
|
||||||
It saves the buffer to db upon receiving quit signal. syncDb#stop()
|
It saves the buffer to db upon receiving quit signal. syncDb#stop()
|
||||||
*/
|
*/
|
||||||
func (self *syncDb) bufferRead(deliver func(interface{}, chan bool) bool) {
|
func (db *syncDb) bufferRead(deliver func(interface{}, chan bool) bool) {
|
||||||
var buffer, db chan interface{} // channels representing the two read modes
|
var buffer, db chan interface{} // channels representing the two read modes
|
||||||
var more bool
|
var more bool
|
||||||
var req interface{}
|
var req interface{}
|
||||||
|
|
@ -116,18 +116,18 @@ func (self *syncDb) bufferRead(deliver func(interface{}, chan bool) bool) {
|
||||||
var inBatch, inDb int
|
var inBatch, inDb int
|
||||||
batch := new(leveldb.Batch)
|
batch := new(leveldb.Batch)
|
||||||
var dbSize chan int
|
var dbSize chan int
|
||||||
quit := self.quit
|
quit := db.quit
|
||||||
counterValue := make([]byte, 8)
|
counterValue := make([]byte, 8)
|
||||||
|
|
||||||
// counter is used for keeping the items in order, persisted to db
|
// counter is used for keeping the items in order, persisted to db
|
||||||
// start counter where db was at, 0 if not found
|
// start counter where db was at, 0 if not found
|
||||||
data, err := self.db.Get(self.counterKey)
|
data, err := db.db.Get(db.counterKey)
|
||||||
var counter uint64
|
var counter uint64
|
||||||
if err == nil {
|
if err == nil {
|
||||||
counter = binary.BigEndian.Uint64(data)
|
counter = binary.BigEndian.Uint64(data)
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter read from db at %v", self.key.Log(), self.priority, counter))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter read from db at %v", db.key.Log(), db.priority, counter))
|
||||||
} else {
|
} else {
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter starts at %v", self.key.Log(), self.priority, counter))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] - counter starts at %v", db.key.Log(), db.priority, counter))
|
||||||
}
|
}
|
||||||
|
|
||||||
LOOP:
|
LOOP:
|
||||||
|
|
@ -139,26 +139,26 @@ LOOP:
|
||||||
// deliver request : this is blocking on network write so
|
// deliver request : this is blocking on network write so
|
||||||
// it is passed the quit channel as argument, so that it returns
|
// it is passed the quit channel as argument, so that it returns
|
||||||
// if syncdb is stopped. In this case we need to save the item to the db
|
// if syncdb is stopped. In this case we need to save the item to the db
|
||||||
more = deliver(req, self.quit)
|
more = deliver(req, db.quit)
|
||||||
if !more {
|
if !more {
|
||||||
log.Debug(fmt.Sprintf("syncDb[%v/%v] quit: switching to db. session tally (db/total): %v/%v", self.key.Log(), self.priority, self.dbTotal, self.total))
|
log.Debug(fmt.Sprintf("syncDb[%v/%v] quit: switching to db. session tally (db/total): %v/%v", db.key.Log(), db.priority, db.dbTotal, db.total))
|
||||||
// received quit signal, save request currently waiting delivery
|
// received quit signal, save request currently waiting delivery
|
||||||
// by switching to db mode and closing the buffer
|
// by switching to db mode and closing the buffer
|
||||||
buffer = nil
|
buffer = nil
|
||||||
db = self.buffer
|
db = db.buffer
|
||||||
close(db)
|
close(db)
|
||||||
quit = nil // needs to block the quit case in select
|
quit = nil // needs to block the quit case in select
|
||||||
break // break from select, this item will be written to the db
|
break // break from select, this item will be written to the db
|
||||||
}
|
}
|
||||||
self.total++
|
db.total++
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] deliver (db/total): %v/%v", self.key.Log(), self.priority, self.dbTotal, self.total))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] deliver (db/total): %v/%v", db.key.Log(), db.priority, db.dbTotal, db.total))
|
||||||
// by the time deliver returns, there were new writes to the buffer
|
// by the time deliver returns, there were new writes to the buffer
|
||||||
// if buffer contention is detected, switch to db mode which drains
|
// if buffer contention is detected, switch to db mode which drains
|
||||||
// the buffer so no process will block on pushing store requests
|
// the buffer so no process will block on pushing store requests
|
||||||
if len(buffer) == cap(buffer) {
|
if len(buffer) == cap(buffer) {
|
||||||
log.Debug(fmt.Sprintf("syncDb[%v/%v] buffer full %v: switching to db. session tally (db/total): %v/%v", self.key.Log(), self.priority, cap(buffer), self.dbTotal, self.total))
|
log.Debug(fmt.Sprintf("syncDb[%v/%v] buffer full %v: switching to db. session tally (db/total): %v/%v", db.key.Log(), db.priority, cap(buffer), db.dbTotal, db.total))
|
||||||
buffer = nil
|
buffer = nil
|
||||||
db = self.buffer
|
db = db.buffer
|
||||||
}
|
}
|
||||||
continue LOOP
|
continue LOOP
|
||||||
|
|
||||||
|
|
@ -167,30 +167,30 @@ LOOP:
|
||||||
if !more {
|
if !more {
|
||||||
// only if quit is called, saved all the buffer
|
// only if quit is called, saved all the buffer
|
||||||
binary.BigEndian.PutUint64(counterValue, counter)
|
binary.BigEndian.PutUint64(counterValue, counter)
|
||||||
batch.Put(self.counterKey, counterValue) // persist counter in batch
|
batch.Put(db.counterKey, counterValue) // persist counter in batch
|
||||||
self.writeSyncBatch(batch) // save batch
|
db.writeSyncBatch(batch) // save batch
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save current batch to db", self.key.Log(), self.priority))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save current batch to db", db.key.Log(), db.priority))
|
||||||
break LOOP
|
break LOOP
|
||||||
}
|
}
|
||||||
self.dbTotal++
|
db.dbTotal++
|
||||||
self.total++
|
db.total++
|
||||||
// otherwise break after select
|
// otherwise break after select
|
||||||
case dbSize = <-self.batch:
|
case dbSize = <-db.batch:
|
||||||
// explicit request for batch
|
// explicit request for batch
|
||||||
if inBatch == 0 && quit != nil {
|
if inBatch == 0 && quit != nil {
|
||||||
// there was no writes since the last batch so db depleted
|
// there was no writes since the last batch so db depleted
|
||||||
// switch to buffer mode
|
// switch to buffer mode
|
||||||
log.Debug(fmt.Sprintf("syncDb[%v/%v] empty db: switching to buffer", self.key.Log(), self.priority))
|
log.Debug(fmt.Sprintf("syncDb[%v/%v] empty db: switching to buffer", db.key.Log(), db.priority))
|
||||||
db = nil
|
db = nil
|
||||||
buffer = self.buffer
|
buffer = db.buffer
|
||||||
dbSize <- 0 // indicates to 'caller' that batch has been written
|
dbSize <- 0 // indicates to 'caller' that batch has been written
|
||||||
inDb = 0
|
inDb = 0
|
||||||
continue LOOP
|
continue LOOP
|
||||||
}
|
}
|
||||||
binary.BigEndian.PutUint64(counterValue, counter)
|
binary.BigEndian.PutUint64(counterValue, counter)
|
||||||
batch.Put(self.counterKey, counterValue)
|
batch.Put(db.counterKey, counterValue)
|
||||||
log.Debug(fmt.Sprintf("syncDb[%v/%v] write batch %v/%v - %x - %x", self.key.Log(), self.priority, inBatch, counter, self.counterKey, counterValue))
|
log.Debug(fmt.Sprintf("syncDb[%v/%v] write batch %v/%v - %x - %x", db.key.Log(), db.priority, inBatch, counter, db.counterKey, counterValue))
|
||||||
batch = self.writeSyncBatch(batch)
|
batch = db.writeSyncBatch(batch)
|
||||||
dbSize <- inBatch // indicates to 'caller' that batch has been written
|
dbSize <- inBatch // indicates to 'caller' that batch has been written
|
||||||
inBatch = 0
|
inBatch = 0
|
||||||
continue LOOP
|
continue LOOP
|
||||||
|
|
@ -198,45 +198,45 @@ LOOP:
|
||||||
// closing syncDb#quit channel is used to signal to all goroutines to quit
|
// closing syncDb#quit channel is used to signal to all goroutines to quit
|
||||||
case <-quit:
|
case <-quit:
|
||||||
// need to save backlog, so switch to db mode
|
// need to save backlog, so switch to db mode
|
||||||
db = self.buffer
|
db = db.buffer
|
||||||
buffer = nil
|
buffer = nil
|
||||||
quit = nil
|
quit = nil
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save buffer to db", self.key.Log(), self.priority))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] quitting: save buffer to db", db.key.Log(), db.priority))
|
||||||
close(db)
|
close(db)
|
||||||
continue LOOP
|
continue LOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
// only get here if we put req into db
|
// only get here if we put req into db
|
||||||
entry, err = self.newSyncDbEntry(req, counter)
|
entry, err = db.newSyncDbEntry(req, counter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("syncDb[%v/%v] saving request %v (#%v/%v) failed: %v", self.key.Log(), self.priority, req, inBatch, inDb, err))
|
log.Warn(fmt.Sprintf("syncDb[%v/%v] saving request %v (#%v/%v) failed: %v", db.key.Log(), db.priority, req, inBatch, inDb, err))
|
||||||
continue LOOP
|
continue LOOP
|
||||||
}
|
}
|
||||||
batch.Put(entry.key, entry.val)
|
batch.Put(entry.key, entry.val)
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] to batch %v '%v' (#%v/%v/%v)", self.key.Log(), self.priority, req, entry, inBatch, inDb, counter))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] to batch %v '%v' (#%v/%v/%v)", db.key.Log(), db.priority, req, entry, inBatch, inDb, counter))
|
||||||
// if just switched to db mode and not quitting, then launch dbRead
|
// if just switched to db mode and not quitting, then launch dbRead
|
||||||
// in a parallel go routine to send deliveries from db
|
// in a parallel go routine to send deliveries from db
|
||||||
if inDb == 0 && quit != nil {
|
if inDb == 0 && quit != nil {
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] start dbRead", self.key.Log(), self.priority))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] start dbRead", db.key.Log(), db.priority))
|
||||||
go self.dbRead(true, counter, deliver)
|
go db.dbRead(true, counter, deliver)
|
||||||
}
|
}
|
||||||
inDb++
|
inDb++
|
||||||
inBatch++
|
inBatch++
|
||||||
counter++
|
counter++
|
||||||
// need to save the batch if it gets too large (== dbBatchSize)
|
// need to save the batch if it gets too large (== dbBatchSize)
|
||||||
if inBatch%int(self.dbBatchSize) == 0 {
|
if inBatch%int(db.dbBatchSize) == 0 {
|
||||||
batch = self.writeSyncBatch(batch)
|
batch = db.writeSyncBatch(batch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("syncDb[%v:%v]: saved %v keys (saved counter at %v)", self.key.Log(), self.priority, inBatch, counter))
|
log.Info(fmt.Sprintf("syncDb[%v:%v]: saved %v keys (saved counter at %v)", db.key.Log(), db.priority, inBatch, counter))
|
||||||
close(self.done)
|
close(db.done)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writes the batch to the db and returns a new batch object
|
// writes the batch to the db and returns a new batch object
|
||||||
func (self *syncDb) writeSyncBatch(batch *leveldb.Batch) *leveldb.Batch {
|
func (db *syncDb) writeSyncBatch(batch *leveldb.Batch) *leveldb.Batch {
|
||||||
err := self.db.Write(batch)
|
err := db.db.Write(batch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("syncDb[%v/%v] saving batch to db failed: %v", self.key.Log(), self.priority, err))
|
log.Warn(fmt.Sprintf("syncDb[%v/%v] saving batch to db failed: %v", db.key.Log(), db.priority, err))
|
||||||
return batch
|
return batch
|
||||||
}
|
}
|
||||||
return new(leveldb.Batch)
|
return new(leveldb.Batch)
|
||||||
|
|
@ -247,8 +247,8 @@ type syncDbEntry struct {
|
||||||
key, val []byte
|
key, val []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self syncDbEntry) String() string {
|
func (entry syncDbEntry) String() string {
|
||||||
return fmt.Sprintf("key: %x, value: %x", self.key, self.val)
|
return fmt.Sprintf("key: %x, value: %x", entry.key, entry.val)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -272,9 +272,9 @@ dbRead needs a boolean to indicate if on first round all the historical
|
||||||
record is synced. Second argument to indicate current db counter
|
record is synced. Second argument to indicate current db counter
|
||||||
The third is the function to apply
|
The third is the function to apply
|
||||||
*/
|
*/
|
||||||
func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}, chan bool) bool) {
|
func (db *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}, chan bool) bool) {
|
||||||
key := make([]byte, 42)
|
key := make([]byte, 42)
|
||||||
copy(key, self.start)
|
copy(key, db.start)
|
||||||
binary.BigEndian.PutUint64(key[34:], counter)
|
binary.BigEndian.PutUint64(key[34:], counter)
|
||||||
var batches, n, cnt, total int
|
var batches, n, cnt, total int
|
||||||
var more bool
|
var more bool
|
||||||
|
|
@ -290,8 +290,8 @@ func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}
|
||||||
// so that loop is not blocking while delivering
|
// so that loop is not blocking while delivering
|
||||||
// only relevant if cnt is large
|
// only relevant if cnt is large
|
||||||
select {
|
select {
|
||||||
case self.batch <- batchSizes:
|
case db.batch <- batchSizes:
|
||||||
case <-self.quit:
|
case <-db.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// wait for the write to finish and get the item count in the next batch
|
// wait for the write to finish and get the item count in the next batch
|
||||||
|
|
@ -302,31 +302,31 @@ func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it = self.db.NewIterator()
|
it = db.db.NewIterator()
|
||||||
it.Seek(key)
|
it.Seek(key)
|
||||||
if !it.Valid() {
|
if !it.Valid() {
|
||||||
copy(key, self.start)
|
copy(key, db.start)
|
||||||
useBatches = true
|
useBatches = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
del = new(leveldb.Batch)
|
del = new(leveldb.Batch)
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v]: new iterator: %x (batch %v, count %v)", self.key.Log(), self.priority, key, batches, cnt))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v]: new iterator: %x (batch %v, count %v)", db.key.Log(), db.priority, key, batches, cnt))
|
||||||
|
|
||||||
for n = 0; !useBatches || n < cnt; it.Next() {
|
for n = 0; !useBatches || n < cnt; it.Next() {
|
||||||
copy(key, it.Key())
|
copy(key, it.Key())
|
||||||
if len(key) == 0 || key[0] != 0 {
|
if len(key) == 0 || key[0] != 0 {
|
||||||
copy(key, self.start)
|
copy(key, db.start)
|
||||||
useBatches = true
|
useBatches = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
val := make([]byte, 40)
|
val := make([]byte, 40)
|
||||||
copy(val, it.Value())
|
copy(val, it.Value())
|
||||||
entry = &syncDbEntry{key, val}
|
entry = &syncDbEntry{key, val}
|
||||||
// log.Trace(fmt.Sprintf("syncDb[%v/%v] - %v, batches: %v, total: %v, session total from db: %v/%v", self.key.Log(), self.priority, self.key.Log(), batches, total, self.dbTotal, self.total))
|
// log.Trace(fmt.Sprintf("syncDb[%v/%v] - %v, batches: %v, total: %v, session total from db: %v/%v", db.key.Log(), db.priority, db.key.Log(), batches, total, db.dbTotal, db.total))
|
||||||
more = fun(entry, self.quit)
|
more = fun(entry, db.quit)
|
||||||
if !more {
|
if !more {
|
||||||
// quit received when waiting to deliver entry, the entry will not be deleted
|
// quit received when waiting to deliver entry, the entry will not be deleted
|
||||||
log.Trace(fmt.Sprintf("syncDb[%v/%v] batch %v quit after %v/%v items", self.key.Log(), self.priority, batches, n, cnt))
|
log.Trace(fmt.Sprintf("syncDb[%v/%v] batch %v quit after %v/%v items", db.key.Log(), db.priority, batches, n, cnt))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// since subsequent batches of the same db session are indexed incrementally
|
// since subsequent batches of the same db session are indexed incrementally
|
||||||
|
|
@ -336,22 +336,22 @@ func (self *syncDb) dbRead(useBatches bool, counter uint64, fun func(interface{}
|
||||||
n++
|
n++
|
||||||
total++
|
total++
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("syncDb[%v/%v] - db session closed, batches: %v, total: %v, session total from db: %v/%v", self.key.Log(), self.priority, batches, total, self.dbTotal, self.total))
|
log.Debug(fmt.Sprintf("syncDb[%v/%v] - db session closed, batches: %v, total: %v, session total from db: %v/%v", db.key.Log(), db.priority, batches, total, db.dbTotal, db.total))
|
||||||
self.db.Write(del) // this could be async called only when db is idle
|
db.db.Write(del) // this could be async called only when db is idle
|
||||||
it.Release()
|
it.Release()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
func (self *syncDb) stop() {
|
func (db *syncDb) stop() {
|
||||||
close(self.quit)
|
close(db.quit)
|
||||||
<-self.done
|
<-db.done
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate a dbkey for the request, for the db to work
|
// calculate a dbkey for the request, for the db to work
|
||||||
// see syncdb for db key structure
|
// see syncdb for db key structure
|
||||||
// polimorphic: accepted types, see syncer#addRequest
|
// polimorphic: accepted types, see syncer#addRequest
|
||||||
func (self *syncDb) newSyncDbEntry(req interface{}, counter uint64) (entry *syncDbEntry, err error) {
|
func (db *syncDb) newSyncDbEntry(req interface{}, counter uint64) (entry *syncDbEntry, err error) {
|
||||||
var key storage.Key
|
var key storage.Key
|
||||||
var chunk *storage.Chunk
|
var chunk *storage.Chunk
|
||||||
var id uint64
|
var id uint64
|
||||||
|
|
@ -377,7 +377,7 @@ func (self *syncDb) newSyncDbEntry(req interface{}, counter uint64) (entry *sync
|
||||||
dbval := make([]byte, 40)
|
dbval := make([]byte, 40)
|
||||||
|
|
||||||
// encode key
|
// encode key
|
||||||
copy(dbkey[:], self.start[:34]) // db peer
|
copy(dbkey[:], db.start[:34]) // db peer
|
||||||
binary.BigEndian.PutUint64(dbkey[34:], counter)
|
binary.BigEndian.PutUint64(dbkey[34:], counter)
|
||||||
// encode value
|
// encode value
|
||||||
copy(dbval, key[:])
|
copy(dbval, key[:])
|
||||||
|
|
|
||||||
|
|
@ -71,25 +71,25 @@ func newTestSyncDb(priority, bufferSize, batchSize int, dbdir string, t *testing
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testSyncDb) close() {
|
func (db *testSyncDb) close() {
|
||||||
self.db.Close()
|
db.db.Close()
|
||||||
os.RemoveAll(self.dbdir)
|
os.RemoveAll(db.dbdir)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testSyncDb) push(n int) {
|
func (db *testSyncDb) push(n int) {
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
self.buffer <- storage.Key(crypto.Keccak256([]byte{byte(self.c)}))
|
db.buffer <- storage.Key(crypto.Keccak256([]byte{byte(db.c)}))
|
||||||
self.sent = append(self.sent, self.c)
|
db.sent = append(db.sent, db.c)
|
||||||
self.c++
|
db.c++
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("pushed %v requests", n))
|
log.Debug(fmt.Sprintf("pushed %v requests", n))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testSyncDb) draindb() {
|
func (db *testSyncDb) draindb() {
|
||||||
it := self.db.NewIterator()
|
it := db.db.NewIterator()
|
||||||
defer it.Release()
|
defer it.Release()
|
||||||
for {
|
for {
|
||||||
it.Seek(self.start)
|
it.Seek(db.start)
|
||||||
if !it.Valid() {
|
if !it.Valid() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -98,44 +98,44 @@ func (self *testSyncDb) draindb() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
it.Release()
|
it.Release()
|
||||||
it = self.db.NewIterator()
|
it = db.db.NewIterator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testSyncDb) deliver(req interface{}, quit chan bool) bool {
|
func (db *testSyncDb) deliver(req interface{}, quit chan bool) bool {
|
||||||
_, db := req.(*syncDbEntry)
|
_, db := req.(*syncDbEntry)
|
||||||
key, _, _, _, err := parseRequest(req)
|
key, _, _, _, err := parseRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.t.Fatalf("unexpected error of key %v: %v", key, err)
|
db.t.Fatalf("unexpected error of key %v: %v", key, err)
|
||||||
}
|
}
|
||||||
self.delivered = append(self.delivered, key)
|
db.delivered = append(db.delivered, key)
|
||||||
select {
|
select {
|
||||||
case self.fromDb <- db:
|
case db.fromDb <- db:
|
||||||
return true
|
return true
|
||||||
case <-quit:
|
case <-quit:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testSyncDb) expect(n int, db bool) {
|
func (db *testSyncDb) expect(n int, db bool) {
|
||||||
var ok bool
|
var ok bool
|
||||||
// for n items
|
// for n items
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
ok = <-self.fromDb
|
ok = <-db.fromDb
|
||||||
if self.at+1 > len(self.delivered) {
|
if db.at+1 > len(db.delivered) {
|
||||||
self.t.Fatalf("expected %v, got %v", self.at+1, len(self.delivered))
|
db.t.Fatalf("expected %v, got %v", db.at+1, len(db.delivered))
|
||||||
}
|
}
|
||||||
if len(self.sent) > self.at && !bytes.Equal(crypto.Keccak256([]byte{byte(self.sent[self.at])}), self.delivered[self.at]) {
|
if len(db.sent) > db.at && !bytes.Equal(crypto.Keccak256([]byte{byte(db.sent[db.at])}), db.delivered[db.at]) {
|
||||||
self.t.Fatalf("expected delivery %v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db)
|
db.t.Fatalf("expected delivery %v/%v/%v to be hash of %v, from db: %v = %v", i, n, db.at, db.sent[db.at], ok, db)
|
||||||
log.Debug(fmt.Sprintf("%v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db))
|
log.Debug(fmt.Sprintf("%v/%v/%v to be hash of %v, from db: %v = %v", i, n, db.at, db.sent[db.at], ok, db))
|
||||||
}
|
}
|
||||||
if !ok && db {
|
if !ok && db {
|
||||||
self.t.Fatalf("expected delivery %v/%v/%v from db", i, n, self.at)
|
db.t.Fatalf("expected delivery %v/%v/%v from db", i, n, db.at)
|
||||||
}
|
}
|
||||||
if ok && !db {
|
if ok && !db {
|
||||||
self.t.Fatalf("expected delivery %v/%v/%v from cache", i, n, self.at)
|
db.t.Fatalf("expected delivery %v/%v/%v from cache", i, n, db.at)
|
||||||
}
|
}
|
||||||
self.at++
|
db.at++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,13 +77,13 @@ func NewDbAccess(loc *storage.LocalStore) *DbAccess {
|
||||||
}
|
}
|
||||||
|
|
||||||
// to obtain the chunks from key or request db entry only
|
// to obtain the chunks from key or request db entry only
|
||||||
func (self *DbAccess) get(key storage.Key) (*storage.Chunk, error) {
|
func (dba *DbAccess) get(key storage.Key) (*storage.Chunk, error) {
|
||||||
return self.loc.Get(key)
|
return dba.loc.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// current storage counter of chunk db
|
// current storage counter of chunk db
|
||||||
func (self *DbAccess) counter() uint64 {
|
func (dba *DbAccess) counter() uint64 {
|
||||||
return self.db.Counter()
|
return dba.db.Counter()
|
||||||
}
|
}
|
||||||
|
|
||||||
// implemented by dbStoreSyncIterator
|
// implemented by dbStoreSyncIterator
|
||||||
|
|
@ -92,30 +92,29 @@ type keyIterator interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generator function for iteration by address range and storage counter
|
// generator function for iteration by address range and storage counter
|
||||||
func (self *DbAccess) iterator(s *syncState) keyIterator {
|
func (dba *DbAccess) iterator(s *syncState) keyIterator {
|
||||||
it, err := self.db.NewSyncIterator(*(s.DbSyncState))
|
it, err := dba.db.NewSyncIterator(*(s.DbSyncState))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return keyIterator(it)
|
return keyIterator(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self syncState) String() string {
|
func (state syncState) String() string {
|
||||||
if self.Synced {
|
if state.Synced {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"session started at: %v, last seen at: %v, latest key: %v",
|
"session started at: %v, last seen at: %v, latest key: %v",
|
||||||
self.SessionAt, self.LastSeenAt,
|
state.SessionAt, state.LastSeenAt,
|
||||||
self.Latest.Log(),
|
state.Latest.Log(),
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"address: %v-%v, index: %v-%v, session started at: %v, last seen at: %v, latest key: %v",
|
|
||||||
self.Start.Log(), self.Stop.Log(),
|
|
||||||
self.First, self.Last,
|
|
||||||
self.SessionAt, self.LastSeenAt,
|
|
||||||
self.Latest.Log(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"address: %v-%v, index: %v-%v, session started at: %v, last seen at: %v, latest key: %v",
|
||||||
|
state.Start.Log(), state.Stop.Log(),
|
||||||
|
state.First, state.Last,
|
||||||
|
state.SessionAt, state.LastSeenAt,
|
||||||
|
state.Latest.Log(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncer parameters (global, not peer specific)
|
// syncer parameters (global, not peer specific)
|
||||||
|
|
@ -145,8 +144,8 @@ func NewDefaultSyncParams() *SyncParams {
|
||||||
|
|
||||||
//this can only finally be set after all config options (file, cmd line, env vars)
|
//this can only finally be set after all config options (file, cmd line, env vars)
|
||||||
//have been evaluated
|
//have been evaluated
|
||||||
func (self *SyncParams) Init(path string) {
|
func (params *SyncParams) Init(path string) {
|
||||||
self.RequestDbPath = filepath.Join(path, "requests")
|
params.RequestDbPath = filepath.Join(path, "requests")
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncer is the agent that manages content distribution/storage replication/chunk storeRequest forwarding
|
// syncer is the agent that manages content distribution/storage replication/chunk storeRequest forwarding
|
||||||
|
|
@ -266,21 +265,21 @@ func decodeSync(meta *json.RawMessage) (*syncState, error) {
|
||||||
|
|
||||||
sync is called from the syncer constructor and is not supposed to be used externally
|
sync is called from the syncer constructor and is not supposed to be used externally
|
||||||
*/
|
*/
|
||||||
func (self *syncer) sync() {
|
func (sync *syncer) sync() {
|
||||||
state := self.state
|
state := sync.state
|
||||||
// sync finished
|
// sync finished
|
||||||
defer close(self.syncStates)
|
defer close(sync.syncStates)
|
||||||
|
|
||||||
// 0. first replay stale requests from request db
|
// 0. first replay stale requests from request db
|
||||||
if state.SessionAt == 0 {
|
if state.SessionAt == 0 {
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: nothing to sync", self.key.Log()))
|
log.Debug(fmt.Sprintf("syncer[%v]: nothing to sync", sync.key.Log()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: start replaying stale requests from request db", self.key.Log()))
|
log.Debug(fmt.Sprintf("syncer[%v]: start replaying stale requests from request db", sync.key.Log()))
|
||||||
for p := priorities - 1; p >= 0; p-- {
|
for p := priorities - 1; p >= 0; p-- {
|
||||||
self.queues[p].dbRead(false, 0, self.replay())
|
sync.queues[p].dbRead(false, 0, sync.replay())
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: done replaying stale requests from request db", self.key.Log()))
|
log.Debug(fmt.Sprintf("syncer[%v]: done replaying stale requests from request db", sync.key.Log()))
|
||||||
|
|
||||||
// unless peer is synced sync unfinished history beginning on
|
// unless peer is synced sync unfinished history beginning on
|
||||||
if !state.Synced {
|
if !state.Synced {
|
||||||
|
|
@ -289,9 +288,9 @@ func (self *syncer) sync() {
|
||||||
if !storage.IsZeroKey(state.Latest) {
|
if !storage.IsZeroKey(state.Latest) {
|
||||||
// 1. there is unfinished earlier sync
|
// 1. there is unfinished earlier sync
|
||||||
state.Start = state.Latest
|
state.Start = state.Latest
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising backlog (unfinished sync: %v)", self.key.Log(), state))
|
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising backlog (unfinished sync: %v)", sync.key.Log(), state))
|
||||||
// blocks while the entire history upto state is synced
|
// blocks while the entire history upto state is synced
|
||||||
self.syncState(state)
|
sync.syncState(state)
|
||||||
if state.Last < state.SessionAt {
|
if state.Last < state.SessionAt {
|
||||||
state.First = state.Last + 1
|
state.First = state.Last + 1
|
||||||
}
|
}
|
||||||
|
|
@ -301,8 +300,8 @@ func (self *syncer) sync() {
|
||||||
// 2. sync up to last disconnect1
|
// 2. sync up to last disconnect1
|
||||||
if state.First < state.LastSeenAt {
|
if state.First < state.LastSeenAt {
|
||||||
state.Last = state.LastSeenAt
|
state.Last = state.LastSeenAt
|
||||||
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history upto last disconnect at %v: %v", self.key.Log(), state.LastSeenAt, state))
|
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history upto last disconnect at %v: %v", sync.key.Log(), state.LastSeenAt, state))
|
||||||
self.syncState(state)
|
sync.syncState(state)
|
||||||
state.First = state.LastSeenAt
|
state.First = state.LastSeenAt
|
||||||
}
|
}
|
||||||
state.Latest = storage.ZeroKey
|
state.Latest = storage.ZeroKey
|
||||||
|
|
@ -316,28 +315,28 @@ func (self *syncer) sync() {
|
||||||
// if there have been new chunks since last session
|
// if there have been new chunks since last session
|
||||||
if state.LastSeenAt < state.SessionAt {
|
if state.LastSeenAt < state.SessionAt {
|
||||||
state.Last = state.SessionAt
|
state.Last = state.SessionAt
|
||||||
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))
|
log.Debug(fmt.Sprintf("syncer[%v]: start syncronising history since last disconnect at %v up until session start at %v: %v", sync.key.Log(), state.LastSeenAt, state.SessionAt, state))
|
||||||
// blocks until state syncing is finished
|
// blocks until state syncing is finished
|
||||||
self.syncState(state)
|
sync.syncState(state)
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("syncer[%v]: syncing all history complete", self.key.Log()))
|
log.Info(fmt.Sprintf("syncer[%v]: syncing all history complete", sync.key.Log()))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait till syncronised block uptil state is synced
|
// wait till syncronised block uptil state is synced
|
||||||
func (self *syncer) syncState(state *syncState) {
|
func (sync *syncer) syncState(state *syncState) {
|
||||||
self.syncStates <- state
|
sync.syncStates <- state
|
||||||
select {
|
select {
|
||||||
case <-state.synced:
|
case <-state.synced:
|
||||||
case <-self.quit:
|
case <-sync.quit:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop quits both request processor and saves the request cache to disk
|
// stop quits both request processor and saves the request cache to disk
|
||||||
func (self *syncer) stop() {
|
func (sync *syncer) stop() {
|
||||||
close(self.quit)
|
close(sync.quit)
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: stop and save sync request db backlog", self.key.Log()))
|
log.Trace(fmt.Sprintf("syncer[%v]: stop and save sync request db backlog", sync.key.Log()))
|
||||||
for _, db := range self.queues {
|
for _, db := range sync.queues {
|
||||||
db.stop()
|
db.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -348,11 +347,11 @@ type syncRequest struct {
|
||||||
Priority uint
|
Priority uint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *syncRequest) String() string {
|
func (req *syncRequest) String() string {
|
||||||
return fmt.Sprintf("<Key: %v, Priority: %v>", self.Key.Log(), self.Priority)
|
return fmt.Sprintf("<Key: %v, Priority: %v>", req.Key.Log(), req.Priority)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *syncer) newSyncRequest(req interface{}, p int) (*syncRequest, error) {
|
func (sync *syncer) newSyncRequest(req interface{}, p int) (*syncRequest, error) {
|
||||||
key, _, _, _, err := parseRequest(req)
|
key, _, _, _, err := parseRequest(req)
|
||||||
// TODO: if req has chunk, it should be put in a cache
|
// TODO: if req has chunk, it should be put in a cache
|
||||||
// create
|
// create
|
||||||
|
|
@ -366,11 +365,11 @@ func (self *syncer) newSyncRequest(req interface{}, p int) (*syncRequest, error)
|
||||||
// * read is on demand, blocking unless history channel is read
|
// * read is on demand, blocking unless history channel is read
|
||||||
// * accepts sync requests (syncStates) to create new db iterator
|
// * accepts sync requests (syncStates) to create new db iterator
|
||||||
// * closes the channel one iteration finishes
|
// * closes the channel one iteration finishes
|
||||||
func (self *syncer) syncHistory(state *syncState) chan interface{} {
|
func (sync *syncer) syncHistory(state *syncState) chan interface{} {
|
||||||
var n uint
|
var n uint
|
||||||
history := make(chan interface{})
|
history := make(chan interface{})
|
||||||
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))
|
log.Debug(fmt.Sprintf("syncer[%v]: syncing history between %v - %v for chunk addresses %v - %v", sync.key.Log(), state.First, state.Last, state.Start, state.Stop))
|
||||||
it := self.dbAccess.iterator(state)
|
it := sync.dbAccess.iterator(state)
|
||||||
if it != nil {
|
if it != nil {
|
||||||
go func() {
|
go func() {
|
||||||
// signal end of the iteration ended
|
// signal end of the iteration ended
|
||||||
|
|
@ -385,22 +384,22 @@ func (self *syncer) syncHistory(state *syncState) chan interface{} {
|
||||||
// blocking until history channel is read from
|
// blocking until history channel is read from
|
||||||
case history <- key:
|
case history <- key:
|
||||||
n++
|
n++
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: history: %v (%v keys)", self.key.Log(), key.Log(), n))
|
log.Trace(fmt.Sprintf("syncer[%v]: history: %v (%v keys)", sync.key.Log(), key.Log(), n))
|
||||||
state.Latest = key
|
state.Latest = key
|
||||||
case <-self.quit:
|
case <-sync.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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))
|
log.Debug(fmt.Sprintf("syncer[%v]: finished syncing history between %v - %v for chunk addresses %v - %v (at %v) (chunks = %v)", sync.key.Log(), state.First, state.Last, state.Start, state.Stop, state.Latest, n))
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
return history
|
return history
|
||||||
}
|
}
|
||||||
|
|
||||||
// triggers key syncronisation
|
// triggers key syncronisation
|
||||||
func (self *syncer) sendUnsyncedKeys() {
|
func (sync *syncer) sendUnsyncedKeys() {
|
||||||
select {
|
select {
|
||||||
case self.deliveryRequest <- true:
|
case sync.deliveryRequest <- true:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -411,7 +410,7 @@ func (self *syncer) sendUnsyncedKeys() {
|
||||||
// historical data is used so historical items are lower priority within
|
// historical data is used so historical items are lower priority within
|
||||||
// their priority group.
|
// their priority group.
|
||||||
// * Order of historical data is unspecified
|
// * Order of historical data is unspecified
|
||||||
func (self *syncer) syncUnsyncedKeys() {
|
func (sync *syncer) syncUnsyncedKeys() {
|
||||||
// send out new
|
// send out new
|
||||||
var unsynced []*syncRequest
|
var unsynced []*syncRequest
|
||||||
var more, justSynced bool
|
var more, justSynced bool
|
||||||
|
|
@ -419,12 +418,12 @@ func (self *syncer) syncUnsyncedKeys() {
|
||||||
var history chan interface{}
|
var history chan interface{}
|
||||||
|
|
||||||
priority := High
|
priority := High
|
||||||
keys := self.keys[priority]
|
keys := sync.keys[priority]
|
||||||
var newUnsyncedKeys, deliveryRequest chan bool
|
var newUnsyncedKeys, deliveryRequest chan bool
|
||||||
keyCounts := make([]int, priorities)
|
keyCounts := make([]int, priorities)
|
||||||
histPrior := self.SyncPriorities[HistoryReq]
|
histPrior := sync.SyncPriorities[HistoryReq]
|
||||||
syncStates := self.syncStates
|
syncStates := sync.syncStates
|
||||||
state := self.state
|
state := sync.state
|
||||||
|
|
||||||
LOOP:
|
LOOP:
|
||||||
for {
|
for {
|
||||||
|
|
@ -440,15 +439,15 @@ LOOP:
|
||||||
PRIORITIES:
|
PRIORITIES:
|
||||||
for priority = High; priority >= 0; priority-- {
|
for priority = High; priority >= 0; priority-- {
|
||||||
// the first priority channel that is non-empty will be assigned to keys
|
// the first priority channel that is non-empty will be assigned to keys
|
||||||
if len(self.keys[priority]) > 0 {
|
if len(sync.keys[priority]) > 0 {
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: reading request with priority %v", self.key.Log(), priority))
|
log.Trace(fmt.Sprintf("syncer[%v]: reading request with priority %v", sync.key.Log(), priority))
|
||||||
keys = self.keys[priority]
|
keys = sync.keys[priority]
|
||||||
break PRIORITIES
|
break PRIORITIES
|
||||||
}
|
}
|
||||||
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])))
|
log.Trace(fmt.Sprintf("syncer[%v/%v]: queue: [%v, %v, %v]", sync.key.Log(), priority, len(sync.keys[High]), len(sync.keys[Medium]), len(sync.keys[Low])))
|
||||||
// if the input queue is empty on this level, resort to history if there is any
|
// if the input queue is empty on this level, resort to history if there is any
|
||||||
if uint(priority) == histPrior && history != nil {
|
if uint(priority) == histPrior && history != nil {
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: reading history for %v", self.key.Log(), self.key))
|
log.Trace(fmt.Sprintf("syncer[%v]: reading history for %v", sync.key.Log(), sync.key))
|
||||||
keys = history
|
keys = history
|
||||||
break PRIORITIES
|
break PRIORITIES
|
||||||
}
|
}
|
||||||
|
|
@ -458,8 +457,8 @@ LOOP:
|
||||||
// if peer ready to receive but nothing to send
|
// if peer ready to receive but nothing to send
|
||||||
if keys == nil && deliveryRequest == nil {
|
if keys == nil && deliveryRequest == nil {
|
||||||
// if no items left and switch to waiting mode
|
// if no items left and switch to waiting mode
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: buffers consumed. Waiting", self.key.Log()))
|
log.Trace(fmt.Sprintf("syncer[%v]: buffers consumed. Waiting", sync.key.Log()))
|
||||||
newUnsyncedKeys = self.newUnsyncedKeys
|
newUnsyncedKeys = sync.newUnsyncedKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
// send msg iff
|
// send msg iff
|
||||||
|
|
@ -470,48 +469,48 @@ LOOP:
|
||||||
if deliveryRequest == nil &&
|
if deliveryRequest == nil &&
|
||||||
(justSynced ||
|
(justSynced ||
|
||||||
len(unsynced) > 0 && keys == nil ||
|
len(unsynced) > 0 && keys == nil ||
|
||||||
len(unsynced) == int(self.SyncBatchSize)) {
|
len(unsynced) == int(sync.SyncBatchSize)) {
|
||||||
justSynced = false
|
justSynced = false
|
||||||
// listen to requests
|
// listen to requests
|
||||||
deliveryRequest = self.deliveryRequest
|
deliveryRequest = sync.deliveryRequest
|
||||||
newUnsyncedKeys = nil // not care about data until next req comes in
|
newUnsyncedKeys = nil // not care about data until next req comes in
|
||||||
// set sync to current counter
|
// set sync to current counter
|
||||||
// (all nonhistorical outgoing traffic sheduled and persisted
|
// (all nonhistorical outgoing traffic sheduled and persisted
|
||||||
state.LastSeenAt = self.dbAccess.counter()
|
state.LastSeenAt = sync.dbAccess.counter()
|
||||||
state.Latest = storage.ZeroKey
|
state.Latest = storage.ZeroKey
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: sending %v", self.key.Log(), unsynced))
|
log.Trace(fmt.Sprintf("syncer[%v]: sending %v", sync.key.Log(), unsynced))
|
||||||
// send the unsynced keys
|
// send the unsynced keyssync
|
||||||
stateCopy := *state
|
stateCopy := *state
|
||||||
err := self.unsyncedKeys(unsynced, &stateCopy)
|
err := sync.unsyncedKeys(unsynced, &stateCopy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("syncer[%v]: unable to send unsynced keys: %v", self.key.Log(), err))
|
log.Warn(fmt.Sprintf("syncer[%v]: unable to send unsynced keys: %v", sync.key.Log(), err))
|
||||||
}
|
}
|
||||||
self.state = state
|
sync.state = state
|
||||||
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))
|
log.Debug(fmt.Sprintf("syncer[%v]: --> %v keys sent: (total: %v (%v), history: %v), sent sync state: %v", sync.key.Log(), len(unsynced), keyCounts, keyCount, historyCnt, stateCopy))
|
||||||
unsynced = nil
|
unsynced = nil
|
||||||
keys = nil
|
keys = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// process item and add it to the batch
|
// process item and add it to the batch
|
||||||
select {
|
select {
|
||||||
case <-self.quit:
|
case <-sync.quit:
|
||||||
break LOOP
|
break LOOP
|
||||||
case req, more = <-keys:
|
case req, more = <-keys:
|
||||||
if keys == history && !more {
|
if keys == history && !more {
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: syncing history segment complete", self.key.Log()))
|
log.Trace(fmt.Sprintf("syncer[%v]: syncing history segment complete", sync.key.Log()))
|
||||||
// history channel is closed, waiting for new state (called from sync())
|
// history channel is closed, waiting for new state (called from sync())
|
||||||
syncStates = self.syncStates
|
syncStates = sync.syncStates
|
||||||
state.Synced = true // this signals that the current segment is complete
|
state.Synced = true // this signals that the current segment is complete
|
||||||
select {
|
select {
|
||||||
case state.synced <- false:
|
case state.synced <- false:
|
||||||
case <-self.quit:
|
case <-sync.quit:
|
||||||
break LOOP
|
break LOOP
|
||||||
}
|
}
|
||||||
justSynced = true
|
justSynced = true
|
||||||
history = nil
|
history = nil
|
||||||
}
|
}
|
||||||
case <-deliveryRequest:
|
case <-deliveryRequest:
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: peer ready to receive", self.key.Log()))
|
log.Trace(fmt.Sprintf("syncer[%v]: peer ready to receive", sync.key.Log()))
|
||||||
|
|
||||||
// this 1 cap channel can wake up the loop
|
// this 1 cap channel can wake up the loop
|
||||||
// signaling that peer is ready to receive unsynced Keys
|
// signaling that peer is ready to receive unsynced Keys
|
||||||
|
|
@ -519,23 +518,23 @@ LOOP:
|
||||||
deliveryRequest = nil
|
deliveryRequest = nil
|
||||||
|
|
||||||
case <-newUnsyncedKeys:
|
case <-newUnsyncedKeys:
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: new unsynced keys available", self.key.Log()))
|
log.Trace(fmt.Sprintf("syncer[%v]: new unsynced keys available", sync.key.Log()))
|
||||||
// this 1 cap channel can wake up the loop
|
// this 1 cap channel can wake up the loop
|
||||||
// signals that data is available to send if peer is ready to receive
|
// signals that data is available to send if peer is ready to receive
|
||||||
newUnsyncedKeys = nil
|
newUnsyncedKeys = nil
|
||||||
keys = self.keys[High]
|
keys = sync.keys[High]
|
||||||
|
|
||||||
case state, more = <-syncStates:
|
case state, more = <-syncStates:
|
||||||
// this resets the state
|
// this resets the state
|
||||||
if !more {
|
if !more {
|
||||||
state = self.state
|
state = sync.state
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing complete upto %v)", self.key.Log(), priority, state))
|
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing complete upto %v)", sync.key.Log(), priority, state))
|
||||||
state.Synced = true
|
state.Synced = true
|
||||||
syncStates = nil
|
syncStates = nil
|
||||||
} else {
|
} else {
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing history upto %v priority %v)", self.key.Log(), priority, state, histPrior))
|
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) syncing history upto %v priority %v)", sync.key.Log(), priority, state, histPrior))
|
||||||
state.Synced = false
|
state.Synced = false
|
||||||
history = self.syncHistory(state)
|
history = sync.syncHistory(state)
|
||||||
// only one history at a time, only allow another one once the
|
// only one history at a time, only allow another one once the
|
||||||
// history channel is closed
|
// history channel is closed
|
||||||
syncStates = nil
|
syncStates = nil
|
||||||
|
|
@ -545,19 +544,19 @@ LOOP:
|
||||||
continue LOOP
|
continue LOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) added to unsynced keys: %v", self.key.Log(), priority, req))
|
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) added to unsynced keys: %v", sync.key.Log(), priority, req))
|
||||||
keyCounts[priority]++
|
keyCounts[priority]++
|
||||||
keyCount++
|
keyCount++
|
||||||
if keys == history {
|
if keys == history {
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) history item %v (synced = %v)", self.key.Log(), priority, req, state.Synced))
|
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v) history item %v (synced = %v)", sync.key.Log(), priority, req, state.Synced))
|
||||||
historyCnt++
|
historyCnt++
|
||||||
}
|
}
|
||||||
if sreq, err := self.newSyncRequest(req, priority); err == nil {
|
if sreq, err := sync.newSyncRequest(req, priority); err == nil {
|
||||||
// extract key from req
|
// extract key from req
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v): request %v (synced = %v)", self.key.Log(), priority, req, state.Synced))
|
log.Trace(fmt.Sprintf("syncer[%v]: (priority %v): request %v (synced = %v)", sync.key.Log(), priority, req, state.Synced))
|
||||||
unsynced = append(unsynced, sreq)
|
unsynced = append(unsynced, sreq)
|
||||||
} else {
|
} else {
|
||||||
log.Warn(fmt.Sprintf("syncer[%v]: (priority %v): error creating request for %v: %v)", self.key.Log(), priority, req, err))
|
log.Warn(fmt.Sprintf("syncer[%v]: (priority %v): error creating request for %v: %v)", sync.key.Log(), priority, req, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -566,7 +565,7 @@ LOOP:
|
||||||
// delivery loop
|
// delivery loop
|
||||||
// takes into account priority, send store Requests with chunk (delivery)
|
// takes into account priority, send store Requests with chunk (delivery)
|
||||||
// idle blocking if no new deliveries in any of the queues
|
// idle blocking if no new deliveries in any of the queues
|
||||||
func (self *syncer) syncDeliveries() {
|
func (sync *syncer) syncDeliveries() {
|
||||||
var req *storeRequestMsgData
|
var req *storeRequestMsgData
|
||||||
p := High
|
p := High
|
||||||
var deliveries chan *storeRequestMsgData
|
var deliveries chan *storeRequestMsgData
|
||||||
|
|
@ -577,7 +576,7 @@ func (self *syncer) syncDeliveries() {
|
||||||
var total, success uint
|
var total, success uint
|
||||||
|
|
||||||
for {
|
for {
|
||||||
deliveries = self.deliveries[p]
|
deliveries = sync.deliveries[p]
|
||||||
select {
|
select {
|
||||||
case req = <-deliveries:
|
case req = <-deliveries:
|
||||||
n[p]++
|
n[p]++
|
||||||
|
|
@ -586,13 +585,13 @@ func (self *syncer) syncDeliveries() {
|
||||||
if p == Low {
|
if p == Low {
|
||||||
// blocking, depletion on all channels, no preference for priority
|
// blocking, depletion on all channels, no preference for priority
|
||||||
select {
|
select {
|
||||||
case req = <-self.deliveries[High]:
|
case req = <-sync.deliveries[High]:
|
||||||
n[High]++
|
n[High]++
|
||||||
case req = <-self.deliveries[Medium]:
|
case req = <-sync.deliveries[Medium]:
|
||||||
n[Medium]++
|
n[Medium]++
|
||||||
case req = <-self.deliveries[Low]:
|
case req = <-sync.deliveries[Low]:
|
||||||
n[Low]++
|
n[Low]++
|
||||||
case <-self.quit:
|
case <-sync.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p = High
|
p = High
|
||||||
|
|
@ -602,20 +601,20 @@ func (self *syncer) syncDeliveries() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
total++
|
total++
|
||||||
msg, err = self.newStoreRequestMsgData(req)
|
msg, err = sync.newStoreRequestMsgData(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("syncer[%v]: failed to create store request for %v: %v", self.key.Log(), req, err))
|
log.Warn(fmt.Sprintf("syncer[%v]: failed to create store request for %v: %v", sync.key.Log(), req, err))
|
||||||
} else {
|
} else {
|
||||||
err = self.store(msg)
|
err = sync.store(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("syncer[%v]: failed to deliver %v: %v", self.key.Log(), req, err))
|
log.Warn(fmt.Sprintf("syncer[%v]: failed to deliver %v: %v", sync.key.Log(), req, err))
|
||||||
} else {
|
} else {
|
||||||
success++
|
success++
|
||||||
log.Trace(fmt.Sprintf("syncer[%v]: %v successfully delivered", self.key.Log(), req))
|
log.Trace(fmt.Sprintf("syncer[%v]: %v successfully delivered", sync.key.Log(), req))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if total%self.SyncBatchSize == 0 {
|
if total%sync.SyncBatchSize == 0 {
|
||||||
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]))
|
log.Debug(fmt.Sprintf("syncer[%v]: deliver Total: %v, Success: %v, High: %v/%v, Medium: %v/%v, Low %v/%v", sync.key.Log(), total, success, c[High], n[High], c[Medium], n[Medium], c[Low], n[Low]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -635,28 +634,28 @@ func (self *syncer) syncDeliveries() {
|
||||||
|
|
||||||
If sync mode is off then, requests are directly sent to deliveries
|
If sync mode is off then, requests are directly sent to deliveries
|
||||||
*/
|
*/
|
||||||
func (self *syncer) addRequest(req interface{}, ty int) {
|
func (sync *syncer) addRequest(req interface{}, ty int) {
|
||||||
// retrieve priority for request type name int8
|
// retrieve priority for request type name int8
|
||||||
|
|
||||||
priority := self.SyncPriorities[ty]
|
priority := sync.SyncPriorities[ty]
|
||||||
// sync mode for this type ON
|
// sync mode for this type ON
|
||||||
if self.syncF() || ty == DeliverReq {
|
if sync.syncF() || ty == DeliverReq {
|
||||||
if self.SyncModes[ty] {
|
if sync.SyncModes[ty] {
|
||||||
self.addKey(req, priority, self.quit)
|
sync.addKey(req, priority, sync.quit)
|
||||||
} else {
|
} else {
|
||||||
self.addDelivery(req, priority, self.quit)
|
sync.addDelivery(req, priority, sync.quit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// addKey queues sync request for sync confirmation with given priority
|
// addKey queues sync request for sync confirmation with given priority
|
||||||
// ie the key will go out in an unsyncedKeys message
|
// ie the key will go out in an unsyncedKeys message
|
||||||
func (self *syncer) addKey(req interface{}, priority uint, quit chan bool) bool {
|
func (sync *syncer) addKey(req interface{}, priority uint, quit chan bool) bool {
|
||||||
select {
|
select {
|
||||||
case self.keys[priority] <- req:
|
case sync.keys[priority] <- req:
|
||||||
// this wakes up the unsynced keys loop if idle
|
// this wakes up the unsynced keys loop if idle
|
||||||
select {
|
select {
|
||||||
case self.newUnsyncedKeys <- true:
|
case sync.newUnsyncedKeys <- true:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -668,9 +667,9 @@ func (self *syncer) addKey(req interface{}, priority uint, quit chan bool) bool
|
||||||
// addDelivery queues delivery request for with given priority
|
// addDelivery queues delivery request for with given priority
|
||||||
// ie the chunk will be delivered ASAP mod priority queueing handled by syncdb
|
// ie the chunk will be delivered ASAP mod priority queueing handled by syncdb
|
||||||
// requests are persisted across sessions for correct sync
|
// requests are persisted across sessions for correct sync
|
||||||
func (self *syncer) addDelivery(req interface{}, priority uint, quit chan bool) bool {
|
func (sync *syncer) addDelivery(req interface{}, priority uint, quit chan bool) bool {
|
||||||
select {
|
select {
|
||||||
case self.queues[priority].buffer <- req:
|
case sync.queues[priority].buffer <- req:
|
||||||
return true
|
return true
|
||||||
case <-quit:
|
case <-quit:
|
||||||
return false
|
return false
|
||||||
|
|
@ -679,14 +678,14 @@ func (self *syncer) addDelivery(req interface{}, priority uint, quit chan bool)
|
||||||
|
|
||||||
// doDelivery delivers the chunk for the request with given priority
|
// doDelivery delivers the chunk for the request with given priority
|
||||||
// without queuing
|
// without queuing
|
||||||
func (self *syncer) doDelivery(req interface{}, priority uint, quit chan bool) bool {
|
func (sync *syncer) doDelivery(req interface{}, priority uint, quit chan bool) bool {
|
||||||
msgdata, err := self.newStoreRequestMsgData(req)
|
msgdata, err := sync.newStoreRequestMsgData(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("unable to deliver request %v: %v", msgdata, err))
|
log.Warn(fmt.Sprintf("unable to deliver request %v: %v", msgdata, err))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case self.deliveries[priority] <- msgdata:
|
case sync.deliveries[priority] <- msgdata:
|
||||||
return true
|
return true
|
||||||
case <-quit:
|
case <-quit:
|
||||||
return false
|
return false
|
||||||
|
|
@ -695,9 +694,9 @@ func (self *syncer) doDelivery(req interface{}, priority uint, quit chan bool) b
|
||||||
|
|
||||||
// returns the delivery function for given priority
|
// returns the delivery function for given priority
|
||||||
// passed on to syncDb
|
// passed on to syncDb
|
||||||
func (self *syncer) deliver(priority uint) func(req interface{}, quit chan bool) bool {
|
func (sync *syncer) deliver(priority uint) func(req interface{}, quit chan bool) bool {
|
||||||
return func(req interface{}, quit chan bool) bool {
|
return func(req interface{}, quit chan bool) bool {
|
||||||
return self.doDelivery(req, priority, quit)
|
return sync.doDelivery(req, priority, quit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -705,25 +704,23 @@ func (self *syncer) deliver(priority uint) func(req interface{}, quit chan bool)
|
||||||
// depending on sync mode settings for BacklogReq,
|
// depending on sync mode settings for BacklogReq,
|
||||||
// re play of request db backlog sends items via confirmation
|
// re play of request db backlog sends items via confirmation
|
||||||
// or directly delivers
|
// or directly delivers
|
||||||
func (self *syncer) replay() func(req interface{}, quit chan bool) bool {
|
func (sync *syncer) replay() func(req interface{}, quit chan bool) bool {
|
||||||
sync := self.SyncModes[BacklogReq]
|
sync := sync.SyncModes[BacklogReq]
|
||||||
priority := self.SyncPriorities[BacklogReq]
|
priority := sync.SyncPriorities[BacklogReq]
|
||||||
// sync mode for this type ON
|
// sync mode for this type ON
|
||||||
if sync {
|
if sync {
|
||||||
return func(req interface{}, quit chan bool) bool {
|
return func(req interface{}, quit chan bool) bool {
|
||||||
return self.addKey(req, priority, quit)
|
return sync.addKey(req, priority, quit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return func(req interface{}, quit chan bool) bool {
|
return func(req interface{}, quit chan bool) bool {
|
||||||
return self.doDelivery(req, priority, quit)
|
return sync.doDelivery(req, priority, quit)
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// given a request, extends it to a full storeRequestMsgData
|
// given a request, extends it to a full storeRequestMsgData
|
||||||
// polimorphic: see addRequest for the types accepted
|
// polimorphic: see addRequest for the types accepted
|
||||||
func (self *syncer) newStoreRequestMsgData(req interface{}) (*storeRequestMsgData, error) {
|
func (sync *syncer) newStoreRequestMsgData(req interface{}) (*storeRequestMsgData, error) {
|
||||||
|
|
||||||
key, id, chunk, sreq, err := parseRequest(req)
|
key, id, chunk, sreq, err := parseRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -733,7 +730,7 @@ func (self *syncer) newStoreRequestMsgData(req interface{}) (*storeRequestMsgDat
|
||||||
if sreq == nil {
|
if sreq == nil {
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
var err error
|
var err error
|
||||||
chunk, err = self.dbAccess.get(key)
|
chunk, err = sync.dbAccess.get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ type PayProfile struct {
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
//create params with default values
|
// NewDefaultSwapParams creates params with default values
|
||||||
func NewDefaultSwapParams() *SwapParams {
|
func NewDefaultSwapParams() *SwapParams {
|
||||||
return &SwapParams{
|
return &SwapParams{
|
||||||
PayProfile: &PayProfile{},
|
PayProfile: &PayProfile{},
|
||||||
|
|
@ -104,10 +104,10 @@ func NewDefaultSwapParams() *SwapParams {
|
||||||
|
|
||||||
//this can only finally be set after all config options (file, cmd line, env vars)
|
//this can only finally be set after all config options (file, cmd line, env vars)
|
||||||
//have been evaluated
|
//have been evaluated
|
||||||
func (self *SwapParams) Init(contract common.Address, prvkey *ecdsa.PrivateKey) {
|
func (params *SwapParams) Init(contract common.Address, prvkey *ecdsa.PrivateKey) {
|
||||||
pubkey := &prvkey.PublicKey
|
pubkey := &prvkey.PublicKey
|
||||||
|
|
||||||
self.PayProfile = &PayProfile{
|
params.PayProfile = &PayProfile{
|
||||||
PublicKey: common.ToHex(crypto.FromECDSAPub(pubkey)),
|
PublicKey: common.ToHex(crypto.FromECDSAPub(pubkey)),
|
||||||
Contract: contract,
|
Contract: contract,
|
||||||
Beneficiary: crypto.PubkeyToAddress(*pubkey),
|
Beneficiary: crypto.PubkeyToAddress(*pubkey),
|
||||||
|
|
@ -184,44 +184,44 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwapParams) Chequebook() *chequebook.Chequebook {
|
func (params *SwapParams) Chequebook() *chequebook.Chequebook {
|
||||||
defer self.lock.Unlock()
|
defer params.lock.Unlock()
|
||||||
self.lock.Lock()
|
params.lock.Lock()
|
||||||
return self.chbook
|
return params.chbook
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwapParams) PrivateKey() *ecdsa.PrivateKey {
|
func (params *SwapParams) PrivateKey() *ecdsa.PrivateKey {
|
||||||
return self.privateKey
|
return params.privateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (self *SwapParams) PublicKey() *ecdsa.PublicKey {
|
// func (params *SwapParams) PublicKey() *ecdsa.PublicKey {
|
||||||
// return self.publicKey
|
// return params.publicKey
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func (self *SwapParams) SetKey(prvkey *ecdsa.PrivateKey) {
|
func (params *SwapParams) SetKey(prvkey *ecdsa.PrivateKey) {
|
||||||
self.privateKey = prvkey
|
params.privateKey = prvkey
|
||||||
self.publicKey = &prvkey.PublicKey
|
params.publicKey = &prvkey.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// setChequebook(path, backend) wraps the
|
// SetChequebook wraps the
|
||||||
// chequebook initialiser and sets up autoDeposit to cover spending.
|
// chequebook initialiser and sets up autoDeposit to cover spending.
|
||||||
func (self *SwapParams) SetChequebook(ctx context.Context, backend chequebook.Backend, path string) error {
|
func (params *SwapParams) SetChequebook(ctx context.Context, backend chequebook.Backend, path string) error {
|
||||||
self.lock.Lock()
|
params.lock.Lock()
|
||||||
contract := self.Contract
|
contract := params.Contract
|
||||||
self.lock.Unlock()
|
params.lock.Unlock()
|
||||||
|
|
||||||
valid, err := chequebook.ValidateCode(ctx, backend, contract)
|
valid, err := chequebook.ValidateCode(ctx, backend, contract)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if valid {
|
} else if valid {
|
||||||
return self.newChequebookFromContract(path, backend)
|
return params.newChequebookFromContract(path, backend)
|
||||||
}
|
}
|
||||||
return self.deployChequebook(ctx, backend, path)
|
return params.deployChequebook(ctx, backend, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SwapParams) deployChequebook(ctx context.Context, backend chequebook.Backend, path string) error {
|
func (params *SwapParams) deployChequebook(ctx context.Context, backend chequebook.Backend, path string) error {
|
||||||
opts := bind.NewKeyedTransactor(self.privateKey)
|
opts := bind.NewKeyedTransactor(params.privateKey)
|
||||||
opts.Value = self.AutoDepositBuffer
|
opts.Value = params.AutoDepositBuffer
|
||||||
opts.Context = ctx
|
opts.Context = ctx
|
||||||
|
|
||||||
log.Info(fmt.Sprintf("Deploying new chequebook (owner: %v)", opts.From.Hex()))
|
log.Info(fmt.Sprintf("Deploying new chequebook (owner: %v)", opts.From.Hex()))
|
||||||
|
|
@ -233,10 +233,10 @@ func (self *SwapParams) deployChequebook(ctx context.Context, backend chequebook
|
||||||
log.Info(fmt.Sprintf("new chequebook deployed at %v (owner: %v)", contract.Hex(), opts.From.Hex()))
|
log.Info(fmt.Sprintf("new chequebook deployed at %v (owner: %v)", contract.Hex(), opts.From.Hex()))
|
||||||
|
|
||||||
// need to save config at this point
|
// need to save config at this point
|
||||||
self.lock.Lock()
|
params.lock.Lock()
|
||||||
self.Contract = contract
|
params.Contract = contract
|
||||||
err = self.newChequebookFromContract(path, backend)
|
err = params.newChequebookFromContract(path, backend)
|
||||||
self.lock.Unlock()
|
params.lock.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("error initialising cheque book (owner: %v): %v", opts.From.Hex(), err))
|
log.Warn(fmt.Sprintf("error initialising cheque book (owner: %v): %v", opts.From.Hex(), err))
|
||||||
}
|
}
|
||||||
|
|
@ -265,26 +265,26 @@ func deployChequebookLoop(opts *bind.TransactOpts, backend chequebook.Backend) (
|
||||||
|
|
||||||
// initialise the chequebook from a persisted json file or create a new one
|
// initialise the chequebook from a persisted json file or create a new one
|
||||||
// caller holds the lock
|
// caller holds the lock
|
||||||
func (self *SwapParams) newChequebookFromContract(path string, backend chequebook.Backend) error {
|
func (params *SwapParams) newChequebookFromContract(path string, backend chequebook.Backend) error {
|
||||||
hexkey := common.Bytes2Hex(self.Contract.Bytes())
|
hexkey := common.Bytes2Hex(params.Contract.Bytes())
|
||||||
err := os.MkdirAll(filepath.Join(path, "chequebooks"), os.ModePerm)
|
err := os.MkdirAll(filepath.Join(path, "chequebooks"), os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create directory for chequebooks: %v", err)
|
return fmt.Errorf("unable to create directory for chequebooks: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
chbookpath := filepath.Join(path, "chequebooks", hexkey+".json")
|
chbookpath := filepath.Join(path, "chequebooks", hexkey+".json")
|
||||||
self.chbook, err = chequebook.LoadChequebook(chbookpath, self.privateKey, backend, true)
|
params.chbook, err = chequebook.LoadChequebook(chbookpath, params.privateKey, backend, true)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.chbook, err = chequebook.NewChequebook(chbookpath, self.Contract, self.privateKey, backend)
|
params.chbook, err = chequebook.NewChequebook(chbookpath, params.Contract, params.privateKey, backend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("unable to initialise chequebook (owner: %v): %v", self.owner.Hex(), err))
|
log.Warn(fmt.Sprintf("unable to initialise chequebook (owner: %v): %v", params.owner.Hex(), err))
|
||||||
return fmt.Errorf("unable to initialise chequebook (owner: %v): %v", self.owner.Hex(), err)
|
return fmt.Errorf("unable to initialise chequebook (owner: %v): %v", params.owner.Hex(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chbook.AutoDeposit(self.AutoDepositInterval, self.AutoDepositThreshold, self.AutoDepositBuffer)
|
params.chbook.AutoDeposit(params.AutoDepositInterval, params.AutoDepositThreshold, params.AutoDepositBuffer)
|
||||||
log.Info(fmt.Sprintf("auto deposit ON for %v -> %v: interval = %v, threshold = %v, buffer = %v)", crypto.PubkeyToAddress(*(self.publicKey)).Hex()[:8], self.Contract.Hex()[:8], self.AutoDepositInterval, self.AutoDepositThreshold, self.AutoDepositBuffer))
|
log.Info(fmt.Sprintf("auto deposit ON for %v -> %v: interval = %v, threshold = %v, buffer = %v)", crypto.PubkeyToAddress(*(params.publicKey)).Hex()[:8], params.Contract.Hex()[:8], params.AutoDepositInterval, params.AutoDepositThreshold, params.AutoDepositBuffer))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ type InPayment interface {
|
||||||
Stop()
|
Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// swap is the swarm accounting protocol instance
|
// Swap is the swarm accounting protocol instance
|
||||||
// * pairwise accounting and payments
|
// * pairwise accounting and payments
|
||||||
type Swap struct {
|
type Swap struct {
|
||||||
lock sync.Mutex // mutex for balance access
|
lock sync.Mutex // mutex for balance access
|
||||||
|
|
@ -114,139 +114,139 @@ func New(local *Params, pm Payment, proto Protocol) (self *Swap, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// entry point for setting remote swap profile (e.g from handshake or other message)
|
// entry point for setting remote swap profile (e.g from handshake or other message)
|
||||||
func (self *Swap) SetRemote(remote *Profile) {
|
func (swap *Swap) SetRemote(remote *Profile) {
|
||||||
defer self.lock.Unlock()
|
defer swap.lock.Unlock()
|
||||||
self.lock.Lock()
|
swap.lock.Lock()
|
||||||
|
|
||||||
self.remote = remote
|
swap.remote = remote
|
||||||
if self.Sells && (remote.BuyAt.Sign() <= 0 || self.local.SellAt.Sign() <= 0 || remote.BuyAt.Cmp(self.local.SellAt) < 0) {
|
if swap.Sells && (remote.BuyAt.Sign() <= 0 || swap.local.SellAt.Sign() <= 0 || remote.BuyAt.Cmp(swap.local.SellAt) < 0) {
|
||||||
self.Out.Stop()
|
swap.Out.Stop()
|
||||||
self.Sells = false
|
swap.Sells = false
|
||||||
}
|
}
|
||||||
if self.Buys && (remote.SellAt.Sign() <= 0 || self.local.BuyAt.Sign() <= 0 || self.local.BuyAt.Cmp(self.remote.SellAt) < 0) {
|
if swap.Buys && (remote.SellAt.Sign() <= 0 || swap.local.BuyAt.Sign() <= 0 || swap.local.BuyAt.Cmp(swap.remote.SellAt) < 0) {
|
||||||
self.In.Stop()
|
swap.In.Stop()
|
||||||
self.Buys = false
|
swap.Buys = false
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug(fmt.Sprintf("<%v> remote profile set: pay at: %v, drop at: %v, buy at: %v, sell at: %v", self.proto, remote.PayAt, remote.DropAt, remote.BuyAt, remote.SellAt))
|
log.Debug(fmt.Sprintf("<%v> remote profile set: pay at: %v, drop at: %v, buy at: %v, sell at: %v", swap.proto, remote.PayAt, remote.DropAt, remote.BuyAt, remote.SellAt))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// to set strategy dynamically
|
// to set strategy dynamically
|
||||||
func (self *Swap) SetParams(local *Params) {
|
func (swap *Swap) SetParams(local *Params) {
|
||||||
defer self.lock.Unlock()
|
defer swap.lock.Unlock()
|
||||||
self.lock.Lock()
|
swap.lock.Lock()
|
||||||
self.local = local
|
swap.local = local
|
||||||
self.setParams(local)
|
swap.setParams(local)
|
||||||
}
|
}
|
||||||
|
|
||||||
// caller holds the lock
|
// caller holds the lock
|
||||||
|
|
||||||
func (self *Swap) setParams(local *Params) {
|
func (swap *Swap) setParams(local *Params) {
|
||||||
|
|
||||||
if self.Sells {
|
if swap.Sells {
|
||||||
self.In.AutoCash(local.AutoCashInterval, local.AutoCashThreshold)
|
swap.In.AutoCash(local.AutoCashInterval, local.AutoCashThreshold)
|
||||||
log.Info(fmt.Sprintf("<%v> set autocash to every %v, max uncashed limit: %v", self.proto, local.AutoCashInterval, local.AutoCashThreshold))
|
log.Info(fmt.Sprintf("<%v> set autocash to every %v, max uncashed limit: %v", swap.proto, local.AutoCashInterval, local.AutoCashThreshold))
|
||||||
} else {
|
} else {
|
||||||
log.Info(fmt.Sprintf("<%v> autocash off (not selling)", self.proto))
|
log.Info(fmt.Sprintf("<%v> autocash off (not selling)", swap.proto))
|
||||||
}
|
}
|
||||||
if self.Buys {
|
if swap.Buys {
|
||||||
self.Out.AutoDeposit(local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer)
|
swap.Out.AutoDeposit(local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer)
|
||||||
log.Info(fmt.Sprintf("<%v> set autodeposit to every %v, pay at: %v, buffer: %v", self.proto, local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer))
|
log.Info(fmt.Sprintf("<%v> set autodeposit to every %v, pay at: %v, buffer: %v", swap.proto, local.AutoDepositInterval, local.AutoDepositThreshold, local.AutoDepositBuffer))
|
||||||
} else {
|
} else {
|
||||||
log.Info(fmt.Sprintf("<%v> autodeposit off (not buying)", self.proto))
|
log.Info(fmt.Sprintf("<%v> autodeposit off (not buying)", swap.proto))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add(n)
|
// Add(n)
|
||||||
// n > 0 called when promised/provided n units of service
|
// n > 0 called when promised/provided n units of service
|
||||||
// n < 0 called when used/requested n units of service
|
// n < 0 called when used/requested n units of service
|
||||||
func (self *Swap) Add(n int) error {
|
func (swap *Swap) Add(n int) error {
|
||||||
defer self.lock.Unlock()
|
defer swap.lock.Unlock()
|
||||||
self.lock.Lock()
|
swap.lock.Lock()
|
||||||
self.balance += n
|
swap.balance += n
|
||||||
if !self.Sells && self.balance > 0 {
|
if !swap.Sells && swap.balance > 0 {
|
||||||
log.Trace(fmt.Sprintf("<%v> remote peer cannot have debt (balance: %v)", self.proto, self.balance))
|
log.Trace(fmt.Sprintf("<%v> remote peer cannot have debt (balance: %v)", swap.proto, swap.balance))
|
||||||
self.proto.Drop()
|
swap.proto.Drop()
|
||||||
return fmt.Errorf("[SWAP] <%v> remote peer cannot have debt (balance: %v)", self.proto, self.balance)
|
return fmt.Errorf("[SWAP] <%v> remote peer cannot have debt (balance: %v)", swap.proto, swap.balance)
|
||||||
}
|
}
|
||||||
if !self.Buys && self.balance < 0 {
|
if !swap.Buys && swap.balance < 0 {
|
||||||
log.Trace(fmt.Sprintf("<%v> we cannot have debt (balance: %v)", self.proto, self.balance))
|
log.Trace(fmt.Sprintf("<%v> we cannot have debt (balance: %v)", swap.proto, swap.balance))
|
||||||
return fmt.Errorf("[SWAP] <%v> we cannot have debt (balance: %v)", self.proto, self.balance)
|
return fmt.Errorf("[SWAP] <%v> we cannot have debt (balance: %v)", swap.proto, swap.balance)
|
||||||
}
|
}
|
||||||
if self.balance >= int(self.local.DropAt) {
|
if swap.balance >= int(swap.local.DropAt) {
|
||||||
log.Trace(fmt.Sprintf("<%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt))
|
log.Trace(fmt.Sprintf("<%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", swap.proto, swap.balance, swap.local.DropAt))
|
||||||
self.proto.Drop()
|
swap.proto.Drop()
|
||||||
return fmt.Errorf("[SWAP] <%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", self.proto, self.balance, self.local.DropAt)
|
return fmt.Errorf("[SWAP] <%v> remote peer has too much debt (balance: %v, disconnect threshold: %v)", swap.proto, swap.balance, swap.local.DropAt)
|
||||||
} else if self.balance <= -int(self.remote.PayAt) {
|
} else if swap.balance <= -int(swap.remote.PayAt) {
|
||||||
self.send()
|
swap.send()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Swap) Balance() int {
|
func (swap *Swap) Balance() int {
|
||||||
defer self.lock.Unlock()
|
defer swap.lock.Unlock()
|
||||||
self.lock.Lock()
|
swap.lock.Lock()
|
||||||
return self.balance
|
return swap.balance
|
||||||
}
|
}
|
||||||
|
|
||||||
// send(units) is called when payment is due
|
// send(units) is called when payment is due
|
||||||
// In case of insolvency no promise is issued and sent, safe against fraud
|
// In case of insolvency no promise is issued and sent, safe against fraud
|
||||||
// No return value: no error = payment is opportunistic = hang in till dropped
|
// No return value: no error = payment is opportunistic = hang in till dropped
|
||||||
func (self *Swap) send() {
|
func (swap *Swap) send() {
|
||||||
if self.local.BuyAt != nil && self.balance < 0 {
|
if swap.local.BuyAt != nil && swap.balance < 0 {
|
||||||
amount := big.NewInt(int64(-self.balance))
|
amount := big.NewInt(int64(-swap.balance))
|
||||||
amount.Mul(amount, self.remote.SellAt)
|
amount.Mul(amount, swap.remote.SellAt)
|
||||||
promise, err := self.Out.Issue(amount)
|
promise, err := swap.Out.Issue(amount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn(fmt.Sprintf("<%v> cannot issue cheque (amount: %v, channel: %v): %v", self.proto, amount, self.Out, err))
|
log.Warn(fmt.Sprintf("<%v> cannot issue cheque (amount: %v, channel: %v): %v", swap.proto, amount, swap.Out, err))
|
||||||
} else {
|
} else {
|
||||||
log.Warn(fmt.Sprintf("<%v> cheque issued (amount: %v, channel: %v)", self.proto, amount, self.Out))
|
log.Warn(fmt.Sprintf("<%v> cheque issued (amount: %v, channel: %v)", swap.proto, amount, swap.Out))
|
||||||
self.proto.Pay(-self.balance, promise)
|
swap.proto.Pay(-swap.balance, promise)
|
||||||
self.balance = 0
|
swap.balance = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// receive(units, promise) is called by the protocol when a payment msg is received
|
// receive(units, promise) is called by the protocol when a payment msg is received
|
||||||
// returns error if promise is invalid.
|
// returns error if promise is invalid.
|
||||||
func (self *Swap) Receive(units int, promise Promise) error {
|
func (swap *Swap) Receive(units int, promise Promise) error {
|
||||||
if units <= 0 {
|
if units <= 0 {
|
||||||
return fmt.Errorf("invalid units: %v <= 0", units)
|
return fmt.Errorf("invalid units: %v <= 0", units)
|
||||||
}
|
}
|
||||||
|
|
||||||
price := new(big.Int).SetInt64(int64(units))
|
price := new(big.Int).SetInt64(int64(units))
|
||||||
price.Mul(price, self.local.SellAt)
|
price.Mul(price, swap.local.SellAt)
|
||||||
|
|
||||||
amount, err := self.In.Receive(promise)
|
amount, err := swap.In.Receive(promise)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("invalid promise: %v", err)
|
err = fmt.Errorf("invalid promise: %v", err)
|
||||||
} else if price.Cmp(amount) != 0 {
|
} else if price.Cmp(amount) != 0 {
|
||||||
// verify amount = units * unit sale price
|
// verify amount = units * unit sale price
|
||||||
return fmt.Errorf("invalid amount: %v = %v * %v (units sent in msg * agreed sale unit price) != %v (signed in cheque)", price, units, self.local.SellAt, amount)
|
return fmt.Errorf("invalid amount: %v = %v * %v (units sent in msg * agreed sale unit price) != %v (signed in cheque)", price, units, swap.local.SellAt, amount)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Trace(fmt.Sprintf("<%v> invalid promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, err))
|
log.Trace(fmt.Sprintf("<%v> invalid promise (amount: %v, channel: %v): %v", swap.proto, amount, swap.In, err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// credit remote peer with units
|
// credit remote peer with units
|
||||||
self.Add(-units)
|
swap.Add(-units)
|
||||||
log.Trace(fmt.Sprintf("<%v> received promise (amount: %v, channel: %v): %v", self.proto, amount, self.In, promise))
|
log.Trace(fmt.Sprintf("<%v> received promise (amount: %v, channel: %v): %v", swap.proto, amount, swap.In, promise))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop() causes autocash loop to terminate.
|
// stop() causes autocash loop to terminate.
|
||||||
// Called after protocol handle loop terminates.
|
// Called after protocol handle loop terminates.
|
||||||
func (self *Swap) Stop() {
|
func (swap *Swap) Stop() {
|
||||||
defer self.lock.Unlock()
|
defer swap.lock.Unlock()
|
||||||
self.lock.Lock()
|
swap.lock.Lock()
|
||||||
if self.Buys {
|
if swap.Buys {
|
||||||
self.Out.Stop()
|
swap.Out.Stop()
|
||||||
}
|
}
|
||||||
if self.Sells {
|
if swap.Sells {
|
||||||
self.In.Stop()
|
swap.In.Stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,20 +34,20 @@ type testPromise struct {
|
||||||
amount *big.Int
|
amount *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testInPayment) Receive(promise Promise) (*big.Int, error) {
|
func (test *testInPayment) Receive(promise Promise) (*big.Int, error) {
|
||||||
p := promise.(*testPromise)
|
p := promise.(*testPromise)
|
||||||
self.received = append(self.received, p)
|
test.received = append(test.received, p)
|
||||||
return p.amount, nil
|
return p.amount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testInPayment) AutoCash(interval time.Duration, limit *big.Int) {
|
func (test *testInPayment) AutoCash(interval time.Duration, limit *big.Int) {
|
||||||
self.autocashInterval = interval
|
test.autocashInterval = interval
|
||||||
self.autocashLimit = limit
|
test.autocashLimit = limit
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testInPayment) Cash() (string, error) { return "", nil }
|
func (test *testInPayment) Cash() (string, error) { return "", nil }
|
||||||
|
|
||||||
func (self *testInPayment) Stop() {}
|
func (test *testInPayment) Stop() {}
|
||||||
|
|
||||||
type testOutPayment struct {
|
type testOutPayment struct {
|
||||||
deposits []*big.Int
|
deposits []*big.Int
|
||||||
|
|
@ -56,22 +56,22 @@ type testOutPayment struct {
|
||||||
autodepositBuffer *big.Int
|
autodepositBuffer *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testOutPayment) Issue(amount *big.Int) (promise Promise, err error) {
|
func (test *testOutPayment) Issue(amount *big.Int) (promise Promise, err error) {
|
||||||
return &testPromise{amount}, nil
|
return &testPromise{amount}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testOutPayment) Deposit(amount *big.Int) (string, error) {
|
func (test *testOutPayment) Deposit(amount *big.Int) (string, error) {
|
||||||
self.deposits = append(self.deposits, amount)
|
test.deposits = append(test.deposits, amount)
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testOutPayment) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
|
func (test *testOutPayment) AutoDeposit(interval time.Duration, threshold, buffer *big.Int) {
|
||||||
self.autodepositInterval = interval
|
test.autodepositInterval = interval
|
||||||
self.autodepositThreshold = threshold
|
test.autodepositThreshold = threshold
|
||||||
self.autodepositBuffer = buffer
|
test.autodepositBuffer = buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testOutPayment) Stop() {}
|
func (test *testOutPayment) Stop() {}
|
||||||
|
|
||||||
type testProtocol struct {
|
type testProtocol struct {
|
||||||
drop bool
|
drop bool
|
||||||
|
|
@ -79,18 +79,18 @@ type testProtocol struct {
|
||||||
promises []*testPromise
|
promises []*testPromise
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testProtocol) Drop() {
|
func (test *testProtocol) Drop() {
|
||||||
self.drop = true
|
test.drop = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testProtocol) String() string {
|
func (test *testProtocol) String() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *testProtocol) Pay(amount int, promise Promise) {
|
func (test *testProtocol) Pay(amount int, promise Promise) {
|
||||||
p := promise.(*testPromise)
|
p := promise.(*testPromise)
|
||||||
self.promises = append(self.promises, p)
|
test.promises = append(test.promises, p)
|
||||||
self.amounts = append(self.amounts, amount)
|
test.amounts = append(test.amounts, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSwap(t *testing.T) {
|
func TestSwap(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -91,13 +91,13 @@ func NewTreeChunker(params *ChunkerParams) (self *TreeChunker) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (self *TreeChunker) KeySize() int64 {
|
// func (tc *TreeChunker) KeySize() int64 {
|
||||||
// return self.hashSize
|
// return tc.hashSize
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// String() for pretty printing
|
// String() for pretty printing
|
||||||
func (self *Chunk) String() string {
|
func (c *Chunk) String() string {
|
||||||
return fmt.Sprintf("Key: %v TreeSize: %v Chunksize: %v", self.Key.Log(), self.Size, len(self.SData))
|
return fmt.Sprintf("Key: %v TreeSize: %v Chunksize: %v", c.Key.Log(), c.Size, len(c.SData))
|
||||||
}
|
}
|
||||||
|
|
||||||
type hashJob struct {
|
type hashJob struct {
|
||||||
|
|
@ -107,26 +107,26 @@ type hashJob struct {
|
||||||
parentWg *sync.WaitGroup
|
parentWg *sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) incrementWorkerCount() {
|
func (tc *TreeChunker) incrementWorkerCount() {
|
||||||
self.workerLock.Lock()
|
tc.workerLock.Lock()
|
||||||
defer self.workerLock.Unlock()
|
defer tc.workerLock.Unlock()
|
||||||
self.workerCount += 1
|
tc.workerCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) getWorkerCount() int64 {
|
func (tc *TreeChunker) getWorkerCount() int64 {
|
||||||
self.workerLock.RLock()
|
tc.workerLock.RLock()
|
||||||
defer self.workerLock.RUnlock()
|
defer tc.workerLock.RUnlock()
|
||||||
return self.workerCount
|
return tc.workerCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) decrementWorkerCount() {
|
func (tc *TreeChunker) decrementWorkerCount() {
|
||||||
self.workerLock.Lock()
|
tc.workerLock.Lock()
|
||||||
defer self.workerLock.Unlock()
|
defer tc.workerLock.Unlock()
|
||||||
self.workerCount -= 1
|
tc.workerCount--
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, swg, wwg *sync.WaitGroup) (Key, error) {
|
func (tc *TreeChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, swg, wwg *sync.WaitGroup) (Key, error) {
|
||||||
if self.chunkSize <= 0 {
|
if tc.chunkSize <= 0 {
|
||||||
panic("chunker must be initialised")
|
panic("chunker must be initialised")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -140,23 +140,23 @@ func (self *TreeChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, s
|
||||||
wwg.Add(1)
|
wwg.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.incrementWorkerCount()
|
tc.incrementWorkerCount()
|
||||||
go self.hashWorker(jobC, chunkC, errC, quitC, swg, wwg)
|
go tc.hashWorker(jobC, chunkC, errC, quitC, swg, wwg)
|
||||||
|
|
||||||
depth := 0
|
depth := 0
|
||||||
treeSize := self.chunkSize
|
treeSize := tc.chunkSize
|
||||||
|
|
||||||
// takes lowest depth such that chunksize*HashCount^(depth+1) > size
|
// takes lowest depth such that chunksize*HashCount^(depth+1) > size
|
||||||
// power series, will find the order of magnitude of the data size in base hashCount or numbers of levels of branching in the resulting tree.
|
// power series, will find the order of magnitude of the data size in base hashCount or numbers of levels of branching in the resulting tree.
|
||||||
for ; treeSize < size; treeSize *= self.branches {
|
for ; treeSize < size; treeSize *= tc.branches {
|
||||||
depth++
|
depth++
|
||||||
}
|
}
|
||||||
|
|
||||||
key := make([]byte, self.hashFunc().Size())
|
key := make([]byte, tc.hashFunc().Size())
|
||||||
// this waitgroup member is released after the root hash is calculated
|
// this waitgroup member is released after the root hash is calculated
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
//launch actual recursive function passing the waitgroups
|
//launch actual recursive function passing the waitgroups
|
||||||
go self.split(depth, treeSize/self.branches, key, data, size, jobC, chunkC, errC, quitC, wg, swg, wwg)
|
go tc.split(depth, treeSize/tc.branches, key, data, size, jobC, chunkC, errC, quitC, wg, swg, wwg)
|
||||||
|
|
||||||
// closes internal error channel if all subprocesses in the workgroup finished
|
// closes internal error channel if all subprocesses in the workgroup finished
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -182,12 +182,12 @@ func (self *TreeChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, s
|
||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reader, size int64, jobC chan *hashJob, chunkC chan *Chunk, errC chan error, quitC chan bool, parentWg, swg, wwg *sync.WaitGroup) {
|
func (tc *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reader, size int64, jobC chan *hashJob, chunkC chan *Chunk, errC chan error, quitC chan bool, parentWg, swg, wwg *sync.WaitGroup) {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
for depth > 0 && size < treeSize {
|
for depth > 0 && size < treeSize {
|
||||||
treeSize /= self.branches
|
treeSize /= tc.branches
|
||||||
depth--
|
depth--
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,7 +214,7 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade
|
||||||
// intermediate chunk containing child nodes hashes
|
// intermediate chunk containing child nodes hashes
|
||||||
branchCnt := (size + treeSize - 1) / treeSize
|
branchCnt := (size + treeSize - 1) / treeSize
|
||||||
|
|
||||||
var chunk = make([]byte, branchCnt*self.hashSize+8)
|
var chunk = make([]byte, branchCnt*tc.hashSize+8)
|
||||||
var pos, i int64
|
var pos, i int64
|
||||||
|
|
||||||
binary.LittleEndian.PutUint64(chunk[0:8], uint64(size))
|
binary.LittleEndian.PutUint64(chunk[0:8], uint64(size))
|
||||||
|
|
@ -229,10 +229,10 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade
|
||||||
secSize = treeSize
|
secSize = treeSize
|
||||||
}
|
}
|
||||||
// the hash of that data
|
// the hash of that data
|
||||||
subTreeKey := chunk[8+i*self.hashSize : 8+(i+1)*self.hashSize]
|
subTreeKey := chunk[8+i*tc.hashSize : 8+(i+1)*tc.hashSize]
|
||||||
|
|
||||||
childrenWg.Add(1)
|
childrenWg.Add(1)
|
||||||
self.split(depth-1, treeSize/self.branches, subTreeKey, data, secSize, jobC, chunkC, errC, quitC, childrenWg, swg, wwg)
|
tc.split(depth-1, treeSize/tc.branches, subTreeKey, data, secSize, jobC, chunkC, errC, quitC, childrenWg, swg, wwg)
|
||||||
|
|
||||||
i++
|
i++
|
||||||
pos += treeSize
|
pos += treeSize
|
||||||
|
|
@ -242,13 +242,13 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade
|
||||||
// go func() {
|
// go func() {
|
||||||
childrenWg.Wait()
|
childrenWg.Wait()
|
||||||
|
|
||||||
worker := self.getWorkerCount()
|
worker := tc.getWorkerCount()
|
||||||
if int64(len(jobC)) > worker && worker < ChunkProcessors {
|
if int64(len(jobC)) > worker && worker < ChunkProcessors {
|
||||||
if wwg != nil {
|
if wwg != nil {
|
||||||
wwg.Add(1)
|
wwg.Add(1)
|
||||||
}
|
}
|
||||||
self.incrementWorkerCount()
|
tc.incrementWorkerCount()
|
||||||
go self.hashWorker(jobC, chunkC, errC, quitC, swg, wwg)
|
go tc.hashWorker(jobC, chunkC, errC, quitC, swg, wwg)
|
||||||
|
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
|
|
@ -257,10 +257,10 @@ func (self *TreeChunker) split(depth int, treeSize int64, key Key, data io.Reade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) hashWorker(jobC chan *hashJob, chunkC chan *Chunk, errC chan error, quitC chan bool, swg, wwg *sync.WaitGroup) {
|
func (tc *TreeChunker) hashWorker(jobC chan *hashJob, chunkC chan *Chunk, errC chan error, quitC chan bool, swg, wwg *sync.WaitGroup) {
|
||||||
defer self.decrementWorkerCount()
|
defer tc.decrementWorkerCount()
|
||||||
|
|
||||||
hasher := self.hashFunc()
|
hasher := tc.hashFunc()
|
||||||
if wwg != nil {
|
if wwg != nil {
|
||||||
defer wwg.Done()
|
defer wwg.Done()
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +272,7 @@ func (self *TreeChunker) hashWorker(jobC chan *hashJob, chunkC chan *Chunk, errC
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// now we got the hashes in the chunk, then hash the chunks
|
// now we got the hashes in the chunk, then hash the chunks
|
||||||
self.hashChunk(hasher, job, chunkC, swg)
|
tc.hashChunk(hasher, job, chunkC, swg)
|
||||||
case <-quitC:
|
case <-quitC:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -282,7 +282,7 @@ func (self *TreeChunker) hashWorker(jobC chan *hashJob, chunkC chan *Chunk, errC
|
||||||
// The treeChunkers own Hash hashes together
|
// The treeChunkers own Hash hashes together
|
||||||
// - the size (of the subtree encoded in the Chunk)
|
// - the size (of the subtree encoded in the Chunk)
|
||||||
// - the Chunk, ie. the contents read from the input reader
|
// - the Chunk, ie. the contents read from the input reader
|
||||||
func (self *TreeChunker) hashChunk(hasher SwarmHash, job *hashJob, chunkC chan *Chunk, swg *sync.WaitGroup) {
|
func (tc *TreeChunker) hashChunk(hasher SwarmHash, job *hashJob, chunkC chan *Chunk, swg *sync.WaitGroup) {
|
||||||
hasher.ResetWithLength(job.chunk[:8]) // 8 bytes of length
|
hasher.ResetWithLength(job.chunk[:8]) // 8 bytes of length
|
||||||
hasher.Write(job.chunk[8:]) // minus 8 []byte length
|
hasher.Write(job.chunk[8:]) // minus 8 []byte length
|
||||||
h := hasher.Sum(nil)
|
h := hasher.Sum(nil)
|
||||||
|
|
@ -316,7 +316,7 @@ func (self *TreeChunker) hashChunk(hasher SwarmHash, job *hashJob, chunkC chan *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TreeChunker) Append(key Key, data io.Reader, chunkC chan *Chunk, swg, wwg *sync.WaitGroup) (Key, error) {
|
func (tc *TreeChunker) Append(key Key, data io.Reader, chunkC chan *Chunk, swg, wwg *sync.WaitGroup) (Key, error) {
|
||||||
return nil, errAppendOppNotSuported
|
return nil, errAppendOppNotSuported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,45 +331,45 @@ type LazyChunkReader struct {
|
||||||
hashSize int64 // inherit from chunker
|
hashSize int64 // inherit from chunker
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements the Joiner interface
|
// Join implements the Joiner interface
|
||||||
func (self *TreeChunker) Join(key Key, chunkC chan *Chunk) LazySectionReader {
|
func (tc *TreeChunker) Join(key Key, chunkC chan *Chunk) LazySectionReader {
|
||||||
return &LazyChunkReader{
|
return &LazyChunkReader{
|
||||||
key: key,
|
key: key,
|
||||||
chunkC: chunkC,
|
chunkC: chunkC,
|
||||||
chunkSize: self.chunkSize,
|
chunkSize: tc.chunkSize,
|
||||||
branches: self.branches,
|
branches: tc.branches,
|
||||||
hashSize: self.hashSize,
|
hashSize: tc.hashSize,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size is meant to be called on the LazySectionReader
|
// Size is meant to be called on the LazySectionReader
|
||||||
func (self *LazyChunkReader) Size(quitC chan bool) (n int64, err error) {
|
func (reader *LazyChunkReader) Size(quitC chan bool) (n int64, err error) {
|
||||||
if self.chunk != nil {
|
if reader.chunk != nil {
|
||||||
return self.chunk.Size, nil
|
return reader.chunk.Size, nil
|
||||||
}
|
}
|
||||||
chunk := retrieve(self.key, self.chunkC, quitC)
|
chunk := retrieve(reader.key, reader.chunkC, quitC)
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
select {
|
select {
|
||||||
case <-quitC:
|
case <-quitC:
|
||||||
return 0, errors.New("aborted")
|
return 0, errors.New("aborted")
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("root chunk not found for %v", self.key.Hex())
|
return 0, fmt.Errorf("root chunk not found for %v", reader.key.Hex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.chunk = chunk
|
reader.chunk = chunk
|
||||||
return chunk.Size, nil
|
return chunk.Size, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// read at can be called numerous times
|
// ReadAt can be called numerous times
|
||||||
// concurrent reads are allowed
|
// concurrent reads are allowed
|
||||||
// Size() needs to be called synchronously on the LazyChunkReader first
|
// Size() needs to be called synchronously on the LazyChunkReader first
|
||||||
func (self *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) {
|
func (reader *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) {
|
||||||
// this is correct, a swarm doc cannot be zero length, so no EOF is expected
|
// this is correct, a swarm doc cannot be zero length, so no EOF is expected
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
size, err := self.Size(quitC)
|
size, err := reader.Size(quitC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -380,13 +380,13 @@ func (self *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) {
|
||||||
var treeSize int64
|
var treeSize int64
|
||||||
var depth int
|
var depth int
|
||||||
// calculate depth and max treeSize
|
// calculate depth and max treeSize
|
||||||
treeSize = self.chunkSize
|
treeSize = reader.chunkSize
|
||||||
for ; treeSize < size; treeSize *= self.branches {
|
for ; treeSize < size; treeSize *= reader.branches {
|
||||||
depth++
|
depth++
|
||||||
}
|
}
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go self.join(b, off, off+int64(len(b)), depth, treeSize/self.branches, self.chunk, &wg, errC, quitC)
|
go reader.join(b, off, off+int64(len(b)), depth, treeSize/reader.branches, reader.chunk, &wg, errC, quitC)
|
||||||
go func() {
|
go func() {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
close(errC)
|
close(errC)
|
||||||
|
|
@ -404,7 +404,7 @@ func (self *LazyChunkReader) ReadAt(b []byte, off int64) (read int, err error) {
|
||||||
return len(b), nil
|
return len(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, treeSize int64, chunk *Chunk, parentWg *sync.WaitGroup, errC chan error, quitC chan bool) {
|
func (reader *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, treeSize int64, chunk *Chunk, parentWg *sync.WaitGroup, errC chan error, quitC chan bool) {
|
||||||
defer parentWg.Done()
|
defer parentWg.Done()
|
||||||
// return NewDPA(&LocalStore{})
|
// return NewDPA(&LocalStore{})
|
||||||
|
|
||||||
|
|
@ -412,7 +412,7 @@ func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, tr
|
||||||
|
|
||||||
// find appropriate block level
|
// find appropriate block level
|
||||||
for chunk.Size < treeSize && depth > 0 {
|
for chunk.Size < treeSize && depth > 0 {
|
||||||
treeSize /= self.branches
|
treeSize /= reader.branches
|
||||||
depth--
|
depth--
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -449,8 +449,8 @@ func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, tr
|
||||||
}
|
}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(j int64) {
|
go func(j int64) {
|
||||||
childKey := chunk.SData[8+j*self.hashSize : 8+(j+1)*self.hashSize]
|
childKey := chunk.SData[8+j*reader.hashSize : 8+(j+1)*reader.hashSize]
|
||||||
chunk := retrieve(childKey, self.chunkC, quitC)
|
chunk := retrieve(childKey, reader.chunkC, quitC)
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
select {
|
select {
|
||||||
case errC <- fmt.Errorf("chunk %v-%v not found", off, off+treeSize):
|
case errC <- fmt.Errorf("chunk %v-%v not found", off, off+treeSize):
|
||||||
|
|
@ -461,7 +461,7 @@ func (self *LazyChunkReader) join(b []byte, off int64, eoff int64, depth int, tr
|
||||||
if soff < off {
|
if soff < off {
|
||||||
soff = off
|
soff = off
|
||||||
}
|
}
|
||||||
self.join(b[soff-off:seoff-off], soff-roff, seoff-roff, depth-1, treeSize/self.branches, chunk, wg, errC, quitC)
|
reader.join(b[soff-off:seoff-off], soff-roff, seoff-roff, depth-1, treeSize/reader.branches, chunk, wg, errC, quitC)
|
||||||
}(i)
|
}(i)
|
||||||
} //for
|
} //for
|
||||||
}
|
}
|
||||||
|
|
@ -496,10 +496,10 @@ func retrieve(key Key, chunkC chan *Chunk, quitC chan bool) *Chunk {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read keeps a cursor so cannot be called simulateously, see ReadAt
|
// Read keeps a cursor so cannot be called simulateously, see ReadAt
|
||||||
func (self *LazyChunkReader) Read(b []byte) (read int, err error) {
|
func (reader *LazyChunkReader) Read(b []byte) (read int, err error) {
|
||||||
read, err = self.ReadAt(b, self.off)
|
read, err = reader.ReadAt(b, reader.off)
|
||||||
|
|
||||||
self.off += int64(read)
|
reader.off += int64(read)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,27 +507,27 @@ func (self *LazyChunkReader) Read(b []byte) (read int, err error) {
|
||||||
var errWhence = errors.New("Seek: invalid whence")
|
var errWhence = errors.New("Seek: invalid whence")
|
||||||
var errOffset = errors.New("Seek: invalid offset")
|
var errOffset = errors.New("Seek: invalid offset")
|
||||||
|
|
||||||
func (s *LazyChunkReader) Seek(offset int64, whence int) (int64, error) {
|
func (reader *LazyChunkReader) Seek(offset int64, whence int) (int64, error) {
|
||||||
switch whence {
|
switch whence {
|
||||||
default:
|
default:
|
||||||
return 0, errWhence
|
return 0, errWhence
|
||||||
case 0:
|
case 0:
|
||||||
offset += 0
|
offset += 0
|
||||||
case 1:
|
case 1:
|
||||||
offset += s.off
|
offset += reader.off
|
||||||
case 2:
|
case 2:
|
||||||
if s.chunk == nil { //seek from the end requires rootchunk for size. call Size first
|
if reader.chunk == nil { //seek from the end requires rootchunk for size. call Size first
|
||||||
_, err := s.Size(nil)
|
_, err := reader.Size(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("can't get size: %v", err)
|
return 0, fmt.Errorf("can't get size: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset += s.chunk.Size
|
offset += reader.chunk.Size
|
||||||
}
|
}
|
||||||
|
|
||||||
if offset < 0 {
|
if offset < 0 {
|
||||||
return 0, errOffset
|
return 0, errOffset
|
||||||
}
|
}
|
||||||
s.off = offset
|
reader.off = offset
|
||||||
return offset, nil
|
return offset, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,12 @@ type chunkerTester struct {
|
||||||
t test
|
t test
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key, err error) {
|
func (tester *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key, err error) {
|
||||||
// reset
|
// reset
|
||||||
self.chunks = make(map[string]*Chunk)
|
tester.chunks = make(map[string]*Chunk)
|
||||||
|
|
||||||
if self.inputs == nil {
|
if tester.inputs == nil {
|
||||||
self.inputs = make(map[uint64][]byte)
|
tester.inputs = make(map[uint64][]byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
|
|
@ -64,8 +64,8 @@ func (self *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, c
|
||||||
case <-quitC:
|
case <-quitC:
|
||||||
return nil
|
return nil
|
||||||
case chunk := <-chunkC:
|
case chunk := <-chunkC:
|
||||||
// self.chunks = append(self.chunks, chunk)
|
// tester.chunks = append(tester.chunks, chunk)
|
||||||
self.chunks[chunk.Key.String()] = chunk
|
tester.chunks[chunk.Key.String()] = chunk
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
chunk.wg.Done()
|
chunk.wg.Done()
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +89,7 @@ func (self *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, c
|
||||||
return key, err
|
return key, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *chunkerTester) Append(chunker Splitter, rootKey Key, data io.Reader, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key, err error) {
|
func (tester *chunkerTester) Append(chunker Splitter, rootKey Key, data io.Reader, chunkC chan *Chunk, swg *sync.WaitGroup, expectedError error) (key Key, err error) {
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
timeout := time.After(60 * time.Second)
|
timeout := time.After(60 * time.Second)
|
||||||
if chunkC != nil {
|
if chunkC != nil {
|
||||||
|
|
@ -102,10 +102,10 @@ func (self *chunkerTester) Append(chunker Splitter, rootKey Key, data io.Reader,
|
||||||
return nil
|
return nil
|
||||||
case chunk := <-chunkC:
|
case chunk := <-chunkC:
|
||||||
if chunk != nil {
|
if chunk != nil {
|
||||||
stored, success := self.chunks[chunk.Key.String()]
|
stored, success := tester.chunks[chunk.Key.String()]
|
||||||
if !success {
|
if !success {
|
||||||
// Requesting data
|
// Requesting data
|
||||||
self.chunks[chunk.Key.String()] = chunk
|
tester.chunks[chunk.Key.String()] = chunk
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
chunk.wg.Done()
|
chunk.wg.Done()
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +135,7 @@ func (self *chunkerTester) Append(chunker Splitter, rootKey Key, data io.Reader,
|
||||||
return key, err
|
return key, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *chunkerTester) Join(chunker Chunker, key Key, c int, chunkC chan *Chunk, quitC chan bool) LazySectionReader {
|
func (tester *chunkerTester) Join(chunker Chunker, key Key, c int, chunkC chan *Chunk, quitC chan bool) LazySectionReader {
|
||||||
// reset but not the chunks
|
// reset but not the chunks
|
||||||
|
|
||||||
reader := chunker.Join(key, chunkC)
|
reader := chunker.Join(key, chunkC)
|
||||||
|
|
@ -153,7 +153,7 @@ func (self *chunkerTester) Join(chunker Chunker, key Key, c int, chunkC chan *Ch
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// this just mocks the behaviour of a chunk store retrieval
|
// this just mocks the behaviour of a chunk store retrieval
|
||||||
stored, success := self.chunks[chunk.Key.String()]
|
stored, success := tester.chunks[chunk.Key.String()]
|
||||||
if !success {
|
if !success {
|
||||||
return errors.New("Not found")
|
return errors.New("Not found")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,12 +46,12 @@ func testDataReader(l int) (r io.Reader) {
|
||||||
return io.LimitReader(rand.Reader, int64(l))
|
return io.LimitReader(rand.Reader, int64(l))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *brokenLimitedReader) Read(buf []byte) (int, error) {
|
func (reader *brokenLimitedReader) Read(buf []byte) (int, error) {
|
||||||
if self.off+len(buf) > self.errAt {
|
if reader.off+len(buf) > reader.errAt {
|
||||||
return 0, fmt.Errorf("Broken reader")
|
return 0, fmt.Errorf("Broken reader")
|
||||||
}
|
}
|
||||||
self.off += len(buf)
|
reader.off += len(buf)
|
||||||
return self.lr.Read(buf)
|
return reader.lr.Read(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDataReaderAndSlice(l int) (r io.Reader, slice []byte) {
|
func testDataReaderAndSlice(l int) (r io.Reader, slice []byte) {
|
||||||
|
|
|
||||||
|
|
@ -45,27 +45,27 @@ func NewLDBDatabase(file string) (*LDBDatabase, error) {
|
||||||
return database, nil
|
return database, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) Put(key []byte, value []byte) {
|
func (db *LDBDatabase) Put(key []byte, value []byte) {
|
||||||
err := self.db.Put(key, value, nil)
|
err := db.db.Put(key, value, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error put", err)
|
fmt.Println("Error put", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
|
func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
|
||||||
dat, err := self.db.Get(key, nil)
|
dat, err := db.db.Get(key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return dat, nil
|
return dat, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) Delete(key []byte) error {
|
func (db *LDBDatabase) Delete(key []byte) error {
|
||||||
return self.db.Delete(key, nil)
|
return db.db.Delete(key, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) LastKnownTD() []byte {
|
func (db *LDBDatabase) LastKnownTD() []byte {
|
||||||
data, _ := self.Get([]byte("LTD"))
|
data, _ := db.Get([]byte("LTD"))
|
||||||
|
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
data = []byte{0x0}
|
data = []byte{0x0}
|
||||||
|
|
@ -74,15 +74,15 @@ func (self *LDBDatabase) LastKnownTD() []byte {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) NewIterator() iterator.Iterator {
|
func (db *LDBDatabase) NewIterator() iterator.Iterator {
|
||||||
return self.db.NewIterator(nil, nil)
|
return db.db.NewIterator(nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) Write(batch *leveldb.Batch) error {
|
func (db *LDBDatabase) Write(batch *leveldb.Batch) error {
|
||||||
return self.db.Write(batch, nil)
|
return db.db.Write(batch, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LDBDatabase) Close() {
|
func (db *LDBDatabase) Close() {
|
||||||
// Close the leveldb database
|
// Close the leveldb database
|
||||||
self.db.Close()
|
db.db.Close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -201,14 +201,12 @@ func gcListSelect(list []*gcItem, left int, right int, n int) int {
|
||||||
pivotIndex = gcListPartition(list, left, right, pivotIndex)
|
pivotIndex = gcListPartition(list, left, right, pivotIndex)
|
||||||
if n == pivotIndex {
|
if n == pivotIndex {
|
||||||
return n
|
return n
|
||||||
} else {
|
} else if n < pivotIndex {
|
||||||
if n < pivotIndex {
|
|
||||||
return gcListSelect(list, left, pivotIndex-1, n)
|
return gcListSelect(list, left, pivotIndex-1, n)
|
||||||
} else {
|
} else {
|
||||||
return gcListSelect(list, pivotIndex+1, right, n)
|
return gcListSelect(list, pivotIndex+1, right, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (s *DbStore) collectGarbage(ratio float32) {
|
func (s *DbStore) collectGarbage(ratio float32) {
|
||||||
it := s.db.NewIterator()
|
it := s.db.NewIterator()
|
||||||
|
|
@ -539,7 +537,7 @@ func (s *DbStore) Close() {
|
||||||
s.db.Close()
|
s.db.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// describes a section of the DbStore representing the unsynced
|
// DbSyncState describes a section of the DbStore representing the unsynced
|
||||||
// domain relevant to a peer
|
// domain relevant to a peer
|
||||||
// Start - Stop designate a continuous area Keys in an address space
|
// Start - Stop designate a continuous area Keys in an address space
|
||||||
// typically the addresses closer to us than to the peer but not closer
|
// typically the addresses closer to us than to the peer but not closer
|
||||||
|
|
@ -558,13 +556,13 @@ type dbSyncIterator struct {
|
||||||
DbSyncState
|
DbSyncState
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialises a sync iterator from a syncToken (passed in with the handshake)
|
// NewSyncIterator initialises a sync iterator from a syncToken (passed in with the handshake)
|
||||||
func (self *DbStore) NewSyncIterator(state DbSyncState) (si *dbSyncIterator, err error) {
|
func (s *DbStore) NewSyncIterator(state DbSyncState) (si *dbSyncIterator, err error) {
|
||||||
if state.First > state.Last {
|
if state.First > state.Last {
|
||||||
return nil, fmt.Errorf("no entries found")
|
return nil, fmt.Errorf("no entries found")
|
||||||
}
|
}
|
||||||
si = &dbSyncIterator{
|
si = &dbSyncIterator{
|
||||||
it: self.db.NewIterator(),
|
it: s.db.NewIterator(),
|
||||||
DbSyncState: state,
|
DbSyncState: state,
|
||||||
}
|
}
|
||||||
si.it.Seek(getIndexKey(state.Start))
|
si.it.Seek(getIndexKey(state.Start))
|
||||||
|
|
@ -573,28 +571,28 @@ func (self *DbStore) NewSyncIterator(state DbSyncState) (si *dbSyncIterator, err
|
||||||
|
|
||||||
// walk the area from Start to Stop and returns items within time interval
|
// walk the area from Start to Stop and returns items within time interval
|
||||||
// First to Last
|
// First to Last
|
||||||
func (self *dbSyncIterator) Next() (key Key) {
|
func (itr *dbSyncIterator) Next() (key Key) {
|
||||||
for self.it.Valid() {
|
for itr.it.Valid() {
|
||||||
dbkey := self.it.Key()
|
dbkey := itr.it.Key()
|
||||||
if dbkey[0] != 0 {
|
if dbkey[0] != 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
key = Key(make([]byte, len(dbkey)-1))
|
key = Key(make([]byte, len(dbkey)-1))
|
||||||
copy(key[:], dbkey[1:])
|
copy(key[:], dbkey[1:])
|
||||||
if bytes.Compare(key[:], self.Start) <= 0 {
|
if bytes.Compare(key[:], itr.Start) <= 0 {
|
||||||
self.it.Next()
|
itr.it.Next()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if bytes.Compare(key[:], self.Stop) > 0 {
|
if bytes.Compare(key[:], itr.Stop) > 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
var index dpaDBIndex
|
var index dpaDBIndex
|
||||||
decodeIndex(self.it.Value(), &index)
|
decodeIndex(itr.it.Value(), &index)
|
||||||
self.it.Next()
|
itr.it.Next()
|
||||||
if (index.Idx >= self.First) && (index.Idx < self.Last) {
|
if (index.Idx >= itr.First) && (index.Idx < itr.Last) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.it.Release()
|
itr.it.Release()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ type DPA struct {
|
||||||
quitC chan bool
|
quitC chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// for testing locally
|
// NewLocalDPA used for testing locally
|
||||||
func NewLocalDPA(datadir string) (*DPA, error) {
|
func NewLocalDPA(datadir string) (*DPA, error) {
|
||||||
|
|
||||||
hash := MakeHashFunc("SHA256")
|
hash := MakeHashFunc("SHA256")
|
||||||
|
|
@ -90,53 +90,53 @@ func NewDPA(store ChunkStore, params *ChunkerParams) *DPA {
|
||||||
// FS-aware API and httpaccess
|
// FS-aware API and httpaccess
|
||||||
// Chunk retrieval blocks on netStore requests with a timeout so reader will
|
// Chunk retrieval blocks on netStore requests with a timeout so reader will
|
||||||
// report error if retrieval of chunks within requested range time out.
|
// report error if retrieval of chunks within requested range time out.
|
||||||
func (self *DPA) Retrieve(key Key) LazySectionReader {
|
func (dpa *DPA) Retrieve(key Key) LazySectionReader {
|
||||||
return self.Chunker.Join(key, self.retrieveC)
|
return dpa.Chunker.Join(key, dpa.retrieveC)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public API. Main entry point for document storage directly. Used by the
|
// Public API. Main entry point for document storage directly. Used by the
|
||||||
// FS-aware API and httpaccess
|
// FS-aware API and httpaccess
|
||||||
func (self *DPA) Store(data io.Reader, size int64, swg *sync.WaitGroup, wwg *sync.WaitGroup) (key Key, err error) {
|
func (dpa *DPA) Store(data io.Reader, size int64, swg *sync.WaitGroup, wwg *sync.WaitGroup) (key Key, err error) {
|
||||||
return self.Chunker.Split(data, size, self.storeC, swg, wwg)
|
return dpa.Chunker.Split(data, size, dpa.storeC, swg, wwg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DPA) Start() {
|
func (dpa *DPA) Start() {
|
||||||
self.lock.Lock()
|
dpa.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer dpa.lock.Unlock()
|
||||||
if self.running {
|
if dpa.running {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.running = true
|
dpa.running = true
|
||||||
self.retrieveC = make(chan *Chunk, retrieveChanCapacity)
|
dpa.retrieveC = make(chan *Chunk, retrieveChanCapacity)
|
||||||
self.storeC = make(chan *Chunk, storeChanCapacity)
|
dpa.storeC = make(chan *Chunk, storeChanCapacity)
|
||||||
self.quitC = make(chan bool)
|
dpa.quitC = make(chan bool)
|
||||||
self.storeLoop()
|
dpa.storeLoop()
|
||||||
self.retrieveLoop()
|
dpa.retrieveLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DPA) Stop() {
|
func (dpa *DPA) Stop() {
|
||||||
self.lock.Lock()
|
dpa.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer dpa.lock.Unlock()
|
||||||
if !self.running {
|
if !dpa.running {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.running = false
|
dpa.running = false
|
||||||
close(self.quitC)
|
close(dpa.quitC)
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieveLoop dispatches the parallel chunk retrieval requests received on the
|
// retrieveLoop dispatches the parallel chunk retrieval requests received on the
|
||||||
// retrieve channel to its ChunkStore (NetStore or LocalStore)
|
// retrieve channel to its ChunkStore (NetStore or LocalStore)
|
||||||
func (self *DPA) retrieveLoop() {
|
func (dpa *DPA) retrieveLoop() {
|
||||||
for i := 0; i < maxRetrieveProcesses; i++ {
|
for i := 0; i < maxRetrieveProcesses; i++ {
|
||||||
go self.retrieveWorker()
|
go dpa.retrieveWorker()
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("dpa: retrieve loop spawning %v workers", maxRetrieveProcesses))
|
log.Trace(fmt.Sprintf("dpa: retrieve loop spawning %v workers", maxRetrieveProcesses))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DPA) retrieveWorker() {
|
func (dpa *DPA) retrieveWorker() {
|
||||||
for chunk := range self.retrieveC {
|
for chunk := range dpa.retrieveC {
|
||||||
log.Trace(fmt.Sprintf("dpa: retrieve loop : chunk %v", chunk.Key.Log()))
|
log.Trace(fmt.Sprintf("dpa: retrieve loop : chunk %v", chunk.Key.Log()))
|
||||||
storedChunk, err := self.Get(chunk.Key)
|
storedChunk, err := dpa.Get(chunk.Key)
|
||||||
if err == notFound {
|
if err == notFound {
|
||||||
log.Trace(fmt.Sprintf("chunk %v not found", chunk.Key.Log()))
|
log.Trace(fmt.Sprintf("chunk %v not found", chunk.Key.Log()))
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
|
@ -148,7 +148,7 @@ func (self *DPA) retrieveWorker() {
|
||||||
close(chunk.C)
|
close(chunk.C)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-self.quitC:
|
case <-dpa.quitC:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
@ -157,24 +157,24 @@ func (self *DPA) retrieveWorker() {
|
||||||
|
|
||||||
// storeLoop dispatches the parallel chunk store request processors
|
// storeLoop dispatches the parallel chunk store request processors
|
||||||
// received on the store channel to its ChunkStore (NetStore or LocalStore)
|
// received on the store channel to its ChunkStore (NetStore or LocalStore)
|
||||||
func (self *DPA) storeLoop() {
|
func (dpa *DPA) storeLoop() {
|
||||||
for i := 0; i < maxStoreProcesses; i++ {
|
for i := 0; i < maxStoreProcesses; i++ {
|
||||||
go self.storeWorker()
|
go dpa.storeWorker()
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("dpa: store spawning %v workers", maxStoreProcesses))
|
log.Trace(fmt.Sprintf("dpa: store spawning %v workers", maxStoreProcesses))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DPA) storeWorker() {
|
func (dpa *DPA) storeWorker() {
|
||||||
|
|
||||||
for chunk := range self.storeC {
|
for chunk := range dpa.storeC {
|
||||||
self.Put(chunk)
|
dpa.Put(chunk)
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
log.Trace(fmt.Sprintf("dpa: store processor %v", chunk.Key.Log()))
|
log.Trace(fmt.Sprintf("dpa: store processor %v", chunk.Key.Log()))
|
||||||
chunk.wg.Done()
|
chunk.wg.Done()
|
||||||
|
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-self.quitC:
|
case <-dpa.quitC:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
@ -198,14 +198,14 @@ func NewDpaChunkStore(localStore, netStore ChunkStore) *dpaChunkStore {
|
||||||
|
|
||||||
// Get is the entrypoint for local retrieve requests
|
// Get is the entrypoint for local retrieve requests
|
||||||
// waits for response or times out
|
// waits for response or times out
|
||||||
func (self *dpaChunkStore) Get(key Key) (chunk *Chunk, err error) {
|
func (s *dpaChunkStore) Get(key Key) (chunk *Chunk, err error) {
|
||||||
chunk, err = self.netStore.Get(key)
|
chunk, err = s.netStore.Get(key)
|
||||||
// timeout := time.Now().Add(searchTimeout)
|
// timeout := time.Now().Add(searchTimeout)
|
||||||
if chunk.SData != nil {
|
if chunk.SData != nil {
|
||||||
log.Trace(fmt.Sprintf("DPA.Get: %v found locally, %d bytes", key.Log(), len(chunk.SData)))
|
log.Trace(fmt.Sprintf("DPA.Get: %v found locally, %d bytes", key.Log(), len(chunk.SData)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// TODO: use self.timer time.Timer and reset with defer disableTimer
|
// TODO: use s.timer time.Timer and reset with defer disableTimer
|
||||||
timer := time.After(searchTimeout)
|
timer := time.After(searchTimeout)
|
||||||
select {
|
select {
|
||||||
case <-timer:
|
case <-timer:
|
||||||
|
|
@ -218,8 +218,8 @@ func (self *dpaChunkStore) Get(key Key) (chunk *Chunk, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put is the entrypoint for local store requests coming from storeLoop
|
// Put is the entrypoint for local store requests coming from storeLoop
|
||||||
func (self *dpaChunkStore) Put(entry *Chunk) {
|
func (s *dpaChunkStore) Put(entry *Chunk) {
|
||||||
chunk, err := self.localStore.Get(entry.Key)
|
chunk, err := s.localStore.Get(entry.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Trace(fmt.Sprintf("DPA.Put: %v new chunk. call netStore.Put", entry.Key.Log()))
|
log.Trace(fmt.Sprintf("DPA.Put: %v new chunk. call netStore.Put", entry.Key.Log()))
|
||||||
chunk = entry
|
chunk = entry
|
||||||
|
|
@ -232,10 +232,10 @@ func (self *dpaChunkStore) Put(entry *Chunk) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// from this point on the storage logic is the same with network storage requests
|
// from this point on the storage logic is the same with network storage requests
|
||||||
log.Trace(fmt.Sprintf("DPA.Put %v: %v", self.n, chunk.Key.Log()))
|
log.Trace(fmt.Sprintf("DPA.Put %v: %v", s.n, chunk.Key.Log()))
|
||||||
self.n++
|
s.n++
|
||||||
self.netStore.Put(chunk)
|
s.netStore.Put(chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close chunk store
|
// Close chunk store
|
||||||
func (self *dpaChunkStore) Close() {}
|
func (s *dpaChunkStore) Close() {}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ type LocalStore struct {
|
||||||
DbStore ChunkStore
|
DbStore ChunkStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// This constructor uses MemStore and DbStore as components
|
// NewLocalStore constructor uses MemStore and DbStore as components
|
||||||
func NewLocalStore(hash SwarmHasher, params *StoreParams) (*LocalStore, error) {
|
func NewLocalStore(hash SwarmHasher, params *StoreParams) (*LocalStore, error) {
|
||||||
dbStore, err := NewDbStore(params.ChunkDbPath, hash, params.DbCapacity, params.Radius)
|
dbStore, err := NewDbStore(params.ChunkDbPath, hash, params.DbCapacity, params.Radius)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -46,48 +46,48 @@ func NewLocalStore(hash SwarmHasher, params *StoreParams) (*LocalStore, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalStore) CacheCounter() uint64 {
|
func (s *LocalStore) CacheCounter() uint64 {
|
||||||
return uint64(self.memStore.(*MemStore).Counter())
|
return uint64(s.memStore.(*MemStore).Counter())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalStore) DbCounter() uint64 {
|
func (s *LocalStore) DbCounter() uint64 {
|
||||||
return self.DbStore.(*DbStore).Counter()
|
return s.DbStore.(*DbStore).Counter()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalStore is itself a chunk store
|
// LocalStore is itself a chunk store
|
||||||
// unsafe, in that the data is not integrity checked
|
// unsafe, in that the data is not integrity checked
|
||||||
func (self *LocalStore) Put(chunk *Chunk) {
|
func (s *LocalStore) Put(chunk *Chunk) {
|
||||||
chunk.dbStored = make(chan bool)
|
chunk.dbStored = make(chan bool)
|
||||||
self.memStore.Put(chunk)
|
s.memStore.Put(chunk)
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
chunk.wg.Add(1)
|
chunk.wg.Add(1)
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
dbStorePutCounter.Inc(1)
|
dbStorePutCounter.Inc(1)
|
||||||
self.DbStore.Put(chunk)
|
s.DbStore.Put(chunk)
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
chunk.wg.Done()
|
chunk.wg.Done()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get(chunk *Chunk) looks up a chunk in the local stores
|
// Get looks up a chunk in the local stores
|
||||||
// This method is blocking until the chunk is retrieved
|
// This method is blocking until the chunk is retrieved
|
||||||
// so additional timeout may be needed to wrap this call if
|
// so additional timeout may be needed to wrap this call if
|
||||||
// ChunkStores are remote and can have long latency
|
// ChunkStores are remote and can have long latency
|
||||||
func (self *LocalStore) Get(key Key) (chunk *Chunk, err error) {
|
func (s *LocalStore) Get(key Key) (chunk *Chunk, err error) {
|
||||||
chunk, err = self.memStore.Get(key)
|
chunk, err = s.memStore.Get(key)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
chunk, err = self.DbStore.Get(key)
|
chunk, err = s.DbStore.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8]))
|
chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8]))
|
||||||
self.memStore.Put(chunk)
|
s.memStore.Put(chunk)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close local store
|
// Close local store
|
||||||
func (self *LocalStore) Close() {}
|
func (s *LocalStore) Close() {}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ type NetStore struct {
|
||||||
cloud CloudStore
|
cloud CloudStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// backend engine for cloud store
|
// CloudStore backend engine
|
||||||
// It can be aggregate dispatching to several parallel implementations:
|
// It can be aggregate dispatching to several parallel implementations:
|
||||||
// bzz/network/forwarder. forwarder or IPFS or IPΞS
|
// bzz/network/forwarder. forwarder or IPFS or IPΞS
|
||||||
type CloudStore interface {
|
type CloudStore interface {
|
||||||
|
|
@ -58,7 +58,7 @@ type StoreParams struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
//create params with default values
|
//create params with default values
|
||||||
func NewDefaultStoreParams() (self *StoreParams) {
|
func NewDefaultStoreParams() (params *StoreParams) {
|
||||||
return &StoreParams{
|
return &StoreParams{
|
||||||
DbCapacity: defaultDbCapacity,
|
DbCapacity: defaultDbCapacity,
|
||||||
CacheCapacity: defaultCacheCapacity,
|
CacheCapacity: defaultCacheCapacity,
|
||||||
|
|
@ -68,11 +68,11 @@ func NewDefaultStoreParams() (self *StoreParams) {
|
||||||
|
|
||||||
//this can only finally be set after all config options (file, cmd line, env vars)
|
//this can only finally be set after all config options (file, cmd line, env vars)
|
||||||
//have been evaluated
|
//have been evaluated
|
||||||
func (self *StoreParams) Init(path string) {
|
func (params *StoreParams) Init(path string) {
|
||||||
self.ChunkDbPath = filepath.Join(path, "chunks")
|
params.ChunkDbPath = filepath.Join(path, "chunks")
|
||||||
}
|
}
|
||||||
|
|
||||||
// netstore contructor, takes path argument that is used to initialise dbStore,
|
// NewNetStore contructs NetStore, takes path argument that is used to initialise dbStore,
|
||||||
// the persistent (disk) storage component of LocalStore
|
// the persistent (disk) storage component of LocalStore
|
||||||
// the second argument is the hive, the connection/logistics manager for the node
|
// the second argument is the hive, the connection/logistics manager for the node
|
||||||
func NewNetStore(hash SwarmHasher, lstore *LocalStore, cloud CloudStore, params *StoreParams) *NetStore {
|
func NewNetStore(hash SwarmHasher, lstore *LocalStore, cloud CloudStore, params *StoreParams) *NetStore {
|
||||||
|
|
@ -92,8 +92,8 @@ var (
|
||||||
// ~ unsafe put in localdb no check if exists no extra copy no hash validation
|
// ~ unsafe put in localdb no check if exists no extra copy no hash validation
|
||||||
// the chunk is forced to propagate (Cloud.Store) even if locally found!
|
// the chunk is forced to propagate (Cloud.Store) even if locally found!
|
||||||
// caller needs to make sure if that is wanted
|
// caller needs to make sure if that is wanted
|
||||||
func (self *NetStore) Put(entry *Chunk) {
|
func (s *NetStore) Put(entry *Chunk) {
|
||||||
self.localStore.Put(entry)
|
s.localStore.Put(entry)
|
||||||
|
|
||||||
// handle deliveries
|
// handle deliveries
|
||||||
if entry.Req != nil {
|
if entry.Req != nil {
|
||||||
|
|
@ -102,19 +102,19 @@ func (self *NetStore) Put(entry *Chunk) {
|
||||||
// that the chunk is has been retrieved
|
// that the chunk is has been retrieved
|
||||||
close(entry.Req.C)
|
close(entry.Req.C)
|
||||||
// deliver the chunk to requesters upstream
|
// deliver the chunk to requesters upstream
|
||||||
go self.cloud.Deliver(entry)
|
go s.cloud.Deliver(entry)
|
||||||
} else {
|
} else {
|
||||||
log.Trace(fmt.Sprintf("NetStore.Put: localStore.Put %v stored locally", entry.Key.Log()))
|
log.Trace(fmt.Sprintf("NetStore.Put: localStore.Put %v stored locally", entry.Key.Log()))
|
||||||
// handle propagating store requests
|
// handle propagating store requests
|
||||||
// go self.cloud.Store(entry)
|
// go s.cloud.Store(entry)
|
||||||
go self.cloud.Store(entry)
|
go s.cloud.Store(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve logic common for local and network chunk retrieval requests
|
// Get logic common for local and network chunk retrieval requests
|
||||||
func (self *NetStore) Get(key Key) (*Chunk, error) {
|
func (s *NetStore) Get(key Key) (*Chunk, error) {
|
||||||
var err error
|
var err error
|
||||||
chunk, err := self.localStore.Get(key)
|
chunk, err := s.localStore.Get(key)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if chunk.Req == nil {
|
if chunk.Req == nil {
|
||||||
log.Trace(fmt.Sprintf("NetStore.Get: %v found locally", key))
|
log.Trace(fmt.Sprintf("NetStore.Get: %v found locally", key))
|
||||||
|
|
@ -127,10 +127,10 @@ func (self *NetStore) Get(key Key) (*Chunk, error) {
|
||||||
// no data and no request status
|
// no data and no request status
|
||||||
log.Trace(fmt.Sprintf("NetStore.Get: %v not found locally. open new request", key))
|
log.Trace(fmt.Sprintf("NetStore.Get: %v not found locally. open new request", key))
|
||||||
chunk = NewChunk(key, newRequestStatus(key))
|
chunk = NewChunk(key, newRequestStatus(key))
|
||||||
self.localStore.memStore.Put(chunk)
|
s.localStore.memStore.Put(chunk)
|
||||||
go self.cloud.Retrieve(chunk)
|
go s.cloud.Retrieve(chunk)
|
||||||
return chunk, nil
|
return chunk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close netstore
|
// Close netstore
|
||||||
func (self *NetStore) Close() {}
|
func (s *NetStore) Close() {}
|
||||||
|
|
|
||||||
|
|
@ -136,44 +136,44 @@ func NewPyramidChunker(params *ChunkerParams) (self *PyramidChunker) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) Join(key Key, chunkC chan *Chunk) LazySectionReader {
|
func (c *PyramidChunker) Join(key Key, chunkC chan *Chunk) LazySectionReader {
|
||||||
return &LazyChunkReader{
|
return &LazyChunkReader{
|
||||||
key: key,
|
key: key,
|
||||||
chunkC: chunkC,
|
chunkC: chunkC,
|
||||||
chunkSize: self.chunkSize,
|
chunkSize: c.chunkSize,
|
||||||
branches: self.branches,
|
branches: c.branches,
|
||||||
hashSize: self.hashSize,
|
hashSize: c.hashSize,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) incrementWorkerCount() {
|
func (c *PyramidChunker) incrementWorkerCount() {
|
||||||
self.workerLock.Lock()
|
c.workerLock.Lock()
|
||||||
defer self.workerLock.Unlock()
|
defer c.workerLock.Unlock()
|
||||||
self.workerCount += 1
|
c.workerCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) getWorkerCount() int64 {
|
func (c *PyramidChunker) getWorkerCount() int64 {
|
||||||
self.workerLock.Lock()
|
c.workerLock.Lock()
|
||||||
defer self.workerLock.Unlock()
|
defer c.workerLock.Unlock()
|
||||||
return self.workerCount
|
return c.workerCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) decrementWorkerCount() {
|
func (c *PyramidChunker) decrementWorkerCount() {
|
||||||
self.workerLock.Lock()
|
c.workerLock.Lock()
|
||||||
defer self.workerLock.Unlock()
|
defer c.workerLock.Unlock()
|
||||||
self.workerCount -= 1
|
c.workerCount--
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, storageWG, processorWG *sync.WaitGroup) (Key, error) {
|
func (c *PyramidChunker) Split(data io.Reader, size int64, chunkC chan *Chunk, storageWG, processorWG *sync.WaitGroup) (Key, error) {
|
||||||
jobC := make(chan *chunkJob, 2*ChunkProcessors)
|
jobC := make(chan *chunkJob, 2*ChunkProcessors)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
errC := make(chan error)
|
errC := make(chan error)
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
rootKey := make([]byte, self.hashSize)
|
rootKey := make([]byte, c.hashSize)
|
||||||
chunkLevel := make([][]*TreeEntry, self.branches)
|
chunkLevel := make([][]*TreeEntry, c.branches)
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go self.prepareChunks(false, chunkLevel, data, rootKey, quitC, wg, jobC, processorWG, chunkC, errC, storageWG)
|
go c.prepareChunks(false, chunkLevel, data, rootKey, quitC, wg, jobC, processorWG, chunkC, errC, storageWG)
|
||||||
|
|
||||||
// closes internal error channel if all subprocesses in the workgroup finished
|
// closes internal error channel if all subprocesses in the workgroup finished
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -204,20 +204,20 @@ func (self *PyramidChunker) Split(data io.Reader, size int64, chunkC chan *Chunk
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) Append(key Key, data io.Reader, chunkC chan *Chunk, storageWG, processorWG *sync.WaitGroup) (Key, error) {
|
func (c *PyramidChunker) Append(key Key, data io.Reader, chunkC chan *Chunk, storageWG, processorWG *sync.WaitGroup) (Key, error) {
|
||||||
quitC := make(chan bool)
|
quitC := make(chan bool)
|
||||||
rootKey := make([]byte, self.hashSize)
|
rootKey := make([]byte, c.hashSize)
|
||||||
chunkLevel := make([][]*TreeEntry, self.branches)
|
chunkLevel := make([][]*TreeEntry, c.branches)
|
||||||
|
|
||||||
// Load the right most unfinished tree chunks in every level
|
// Load the right most unfinished tree chunks in every level
|
||||||
self.loadTree(chunkLevel, key, chunkC, quitC)
|
c.loadTree(chunkLevel, key, chunkC, quitC)
|
||||||
|
|
||||||
jobC := make(chan *chunkJob, 2*ChunkProcessors)
|
jobC := make(chan *chunkJob, 2*ChunkProcessors)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
errC := make(chan error)
|
errC := make(chan error)
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go self.prepareChunks(true, chunkLevel, data, rootKey, quitC, wg, jobC, processorWG, chunkC, errC, storageWG)
|
go c.prepareChunks(true, chunkLevel, data, rootKey, quitC, wg, jobC, processorWG, chunkC, errC, storageWG)
|
||||||
|
|
||||||
// closes internal error channel if all subprocesses in the workgroup finished
|
// closes internal error channel if all subprocesses in the workgroup finished
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -245,10 +245,10 @@ func (self *PyramidChunker) Append(key Key, data io.Reader, chunkC chan *Chunk,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) processor(id int64, jobC chan *chunkJob, chunkC chan *Chunk, errC chan error, quitC chan bool, swg, wwg *sync.WaitGroup) {
|
func (c *PyramidChunker) processor(id int64, jobC chan *chunkJob, chunkC chan *Chunk, errC chan error, quitC chan bool, swg, wwg *sync.WaitGroup) {
|
||||||
defer self.decrementWorkerCount()
|
defer c.decrementWorkerCount()
|
||||||
|
|
||||||
hasher := self.hashFunc()
|
hasher := c.hashFunc()
|
||||||
if wwg != nil {
|
if wwg != nil {
|
||||||
defer wwg.Done()
|
defer wwg.Done()
|
||||||
}
|
}
|
||||||
|
|
@ -259,14 +259,14 @@ func (self *PyramidChunker) processor(id int64, jobC chan *chunkJob, chunkC chan
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.processChunk(id, hasher, job, chunkC, swg)
|
c.processChunk(id, hasher, job, chunkC, swg)
|
||||||
case <-quitC:
|
case <-quitC:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) processChunk(id int64, hasher SwarmHash, job *chunkJob, chunkC chan *Chunk, swg *sync.WaitGroup) {
|
func (c *PyramidChunker) processChunk(id int64, hasher SwarmHash, job *chunkJob, chunkC chan *Chunk, swg *sync.WaitGroup) {
|
||||||
hasher.ResetWithLength(job.chunk[:8]) // 8 bytes of length
|
hasher.ResetWithLength(job.chunk[:8]) // 8 bytes of length
|
||||||
hasher.Write(job.chunk[8:]) // minus 8 []byte length
|
hasher.Write(job.chunk[8:]) // minus 8 []byte length
|
||||||
h := hasher.Sum(nil)
|
h := hasher.Sum(nil)
|
||||||
|
|
@ -294,7 +294,7 @@ func (self *PyramidChunker) processChunk(id int64, hasher SwarmHash, job *chunkJ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC chan *Chunk, quitC chan bool) error {
|
func (c *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC chan *Chunk, quitC chan bool) error {
|
||||||
// Get the root chunk to get the total size
|
// Get the root chunk to get the total size
|
||||||
chunk := retrieve(key, chunkC, quitC)
|
chunk := retrieve(key, chunkC, quitC)
|
||||||
if chunk == nil {
|
if chunk == nil {
|
||||||
|
|
@ -302,13 +302,13 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC
|
||||||
}
|
}
|
||||||
|
|
||||||
//if data size is less than a chunk... add a parent with update as pending
|
//if data size is less than a chunk... add a parent with update as pending
|
||||||
if chunk.Size <= self.chunkSize {
|
if chunk.Size <= c.chunkSize {
|
||||||
newEntry := &TreeEntry{
|
newEntry := &TreeEntry{
|
||||||
level: 0,
|
level: 0,
|
||||||
branchCount: 1,
|
branchCount: 1,
|
||||||
subtreeSize: uint64(chunk.Size),
|
subtreeSize: uint64(chunk.Size),
|
||||||
chunk: make([]byte, self.chunkSize+8),
|
chunk: make([]byte, c.chunkSize+8),
|
||||||
key: make([]byte, self.hashSize),
|
key: make([]byte, c.hashSize),
|
||||||
index: 0,
|
index: 0,
|
||||||
updatePending: true,
|
updatePending: true,
|
||||||
}
|
}
|
||||||
|
|
@ -319,13 +319,13 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC
|
||||||
|
|
||||||
var treeSize int64
|
var treeSize int64
|
||||||
var depth int
|
var depth int
|
||||||
treeSize = self.chunkSize
|
treeSize = c.chunkSize
|
||||||
for ; treeSize < chunk.Size; treeSize *= self.branches {
|
for ; treeSize < chunk.Size; treeSize *= c.branches {
|
||||||
depth++
|
depth++
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the root chunk entry
|
// Add the root chunk entry
|
||||||
branchCount := int64(len(chunk.SData)-8) / self.hashSize
|
branchCount := int64(len(chunk.SData)-8) / c.hashSize
|
||||||
newEntry := &TreeEntry{
|
newEntry := &TreeEntry{
|
||||||
level: depth - 1,
|
level: depth - 1,
|
||||||
branchCount: branchCount,
|
branchCount: branchCount,
|
||||||
|
|
@ -343,14 +343,14 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC
|
||||||
//TODO(jmozah): instead of loading finished branches and then trim in the end,
|
//TODO(jmozah): instead of loading finished branches and then trim in the end,
|
||||||
//avoid loading them in the first place
|
//avoid loading them in the first place
|
||||||
for _, ent := range chunkLevel[lvl] {
|
for _, ent := range chunkLevel[lvl] {
|
||||||
branchCount = int64(len(ent.chunk)-8) / self.hashSize
|
branchCount = int64(len(ent.chunk)-8) / c.hashSize
|
||||||
for i := int64(0); i < branchCount; i++ {
|
for i := int64(0); i < branchCount; i++ {
|
||||||
key := ent.chunk[8+(i*self.hashSize) : 8+((i+1)*self.hashSize)]
|
key := ent.chunk[8+(i*c.hashSize) : 8+((i+1)*c.hashSize)]
|
||||||
newChunk := retrieve(key, chunkC, quitC)
|
newChunk := retrieve(key, chunkC, quitC)
|
||||||
if newChunk == nil {
|
if newChunk == nil {
|
||||||
return errLoadingTreeChunk
|
return errLoadingTreeChunk
|
||||||
}
|
}
|
||||||
bewBranchCount := int64(len(newChunk.SData)-8) / self.hashSize
|
bewBranchCount := int64(len(newChunk.SData)-8) / c.hashSize
|
||||||
newEntry := &TreeEntry{
|
newEntry := &TreeEntry{
|
||||||
level: lvl - 1,
|
level: lvl - 1,
|
||||||
branchCount: bewBranchCount,
|
branchCount: bewBranchCount,
|
||||||
|
|
@ -365,7 +365,7 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to get only the right most unfinished branch.. so trim all finished branches
|
// We need to get only the right most unfinished branch.. so trim all finished branches
|
||||||
if int64(len(chunkLevel[lvl-1])) >= self.branches {
|
if int64(len(chunkLevel[lvl-1])) >= c.branches {
|
||||||
chunkLevel[lvl-1] = nil
|
chunkLevel[lvl-1] = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -374,7 +374,7 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEntry, data io.Reader, rootKey []byte, quitC chan bool, wg *sync.WaitGroup, jobC chan *chunkJob, processorWG *sync.WaitGroup, chunkC chan *Chunk, errC chan error, storageWG *sync.WaitGroup) {
|
func (c *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEntry, data io.Reader, rootKey []byte, quitC chan bool, wg *sync.WaitGroup, jobC chan *chunkJob, processorWG *sync.WaitGroup, chunkC chan *Chunk, errC chan error, storageWG *sync.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
chunkWG := &sync.WaitGroup{}
|
chunkWG := &sync.WaitGroup{}
|
||||||
|
|
@ -385,10 +385,10 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
processorWG.Add(1)
|
processorWG.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.incrementWorkerCount()
|
c.incrementWorkerCount()
|
||||||
go self.processor(self.workerCount, jobC, chunkC, errC, quitC, storageWG, processorWG)
|
go c.processor(c.workerCount, jobC, chunkC, errC, quitC, storageWG, processorWG)
|
||||||
|
|
||||||
parent := NewTreeEntry(self)
|
parent := NewTreeEntry(c)
|
||||||
var unFinishedChunk *Chunk
|
var unFinishedChunk *Chunk
|
||||||
|
|
||||||
if isAppend && len(chunkLevel[0]) != 0 {
|
if isAppend && len(chunkLevel[0]) != 0 {
|
||||||
|
|
@ -396,7 +396,7 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
lastIndex := len(chunkLevel[0]) - 1
|
lastIndex := len(chunkLevel[0]) - 1
|
||||||
ent := chunkLevel[0][lastIndex]
|
ent := chunkLevel[0][lastIndex]
|
||||||
|
|
||||||
if ent.branchCount < self.branches {
|
if ent.branchCount < c.branches {
|
||||||
parent = &TreeEntry{
|
parent = &TreeEntry{
|
||||||
level: 0,
|
level: 0,
|
||||||
branchCount: ent.branchCount,
|
branchCount: ent.branchCount,
|
||||||
|
|
@ -408,10 +408,10 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBranch := parent.branchCount - 1
|
lastBranch := parent.branchCount - 1
|
||||||
lastKey := parent.chunk[8+lastBranch*self.hashSize : 8+(lastBranch+1)*self.hashSize]
|
lastKey := parent.chunk[8+lastBranch*c.hashSize : 8+(lastBranch+1)*c.hashSize]
|
||||||
|
|
||||||
unFinishedChunk = retrieve(lastKey, chunkC, quitC)
|
unFinishedChunk = retrieve(lastKey, chunkC, quitC)
|
||||||
if unFinishedChunk.Size < self.chunkSize {
|
if unFinishedChunk.Size < c.chunkSize {
|
||||||
|
|
||||||
parent.subtreeSize = parent.subtreeSize - uint64(unFinishedChunk.Size)
|
parent.subtreeSize = parent.subtreeSize - uint64(unFinishedChunk.Size)
|
||||||
parent.branchCount = parent.branchCount - 1
|
parent.branchCount = parent.branchCount - 1
|
||||||
|
|
@ -425,7 +425,7 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
|
|
||||||
var n int
|
var n int
|
||||||
var err error
|
var err error
|
||||||
chunkData := make([]byte, self.chunkSize+8)
|
chunkData := make([]byte, c.chunkSize+8)
|
||||||
if unFinishedChunk != nil {
|
if unFinishedChunk != nil {
|
||||||
copy(chunkData, unFinishedChunk.SData)
|
copy(chunkData, unFinishedChunk.SData)
|
||||||
n, err = data.Read(chunkData[8+unFinishedChunk.Size:])
|
n, err = data.Read(chunkData[8+unFinishedChunk.Size:])
|
||||||
|
|
@ -441,7 +441,7 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
if parent.branchCount == 1 {
|
if parent.branchCount == 1 {
|
||||||
// Data is exactly one chunk.. pick the last chunk key as root
|
// Data is exactly one chunk.. pick the last chunk key as root
|
||||||
chunkWG.Wait()
|
chunkWG.Wait()
|
||||||
lastChunksKey := parent.chunk[8 : 8+self.hashSize]
|
lastChunksKey := parent.chunk[8 : 8+c.hashSize]
|
||||||
copy(rootKey, lastChunksKey)
|
copy(rootKey, lastChunksKey)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -453,18 +453,18 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
|
|
||||||
// Data ended in chunk boundary.. just signal to start bulding tree
|
// Data ended in chunk boundary.. just signal to start bulding tree
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
self.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, true, rootKey)
|
c.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, true, rootKey)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
pkey := self.enqueueDataChunk(chunkData, uint64(n), parent, chunkWG, jobC, quitC)
|
pkey := c.enqueueDataChunk(chunkData, uint64(n), parent, chunkWG, jobC, quitC)
|
||||||
|
|
||||||
// update tree related parent data structures
|
// update tree related parent data structures
|
||||||
parent.subtreeSize += uint64(n)
|
parent.subtreeSize += uint64(n)
|
||||||
parent.branchCount++
|
parent.branchCount++
|
||||||
|
|
||||||
// Data got exhausted... signal to send any parent tree related chunks
|
// Data got exhausted... signal to send any parent tree related chunks
|
||||||
if int64(n) < self.chunkSize {
|
if int64(n) < c.chunkSize {
|
||||||
|
|
||||||
// only one data chunk .. so dont add any parent chunk
|
// only one data chunk .. so dont add any parent chunk
|
||||||
if parent.branchCount <= 1 {
|
if parent.branchCount <= 1 {
|
||||||
|
|
@ -473,39 +473,39 @@ func (self *PyramidChunker) prepareChunks(isAppend bool, chunkLevel [][]*TreeEnt
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
self.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, true, rootKey)
|
c.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, true, rootKey)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if parent.branchCount == self.branches {
|
if parent.branchCount == c.branches {
|
||||||
self.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, false, rootKey)
|
c.buildTree(isAppend, chunkLevel, parent, chunkWG, jobC, quitC, false, rootKey)
|
||||||
parent = NewTreeEntry(self)
|
parent = NewTreeEntry(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
workers := self.getWorkerCount()
|
workers := c.getWorkerCount()
|
||||||
if int64(len(jobC)) > workers && workers < ChunkProcessors {
|
if int64(len(jobC)) > workers && workers < ChunkProcessors {
|
||||||
if processorWG != nil {
|
if processorWG != nil {
|
||||||
processorWG.Add(1)
|
processorWG.Add(1)
|
||||||
}
|
}
|
||||||
self.incrementWorkerCount()
|
c.incrementWorkerCount()
|
||||||
go self.processor(self.workerCount, jobC, chunkC, errC, quitC, storageWG, processorWG)
|
go c.processor(c.workerCount, jobC, chunkC, errC, quitC, storageWG, processorWG)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry, ent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool, last bool, rootKey []byte) {
|
func (c *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry, ent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool, last bool, rootKey []byte) {
|
||||||
chunkWG.Wait()
|
chunkWG.Wait()
|
||||||
self.enqueueTreeChunk(chunkLevel, ent, chunkWG, jobC, quitC, last)
|
c.enqueueTreeChunk(chunkLevel, ent, chunkWG, jobC, quitC, last)
|
||||||
|
|
||||||
compress := false
|
compress := false
|
||||||
endLvl := self.branches
|
endLvl := c.branches
|
||||||
for lvl := int64(0); lvl < self.branches; lvl++ {
|
for lvl := int64(0); lvl < c.branches; lvl++ {
|
||||||
lvlCount := int64(len(chunkLevel[lvl]))
|
lvlCount := int64(len(chunkLevel[lvl]))
|
||||||
if lvlCount >= self.branches {
|
if lvlCount >= c.branches {
|
||||||
endLvl = lvl + 1
|
endLvl = lvl + 1
|
||||||
compress = true
|
compress = true
|
||||||
break
|
break
|
||||||
|
|
@ -527,9 +527,9 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for startCount := int64(0); startCount < lvlCount; startCount += self.branches {
|
for startCount := int64(0); startCount < lvlCount; startCount += c.branches {
|
||||||
|
|
||||||
endCount := startCount + self.branches
|
endCount := startCount + c.branches
|
||||||
if endCount > lvlCount {
|
if endCount > lvlCount {
|
||||||
endCount = lvlCount
|
endCount = lvlCount
|
||||||
}
|
}
|
||||||
|
|
@ -545,18 +545,18 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry,
|
||||||
level: int(lvl + 1),
|
level: int(lvl + 1),
|
||||||
branchCount: 0,
|
branchCount: 0,
|
||||||
subtreeSize: 0,
|
subtreeSize: 0,
|
||||||
chunk: make([]byte, self.chunkSize+8),
|
chunk: make([]byte, c.chunkSize+8),
|
||||||
key: make([]byte, self.hashSize),
|
key: make([]byte, c.hashSize),
|
||||||
index: int(nextLvlCount),
|
index: int(nextLvlCount),
|
||||||
updatePending: true,
|
updatePending: true,
|
||||||
}
|
}
|
||||||
for index := int64(0); index < lvlCount; index++ {
|
for index := int64(0); index < lvlCount; index++ {
|
||||||
updateEntry.branchCount++
|
updateEntry.branchCount++
|
||||||
updateEntry.subtreeSize += chunkLevel[lvl][index].subtreeSize
|
updateEntry.subtreeSize += chunkLevel[lvl][index].subtreeSize
|
||||||
copy(updateEntry.chunk[8+(index*self.hashSize):8+((index+1)*self.hashSize)], chunkLevel[lvl][index].key[:self.hashSize])
|
copy(updateEntry.chunk[8+(index*c.hashSize):8+((index+1)*c.hashSize)], chunkLevel[lvl][index].key[:c.hashSize])
|
||||||
}
|
}
|
||||||
|
|
||||||
self.enqueueTreeChunk(chunkLevel, updateEntry, chunkWG, jobC, quitC, last)
|
c.enqueueTreeChunk(chunkLevel, updateEntry, chunkWG, jobC, quitC, last)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
@ -565,8 +565,8 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry,
|
||||||
level: int(lvl + 1),
|
level: int(lvl + 1),
|
||||||
branchCount: noOfBranches,
|
branchCount: noOfBranches,
|
||||||
subtreeSize: 0,
|
subtreeSize: 0,
|
||||||
chunk: make([]byte, (noOfBranches*self.hashSize)+8),
|
chunk: make([]byte, (noOfBranches*c.hashSize)+8),
|
||||||
key: make([]byte, self.hashSize),
|
key: make([]byte, c.hashSize),
|
||||||
index: int(nextLvlCount),
|
index: int(nextLvlCount),
|
||||||
updatePending: false,
|
updatePending: false,
|
||||||
}
|
}
|
||||||
|
|
@ -575,11 +575,11 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry,
|
||||||
for i := startCount; i < endCount; i++ {
|
for i := startCount; i < endCount; i++ {
|
||||||
entry := chunkLevel[lvl][i]
|
entry := chunkLevel[lvl][i]
|
||||||
newEntry.subtreeSize += entry.subtreeSize
|
newEntry.subtreeSize += entry.subtreeSize
|
||||||
copy(newEntry.chunk[8+(index*self.hashSize):8+((index+1)*self.hashSize)], entry.key[:self.hashSize])
|
copy(newEntry.chunk[8+(index*c.hashSize):8+((index+1)*c.hashSize)], entry.key[:c.hashSize])
|
||||||
index++
|
index++
|
||||||
}
|
}
|
||||||
|
|
||||||
self.enqueueTreeChunk(chunkLevel, newEntry, chunkWG, jobC, quitC, last)
|
c.enqueueTreeChunk(chunkLevel, newEntry, chunkWG, jobC, quitC, last)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -595,7 +595,7 @@ func (self *PyramidChunker) buildTree(isAppend bool, chunkLevel [][]*TreeEntry,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) enqueueTreeChunk(chunkLevel [][]*TreeEntry, ent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool, last bool) {
|
func (c *PyramidChunker) enqueueTreeChunk(chunkLevel [][]*TreeEntry, ent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool, last bool) {
|
||||||
if ent != nil {
|
if ent != nil {
|
||||||
|
|
||||||
// wait for data chunks to get over before processing the tree chunk
|
// wait for data chunks to get over before processing the tree chunk
|
||||||
|
|
@ -604,10 +604,10 @@ func (self *PyramidChunker) enqueueTreeChunk(chunkLevel [][]*TreeEntry, ent *Tre
|
||||||
}
|
}
|
||||||
|
|
||||||
binary.LittleEndian.PutUint64(ent.chunk[:8], ent.subtreeSize)
|
binary.LittleEndian.PutUint64(ent.chunk[:8], ent.subtreeSize)
|
||||||
ent.key = make([]byte, self.hashSize)
|
ent.key = make([]byte, c.hashSize)
|
||||||
chunkWG.Add(1)
|
chunkWG.Add(1)
|
||||||
select {
|
select {
|
||||||
case jobC <- &chunkJob{ent.key, ent.chunk[:ent.branchCount*self.hashSize+8], int64(ent.subtreeSize), chunkWG, TreeChunk, 0}:
|
case jobC <- &chunkJob{ent.key, ent.chunk[:ent.branchCount*c.hashSize+8], int64(ent.subtreeSize), chunkWG, TreeChunk, 0}:
|
||||||
case <-quitC:
|
case <-quitC:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -622,9 +622,9 @@ func (self *PyramidChunker) enqueueTreeChunk(chunkLevel [][]*TreeEntry, ent *Tre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PyramidChunker) enqueueDataChunk(chunkData []byte, size uint64, parent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool) Key {
|
func (c *PyramidChunker) enqueueDataChunk(chunkData []byte, size uint64, parent *TreeEntry, chunkWG *sync.WaitGroup, jobC chan *chunkJob, quitC chan bool) Key {
|
||||||
binary.LittleEndian.PutUint64(chunkData[:8], size)
|
binary.LittleEndian.PutUint64(chunkData[:8], size)
|
||||||
pkey := parent.chunk[8+parent.branchCount*self.hashSize : 8+(parent.branchCount+1)*self.hashSize]
|
pkey := parent.chunk[8+parent.branchCount*c.hashSize : 8+(parent.branchCount+1)*c.hashSize]
|
||||||
|
|
||||||
chunkWG.Add(1)
|
chunkWG.Add(1)
|
||||||
select {
|
select {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ type HashWithLength struct {
|
||||||
hash.Hash
|
hash.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HashWithLength) ResetWithLength(length []byte) {
|
func (len *HashWithLength) ResetWithLength(length []byte) {
|
||||||
self.Reset()
|
len.Reset()
|
||||||
self.Write(length)
|
len.Write(length)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,6 @@ type LazyTestSectionReader struct {
|
||||||
*io.SectionReader
|
*io.SectionReader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LazyTestSectionReader) Size(chan bool) (int64, error) {
|
func (r *LazyTestSectionReader) Size(chan bool) (int64, error) {
|
||||||
return self.SectionReader.Size(), nil
|
return r.SectionReader.Size(), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
109
swarm/swarm.go
109
swarm/swarm.go
|
|
@ -57,7 +57,7 @@ var (
|
||||||
cacheSizeGauge = metrics.NewRegisteredGauge("storage.db.cache.size", nil)
|
cacheSizeGauge = metrics.NewRegisteredGauge("storage.db.cache.size", nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// the swarm stack
|
// Swarm stack
|
||||||
type Swarm struct {
|
type Swarm struct {
|
||||||
config *api.Config // swarm configuration
|
config *api.Config // swarm configuration
|
||||||
api *api.Api // high level api layer (fs/manifest)
|
api *api.Api // high level api layer (fs/manifest)
|
||||||
|
|
@ -82,15 +82,15 @@ type SwarmAPI struct {
|
||||||
PrvKey *ecdsa.PrivateKey
|
PrvKey *ecdsa.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Swarm) API() *SwarmAPI {
|
func (s *Swarm) API() *SwarmAPI {
|
||||||
return &SwarmAPI{
|
return &SwarmAPI{
|
||||||
Api: self.api,
|
Api: s.api,
|
||||||
Backend: self.backend,
|
Backend: s.backend,
|
||||||
PrvKey: self.privateKey,
|
PrvKey: s.privateKey,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates a new swarm service instance
|
// NewSwarm creates a new swarm service instance
|
||||||
// implements node.Service
|
// implements node.Service
|
||||||
func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.Config) (self *Swarm, err error) {
|
func NewSwarm(ctx *node.ServiceContext, backend chequebook.Backend, config *api.Config) (self *Swarm, err error) {
|
||||||
if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) {
|
if bytes.Equal(common.FromHex(config.PublicKey), storage.ZeroKey) {
|
||||||
|
|
@ -272,7 +272,7 @@ Start is called when the stack is started
|
||||||
* TODO: start subservices like sword, swear, swarmdns
|
* TODO: start subservices like sword, swear, swarmdns
|
||||||
*/
|
*/
|
||||||
// implements the node.Service interface
|
// implements the node.Service interface
|
||||||
func (self *Swarm) Start(srv *p2p.Server) error {
|
func (s *Swarm) Start(srv *p2p.Server) error {
|
||||||
startTime = time.Now()
|
startTime = time.Now()
|
||||||
connectPeer := func(url string) error {
|
connectPeer := func(url string) error {
|
||||||
node, err := discover.ParseNode(url)
|
node, err := discover.ParseNode(url)
|
||||||
|
|
@ -283,119 +283,120 @@ func (self *Swarm) Start(srv *p2p.Server) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// set chequebook
|
// set chequebook
|
||||||
if self.swapEnabled {
|
if s.swapEnabled {
|
||||||
ctx := context.Background() // The initial setup has no deadline.
|
ctx := context.Background() // The initial setup has no deadline.
|
||||||
err := self.SetChequebook(ctx)
|
err := s.SetChequebook(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Unable to set chequebook for SWAP: %v", err)
|
return fmt.Errorf("Unable to set chequebook for SWAP: %v", err)
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", self.config.Swap.Chequebook()))
|
log.Debug(fmt.Sprintf("-> cheque book for SWAP: %v", s.config.Swap.Chequebook()))
|
||||||
} else {
|
} else {
|
||||||
log.Debug(fmt.Sprintf("SWAP disabled: no cheque book set"))
|
log.Debug(fmt.Sprintf("SWAP disabled: no cheque book set"))
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warn(fmt.Sprintf("Starting Swarm service"))
|
log.Warn(fmt.Sprintf("Starting Swarm service"))
|
||||||
self.hive.Start(
|
s.hive.Start(
|
||||||
discover.PubkeyID(&srv.PrivateKey.PublicKey),
|
discover.PubkeyID(&srv.PrivateKey.PublicKey),
|
||||||
func() string { return srv.ListenAddr },
|
func() string { return srv.ListenAddr },
|
||||||
connectPeer,
|
connectPeer,
|
||||||
)
|
)
|
||||||
log.Info(fmt.Sprintf("Swarm network started on bzz address: %v", self.hive.Addr()))
|
log.Info(fmt.Sprintf("Swarm network started on bzz address: %v", s.hive.Addr()))
|
||||||
|
|
||||||
self.dpa.Start()
|
s.dpa.Start()
|
||||||
log.Debug(fmt.Sprintf("Swarm DPA started"))
|
log.Debug(fmt.Sprintf("Swarm DPA started"))
|
||||||
|
|
||||||
// start swarm http proxy server
|
// start swarm http proxy server
|
||||||
if self.config.Port != "" {
|
if s.config.Port != "" {
|
||||||
addr := net.JoinHostPort(self.config.ListenAddr, self.config.Port)
|
addr := net.JoinHostPort(s.config.ListenAddr, s.config.Port)
|
||||||
go httpapi.StartHttpServer(self.api, &httpapi.ServerConfig{
|
go httpapi.StartHttpServer(s.api, &httpapi.ServerConfig{
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
CorsString: self.corsString,
|
CorsString: s.corsString,
|
||||||
})
|
})
|
||||||
log.Info(fmt.Sprintf("Swarm http proxy started on %v", addr))
|
log.Info(fmt.Sprintf("Swarm http proxy started on %v", addr))
|
||||||
|
|
||||||
if self.corsString != "" {
|
if s.corsString != "" {
|
||||||
log.Debug(fmt.Sprintf("Swarm http proxy started with corsdomain: %v", self.corsString))
|
log.Debug(fmt.Sprintf("Swarm http proxy started with corsdomain: %v", s.corsString))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.periodicallyUpdateGauges()
|
s.periodicallyUpdateGauges()
|
||||||
|
|
||||||
startCounter.Inc(1)
|
startCounter.Inc(1)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Swarm) periodicallyUpdateGauges() {
|
func (s *Swarm) periodicallyUpdateGauges() {
|
||||||
ticker := time.NewTicker(updateGaugesPeriod)
|
ticker := time.NewTicker(updateGaugesPeriod)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
self.updateGauges()
|
s.updateGauges()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Swarm) updateGauges() {
|
func (s *Swarm) updateGauges() {
|
||||||
dbSizeGauge.Update(int64(self.lstore.DbCounter()))
|
dbSizeGauge.Update(int64(s.lstore.DbCounter()))
|
||||||
cacheSizeGauge.Update(int64(self.lstore.CacheCounter()))
|
cacheSizeGauge.Update(int64(s.lstore.CacheCounter()))
|
||||||
uptimeGauge.Update(time.Since(startTime).Nanoseconds())
|
uptimeGauge.Update(time.Since(startTime).Nanoseconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements the node.Service interface
|
// Stop implements the node.Service interface
|
||||||
// stops all component services.
|
// stops all component services.
|
||||||
func (self *Swarm) Stop() error {
|
func (s *Swarm) Stop() error {
|
||||||
self.dpa.Stop()
|
s.dpa.Stop()
|
||||||
err := self.hive.Stop()
|
err := s.hive.Stop()
|
||||||
if ch := self.config.Swap.Chequebook(); ch != nil {
|
if ch := s.config.Swap.Chequebook(); ch != nil {
|
||||||
ch.Stop()
|
ch.Stop()
|
||||||
ch.Save()
|
ch.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.lstore != nil {
|
if s.lstore != nil {
|
||||||
self.lstore.DbStore.Close()
|
s.lstore.DbStore.Close()
|
||||||
}
|
}
|
||||||
self.sfs.Stop()
|
s.sfs.Stop()
|
||||||
stopCounter.Inc(1)
|
stopCounter.Inc(1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements the node.Service interface
|
// Protocols implements the node.Service interface
|
||||||
func (self *Swarm) Protocols() []p2p.Protocol {
|
func (s *Swarm) Protocols() []p2p.Protocol {
|
||||||
proto, err := network.Bzz(self.depo, self.backend, self.hive, self.dbAccess, self.config.Swap, self.config.SyncParams, self.config.NetworkId)
|
proto, err := network.Bzz(s.depo, s.backend, s.hive, s.dbAccess, s.config.Swap, s.config.SyncParams, s.config.NetworkId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return []p2p.Protocol{proto}
|
return []p2p.Protocol{proto}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// APIs returns the RPC Api descriptors the Swarm implementation offers
|
||||||
// implements node.Service
|
// implements node.Service
|
||||||
// Apis returns the RPC Api descriptors the Swarm implementation offers
|
func (s *Swarm) APIs() []rpc.API {
|
||||||
func (self *Swarm) APIs() []rpc.API {
|
|
||||||
return []rpc.API{
|
return []rpc.API{
|
||||||
// public APIs
|
// public APIs
|
||||||
{
|
{
|
||||||
Namespace: "bzz",
|
Namespace: "bzz",
|
||||||
Version: "0.1",
|
Version: "0.1",
|
||||||
Service: &Info{self.config, chequebook.ContractParams},
|
Service: &Info{s.config, chequebook.ContractParams},
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
// admin APIs
|
// admin APIs
|
||||||
{
|
{
|
||||||
Namespace: "bzz",
|
Namespace: "bzz",
|
||||||
Version: "0.1",
|
Version: "0.1",
|
||||||
Service: api.NewControl(self.api, self.hive),
|
Service: api.NewControl(s.api, s.hive),
|
||||||
Public: false,
|
Public: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Namespace: "chequebook",
|
Namespace: "chequebook",
|
||||||
Version: chequebook.Version,
|
Version: chequebook.Version,
|
||||||
Service: chequebook.NewApi(self.config.Swap.Chequebook),
|
Service: chequebook.NewApi(s.config.Swap.Chequebook),
|
||||||
Public: false,
|
Public: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Namespace: "swarmfs",
|
Namespace: "swarmfs",
|
||||||
Version: fuse.Swarmfs_Version,
|
Version: fuse.Swarmfs_Version,
|
||||||
Service: self.sfs,
|
Service: s.sfs,
|
||||||
Public: false,
|
Public: false,
|
||||||
},
|
},
|
||||||
// storage APIs
|
// storage APIs
|
||||||
|
|
@ -403,35 +404,35 @@ func (self *Swarm) APIs() []rpc.API {
|
||||||
{
|
{
|
||||||
Namespace: "bzz",
|
Namespace: "bzz",
|
||||||
Version: "0.1",
|
Version: "0.1",
|
||||||
Service: api.NewStorage(self.api),
|
Service: api.NewStorage(s.api),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Namespace: "bzz",
|
Namespace: "bzz",
|
||||||
Version: "0.1",
|
Version: "0.1",
|
||||||
Service: api.NewFileSystem(self.api),
|
Service: api.NewFileSystem(s.api),
|
||||||
Public: false,
|
Public: false,
|
||||||
},
|
},
|
||||||
// {Namespace, Version, api.NewAdmin(self), false},
|
// {Namespace, Version, api.NewAdmin(s), false},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Swarm) Api() *api.Api {
|
func (s *Swarm) Api() *api.Api {
|
||||||
return self.api
|
return s.api
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetChequebook ensures that the local checquebook is set up on chain.
|
// SetChequebook ensures that the local checquebook is set up on chain.
|
||||||
func (self *Swarm) SetChequebook(ctx context.Context) error {
|
func (s *Swarm) SetChequebook(ctx context.Context) error {
|
||||||
err := self.config.Swap.SetChequebook(ctx, self.backend, self.config.Path)
|
err := s.config.Swap.SetChequebook(ctx, s.backend, s.config.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", self.config.Swap.Contract.Hex()))
|
log.Info(fmt.Sprintf("new chequebook set (%v): saving config file, resetting all connections in the hive", s.config.Swap.Contract.Hex()))
|
||||||
self.hive.DropAll()
|
s.hive.DropAll()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local swarm without netStore
|
// NewLocalSwarm without netStore
|
||||||
func NewLocalSwarm(datadir, port string) (self *Swarm, err error) {
|
func NewLocalSwarm(datadir, port string) (self *Swarm, err error) {
|
||||||
|
|
||||||
prvKey, err := crypto.GenerateKey()
|
prvKey, err := crypto.GenerateKey()
|
||||||
|
|
@ -463,6 +464,6 @@ type Info struct {
|
||||||
*chequebook.Params
|
*chequebook.Params
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Info) Info() *Info {
|
func (info *Info) Info() *Info {
|
||||||
return self
|
return info
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue