Commit 1ca2d428 authored by Jeromy Johnson's avatar Jeromy Johnson Committed by GitHub

Merge pull request #3348 from ipfs/kevina/gclocker

Separate out the G.C. Locking from the Blockstore interface.
parents 9d132e70 ffe9d7da
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
var exampleBlock = blocks.NewBlock([]byte("foo")) var exampleBlock = blocks.NewBlock([]byte("foo"))
func testArcCached(bs GCBlockstore, ctx context.Context) (*arccache, error) { func testArcCached(bs Blockstore, ctx context.Context) (*arccache, error) {
if ctx == nil { if ctx == nil {
ctx = context.TODO() ctx = context.TODO()
} }
......
...@@ -39,9 +39,7 @@ type Blockstore interface { ...@@ -39,9 +39,7 @@ type Blockstore interface {
AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error)
} }
type GCBlockstore interface { type GCLocker interface {
Blockstore
// GCLock locks the blockstore for garbage collection. No operations // GCLock locks the blockstore for garbage collection. No operations
// that expect to finish with a pin should ocurr simultaneously. // that expect to finish with a pin should ocurr simultaneously.
// Reading during GC is safe, and requires no lock. // Reading during GC is safe, and requires no lock.
...@@ -58,6 +56,20 @@ type GCBlockstore interface { ...@@ -58,6 +56,20 @@ type GCBlockstore interface {
GCRequested() bool GCRequested() bool
} }
type GCBlockstore interface {
Blockstore
GCLocker
}
func NewGCBlockstore(bs Blockstore, gcl GCLocker) GCBlockstore {
return gcBlockstore{bs, gcl}
}
type gcBlockstore struct {
Blockstore
GCLocker
}
func NewBlockstore(d ds.Batching) *blockstore { func NewBlockstore(d ds.Batching) *blockstore {
var dsb ds.Batching var dsb ds.Batching
dd := dsns.Wrap(d, BlockPrefix) dd := dsns.Wrap(d, BlockPrefix)
...@@ -223,6 +235,16 @@ func (bs *blockstore) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) ...@@ -223,6 +235,16 @@ func (bs *blockstore) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error)
return output, nil return output, nil
} }
func NewGCLocker() *gclocker {
return &gclocker{}
}
type gclocker struct {
lk sync.RWMutex
gcreq int32
gcreqlk sync.Mutex
}
type Unlocker interface { type Unlocker interface {
Unlock() Unlock()
} }
...@@ -236,18 +258,18 @@ func (u *unlocker) Unlock() { ...@@ -236,18 +258,18 @@ func (u *unlocker) Unlock() {
u.unlock = nil // ensure its not called twice u.unlock = nil // ensure its not called twice
} }
func (bs *blockstore) GCLock() Unlocker { func (bs *gclocker) GCLock() Unlocker {
atomic.AddInt32(&bs.gcreq, 1) atomic.AddInt32(&bs.gcreq, 1)
bs.lk.Lock() bs.lk.Lock()
atomic.AddInt32(&bs.gcreq, -1) atomic.AddInt32(&bs.gcreq, -1)
return &unlocker{bs.lk.Unlock} return &unlocker{bs.lk.Unlock}
} }
func (bs *blockstore) PinLock() Unlocker { func (bs *gclocker) PinLock() Unlocker {
bs.lk.RLock() bs.lk.RLock()
return &unlocker{bs.lk.RUnlock} return &unlocker{bs.lk.RUnlock}
} }
func (bs *blockstore) GCRequested() bool { func (bs *gclocker) GCRequested() bool {
return atomic.LoadInt32(&bs.gcreq) > 0 return atomic.LoadInt32(&bs.gcreq) > 0
} }
...@@ -14,7 +14,7 @@ import ( ...@@ -14,7 +14,7 @@ import (
syncds "gx/ipfs/QmbzuUusHqaLLoNTDEVLcSF6vZDHZDLPC7p4bztRvvkXxU/go-datastore/sync" syncds "gx/ipfs/QmbzuUusHqaLLoNTDEVLcSF6vZDHZDLPC7p4bztRvvkXxU/go-datastore/sync"
) )
func testBloomCached(bs GCBlockstore, ctx context.Context) (*bloomcache, error) { func testBloomCached(bs Blockstore, ctx context.Context) (*bloomcache, error) {
if ctx == nil { if ctx == nil {
ctx = context.TODO() ctx = context.TODO()
} }
......
...@@ -22,8 +22,8 @@ func DefaultCacheOpts() CacheOpts { ...@@ -22,8 +22,8 @@ func DefaultCacheOpts() CacheOpts {
} }
} }
func CachedBlockstore(bs GCBlockstore, func CachedBlockstore(bs Blockstore,
ctx context.Context, opts CacheOpts) (cbs GCBlockstore, err error) { ctx context.Context, opts CacheOpts) (cbs Blockstore, err error) {
cbs = bs cbs = bs
if opts.HasBloomFilterSize < 0 || opts.HasBloomFilterHashes < 0 || if opts.HasBloomFilterSize < 0 || opts.HasBloomFilterHashes < 0 ||
......
...@@ -36,14 +36,14 @@ func TestWriteThroughWorks(t *testing.T) { ...@@ -36,14 +36,14 @@ func TestWriteThroughWorks(t *testing.T) {
} }
} }
var _ blockstore.GCBlockstore = (*PutCountingBlockstore)(nil) var _ blockstore.Blockstore = (*PutCountingBlockstore)(nil)
type PutCountingBlockstore struct { type PutCountingBlockstore struct {
blockstore.GCBlockstore blockstore.Blockstore
PutCounter int PutCounter int
} }
func (bs *PutCountingBlockstore) Put(block blocks.Block) error { func (bs *PutCountingBlockstore) Put(block blocks.Block) error {
bs.PutCounter++ bs.PutCounter++
return bs.GCBlockstore.Put(block) return bs.Blockstore.Put(block)
} }
...@@ -179,11 +179,13 @@ func setupNode(ctx context.Context, n *IpfsNode, cfg *BuildCfg) error { ...@@ -179,11 +179,13 @@ func setupNode(ctx context.Context, n *IpfsNode, cfg *BuildCfg) error {
opts.HasBloomFilterSize = 0 opts.HasBloomFilterSize = 0
} }
n.Blockstore, err = bstore.CachedBlockstore(bs, ctx, opts) cbs, err := bstore.CachedBlockstore(bs, ctx, opts)
if err != nil { if err != nil {
return err return err
} }
n.Blockstore = bstore.NewGCBlockstore(cbs, bstore.NewGCLocker())
rcfg, err := n.Repo.Config() rcfg, err := n.Repo.Config()
if err != nil { if err != nil {
return err return err
......
...@@ -22,7 +22,7 @@ import ( ...@@ -22,7 +22,7 @@ import (
"gx/ipfs/QmbzuUusHqaLLoNTDEVLcSF6vZDHZDLPC7p4bztRvvkXxU/go-datastore/sync" "gx/ipfs/QmbzuUusHqaLLoNTDEVLcSF6vZDHZDLPC7p4bztRvvkXxU/go-datastore/sync"
) )
func getMockDagServAndBstore(t testing.TB) (mdag.DAGService, blockstore.GCBlockstore) { func getMockDagServAndBstore(t testing.TB) (mdag.DAGService, blockstore.Blockstore) {
dstore := ds.NewMapDatastore() dstore := ds.NewMapDatastore()
tsds := sync.MutexWrap(dstore) tsds := sync.MutexWrap(dstore)
bstore := blockstore.NewBlockstore(tsds) bstore := blockstore.NewBlockstore(tsds)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment