swarm: first version of HasChunk implementation

This commit is contained in:
Fabio Barone 2019-01-31 19:29:02 -05:00
parent a89170cfb2
commit b15960d933
13 changed files with 130 additions and 1 deletions

View file

@ -80,6 +80,7 @@ const (
SWARM_ENV_STORE_CAPACITY = "SWARM_STORE_CAPACITY"
SWARM_ENV_STORE_CACHE_CAPACITY = "SWARM_STORE_CACHE_CAPACITY"
SWARM_ENV_BOOTNODE_MODE = "SWARM_BOOTNODE_MODE"
SWARM_ENV_DEBUG_API = "SWARM_DEBUG_API"
SWARM_ACCESS_PASSWORD = "SWARM_ACCESS_PASSWORD"
SWARM_AUTO_DEFAULTPATH = "SWARM_AUTO_DEFAULTPATH"
GETH_ENV_DATADIR = "GETH_DATADIR"
@ -262,6 +263,10 @@ func cmdLineOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Con
currentConfig.BootnodeMode = ctx.GlobalBool(SwarmBootnodeModeFlag.Name)
}
if ctx.GlobalIsSet(SwarmDebugAPIFlag.Name) {
currentConfig.DebugAPI = ctx.GlobalBool(SwarmDebugAPIFlag.Name)
}
return currentConfig
}
@ -375,6 +380,14 @@ func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) {
currentConfig.BootnodeMode = bootnodeMode
}
if debugAPIenable := os.Getenv(SWARM_ENV_DEBUG_API); debugAPIenable != "" {
debug, err := strconv.ParseBool(debugAPIenable)
if err != nil {
utils.Fatalf("invalid environment variable %s: %v", SWARM_ENV_DEBUG_API, err)
}
currentConfig.DebugAPI = debug
}
return currentConfig
}

View file

@ -176,4 +176,8 @@ var (
Name: "user",
Usage: "Indicates the user who updates the feed",
}
SwarmDebugAPIFlag = cli.BoolFlag{
Name: "debug-api",
Usage: "Make debug APIs available",
}
)

View file

@ -194,6 +194,8 @@ func init() {
SwarmStorePath,
SwarmStoreCapacity,
SwarmStoreCacheCapacity,
// provide debug API endpoints
SwarmDebugAPIFlag,
}
rpcFlags := []cli.Flag{
utils.WSEnabledFlag,

View file

@ -60,6 +60,7 @@ type Config struct {
BzzKey string
NodeID string
NetworkID uint64
DebugAPI bool
SwapEnabled bool
SyncEnabled bool
SyncingSkipCheck bool
@ -90,6 +91,7 @@ func NewConfig() (c *Config) {
EnsAPIs: nil,
EnsRoot: ens.TestNetAddress,
NetworkID: network.DefaultNetworkID,
DebugAPI: false,
SwapEnabled: false,
SyncEnabled: true,
SyncingSkipCheck: false,

View file

@ -17,7 +17,11 @@
package api
import (
"context"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/swarm/network"
"github.com/ethereum/go-ethereum/swarm/storage"
)
type Control struct {
@ -32,3 +36,30 @@ func NewControl(api *API, hive *network.Hive) *Control {
func (c *Control) Hive() string {
return c.hive.String()
}
type DebugAPI struct {
netStore *storage.NetStore
}
func NewDebugAPI(nstore *storage.NetStore) *DebugAPI {
return &DebugAPI{
netStore: nstore,
}
}
func (dapi *DebugAPI) String() string {
return "debugapi"
}
func (dapi *DebugAPI) HasChunk(chunkAddress storage.Address) bool {
return dapi.netStore.HasChunk(context.Background(), chunkAddress)
}
func GetDebugAPIDesc(nstore *storage.NetStore) rpc.API {
return rpc.API{
Namespace: "debugapi",
Version: "1.0",
Service: NewDebugAPI(nstore),
Public: false,
}
}

View file

@ -266,6 +266,14 @@ func (m *MapChunkStore) Get(_ context.Context, ref Address) (Chunk, error) {
return chunk, nil
}
func (m *MapChunkStore) HasChunk(ctx context.Context, ref Address) bool {
m.mu.RLock()
defer m.mu.RUnlock()
_, has := m.chunks[ref.Hex()]
return has
}
func (m *MapChunkStore) Close() {
}

View file

@ -969,6 +969,16 @@ func (s *LDBStore) Get(_ context.Context, addr Address) (chunk Chunk, err error)
return s.get(addr)
}
// HasChunk queries the underlying DB if a chunk with the given address is stored
// Returns true if the chunk is found, false if not
func (s *LDBStore) HasChunk(_ context.Context, addr Address) bool {
s.lock.RLock()
defer s.lock.RUnlock()
proximity := s.po(addr)
_, found := s.tryAccessIdx(addr, proximity)
return found
}
// TODO: To conform with other private methods of this object indices should not be updated
func (s *LDBStore) get(addr Address) (chunk *chunk, err error) {
if s.closed {

View file

@ -132,6 +132,13 @@ func (ls *LocalStore) Put(ctx context.Context, chunk Chunk) error {
return err
}
// HasChunk queries the underlying DbStore if a chunk with the given address
// is being stored there.
// Returns true if it is stored, false if not
func (ls *LocalStore) HasChunk(ctx context.Context, addr Address) bool {
return ls.DbStore.HasChunk(ctx, addr)
}
// Get(chunk *Chunk) looks up a chunk in the local stores
// This method is blocking until the chunk is retrieved
// so additional timeout may be needed to wrap this call if

View file

@ -209,3 +209,36 @@ func setupLocalStore(t *testing.T, ldbCap int) (ls *LocalStore, cleanup func())
return store, cleanup
}
func TestHasChunk(t *testing.T) {
ldbCap := defaultGCRatio
store, cleanup := setupLocalStore(t, ldbCap)
defer cleanup()
nonStoredAddr := GenerateRandomChunk(128).Address()
has := store.HasChunk(context.Background(), nonStoredAddr)
if has {
t.Fatal("Expected HasChunk() to return false, but returned true!")
}
storeChunks := GenerateRandomChunks(128, 3)
for _, ch := range storeChunks {
err := store.Put(context.Background(), ch)
if err != nil {
t.Fatalf("Expected store to store chunk, but it failed: %v", err)
}
has := store.HasChunk(context.Background(), ch.Address())
if !has {
t.Fatal("Expected HasChunk() to return true, but returned false!")
}
}
//let's be paranoic and test again that the non-existent chunk returns false
has = store.HasChunk(context.Background(), nonStoredAddr)
if has {
t.Fatal("Expected HasChunk() to return false, but returned true!")
}
}

View file

@ -48,6 +48,10 @@ func NewMemStore(params *StoreParams, _ *LDBStore) (m *MemStore) {
}
}
func (m *MemStore) HasChunk(_ context.Context, addr Address) bool {
return m.cache.Contains(addr)
}
func (m *MemStore) Get(_ context.Context, addr Address) (Chunk, error) {
if m.disabled {
return nil, ErrChunkNotFound

View file

@ -158,6 +158,10 @@ func (n *NetStore) get(ctx context.Context, ref Address) (Chunk, func(context.Co
return chunk, nil, nil
}
func (n *NetStore) HasChunk(ctx context.Context, ref Address) bool {
return n.store.HasChunk(ctx, ref)
}
// getOrCreateFetcher attempts at retrieving an existing fetchers
// if none exists, creates one and saves it in the fetchers cache
// caller must hold the lock

View file

@ -292,6 +292,7 @@ func (v *ContentAddressValidator) Validate(chunk Chunk) bool {
type ChunkStore interface {
Put(ctx context.Context, ch Chunk) (err error)
Get(rctx context.Context, ref Address) (ch Chunk, err error)
HasChunk(rctx context.Context, ref Address) bool
Close()
}
@ -314,7 +315,12 @@ func (f *FakeChunkStore) Put(_ context.Context, ch Chunk) error {
return nil
}
// Gut doesn't store anything it is just here to implement ChunkStore
// HasChunk doesn't do anything it is just here to implement ChunkStore
func (f *FakeChunkStore) HasChunk(_ context.Context, ref Address) bool {
panic("FakeChunkStore doesn't support HasChunk")
}
// Get doesn't store anything it is just here to implement ChunkStore
func (f *FakeChunkStore) Get(_ context.Context, ref Address) (Chunk, error) {
panic("FakeChunkStore doesn't support Get")
}

View file

@ -514,6 +514,11 @@ func (self *Swarm) APIs() []rpc.API {
apis = append(apis, self.ps.APIs()...)
}
if self.config.DebugAPI {
log.Info("Running node with debug APIs attached")
apis = append(apis, api.GetDebugAPIDesc(self.netStore))
}
return apis
}