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_CAPACITY = "SWARM_STORE_CAPACITY"
SWARM_ENV_STORE_CACHE_CAPACITY = "SWARM_STORE_CACHE_CAPACITY" SWARM_ENV_STORE_CACHE_CAPACITY = "SWARM_STORE_CACHE_CAPACITY"
SWARM_ENV_BOOTNODE_MODE = "SWARM_BOOTNODE_MODE" SWARM_ENV_BOOTNODE_MODE = "SWARM_BOOTNODE_MODE"
SWARM_ENV_DEBUG_API = "SWARM_DEBUG_API"
SWARM_ACCESS_PASSWORD = "SWARM_ACCESS_PASSWORD" SWARM_ACCESS_PASSWORD = "SWARM_ACCESS_PASSWORD"
SWARM_AUTO_DEFAULTPATH = "SWARM_AUTO_DEFAULTPATH" SWARM_AUTO_DEFAULTPATH = "SWARM_AUTO_DEFAULTPATH"
GETH_ENV_DATADIR = "GETH_DATADIR" 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) currentConfig.BootnodeMode = ctx.GlobalBool(SwarmBootnodeModeFlag.Name)
} }
if ctx.GlobalIsSet(SwarmDebugAPIFlag.Name) {
currentConfig.DebugAPI = ctx.GlobalBool(SwarmDebugAPIFlag.Name)
}
return currentConfig return currentConfig
} }
@ -375,6 +380,14 @@ func envVarsOverride(currentConfig *bzzapi.Config) (config *bzzapi.Config) {
currentConfig.BootnodeMode = bootnodeMode 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 return currentConfig
} }

View file

@ -176,4 +176,8 @@ var (
Name: "user", Name: "user",
Usage: "Indicates the user who updates the feed", 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, SwarmStorePath,
SwarmStoreCapacity, SwarmStoreCapacity,
SwarmStoreCacheCapacity, SwarmStoreCacheCapacity,
// provide debug API endpoints
SwarmDebugAPIFlag,
} }
rpcFlags := []cli.Flag{ rpcFlags := []cli.Flag{
utils.WSEnabledFlag, utils.WSEnabledFlag,

View file

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

View file

@ -17,7 +17,11 @@
package api package api
import ( import (
"context"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/swarm/network" "github.com/ethereum/go-ethereum/swarm/network"
"github.com/ethereum/go-ethereum/swarm/storage"
) )
type Control struct { type Control struct {
@ -32,3 +36,30 @@ func NewControl(api *API, hive *network.Hive) *Control {
func (c *Control) Hive() string { func (c *Control) Hive() string {
return c.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 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() { 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) 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 // 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) { func (s *LDBStore) get(addr Address) (chunk *chunk, err error) {
if s.closed { if s.closed {

View file

@ -132,6 +132,13 @@ func (ls *LocalStore) Put(ctx context.Context, chunk Chunk) error {
return err 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 // Get(chunk *Chunk) 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

View file

@ -209,3 +209,36 @@ func setupLocalStore(t *testing.T, ldbCap int) (ls *LocalStore, cleanup func())
return store, cleanup 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) { func (m *MemStore) Get(_ context.Context, addr Address) (Chunk, error) {
if m.disabled { if m.disabled {
return nil, ErrChunkNotFound 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 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 // getOrCreateFetcher attempts at retrieving an existing fetchers
// if none exists, creates one and saves it in the fetchers cache // if none exists, creates one and saves it in the fetchers cache
// caller must hold the lock // caller must hold the lock

View file

@ -292,6 +292,7 @@ func (v *ContentAddressValidator) Validate(chunk Chunk) bool {
type ChunkStore interface { type ChunkStore interface {
Put(ctx context.Context, ch Chunk) (err error) Put(ctx context.Context, ch Chunk) (err error)
Get(rctx context.Context, ref Address) (ch Chunk, err error) Get(rctx context.Context, ref Address) (ch Chunk, err error)
HasChunk(rctx context.Context, ref Address) bool
Close() Close()
} }
@ -314,7 +315,12 @@ func (f *FakeChunkStore) Put(_ context.Context, ch Chunk) error {
return nil 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) { func (f *FakeChunkStore) Get(_ context.Context, ref Address) (Chunk, error) {
panic("FakeChunkStore doesn't support Get") panic("FakeChunkStore doesn't support Get")
} }

View file

@ -514,6 +514,11 @@ func (self *Swarm) APIs() []rpc.API {
apis = append(apis, self.ps.APIs()...) 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 return apis
} }