Unverified Commit 47b99b1c authored by dirkmc's avatar dirkmc Committed by GitHub

feat: configurable engine blockstore worker count (#449)

parent 95cb1a00
...@@ -5,6 +5,7 @@ package bitswap ...@@ -5,6 +5,7 @@ package bitswap
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"sync" "sync"
"time" "time"
...@@ -45,6 +46,9 @@ const ( ...@@ -45,6 +46,9 @@ const (
// these requests take at _least_ two minutes at the moment. // these requests take at _least_ two minutes at the moment.
provideTimeout = time.Minute * 3 provideTimeout = time.Minute * 3
defaultProvSearchDelay = time.Second defaultProvSearchDelay = time.Second
// Number of concurrent workers in decision engine that process requests to the blockstore
defaulEngineBlockstoreWorkerCount = 128
) )
var ( var (
...@@ -85,6 +89,17 @@ func RebroadcastDelay(newRebroadcastDelay delay.D) Option { ...@@ -85,6 +89,17 @@ func RebroadcastDelay(newRebroadcastDelay delay.D) Option {
} }
} }
// EngineBlockstoreWorkerCount sets the number of worker threads used for
// blockstore operations in the decision engine
func EngineBlockstoreWorkerCount(count int) Option {
if count <= 0 {
panic(fmt.Sprintf("Engine blockstore worker count is %d but must be > 0", count))
}
return func(bs *Bitswap) {
bs.engineBstoreWorkerCount = count
}
}
// SetSendDontHaves indicates what to do when the engine receives a want-block // SetSendDontHaves indicates what to do when the engine receives a want-block
// for a block that is not in the blockstore. Either // for a block that is not in the blockstore. Either
// - Send a DONT_HAVE message // - Send a DONT_HAVE message
...@@ -99,7 +114,7 @@ func SetSendDontHaves(send bool) Option { ...@@ -99,7 +114,7 @@ func SetSendDontHaves(send bool) Option {
// Configures the engine to use the given score decision logic. // Configures the engine to use the given score decision logic.
func WithScoreLedger(scoreLedger deciface.ScoreLedger) Option { func WithScoreLedger(scoreLedger deciface.ScoreLedger) Option {
return func(bs *Bitswap) { return func(bs *Bitswap) {
bs.engine.UseScoreLedger(scoreLedger) bs.engineScoreLedger = scoreLedger
} }
} }
...@@ -166,27 +181,26 @@ func New(parent context.Context, network bsnet.BitSwapNetwork, ...@@ -166,27 +181,26 @@ func New(parent context.Context, network bsnet.BitSwapNetwork,
} }
notif := notifications.New() notif := notifications.New()
sm = bssm.New(ctx, sessionFactory, sim, sessionPeerManagerFactory, bpm, pm, notif, network.Self()) sm = bssm.New(ctx, sessionFactory, sim, sessionPeerManagerFactory, bpm, pm, notif, network.Self())
engine := decision.NewEngine(ctx, bstore, network.ConnectionManager(), network.Self())
bs := &Bitswap{ bs := &Bitswap{
blockstore: bstore, blockstore: bstore,
engine: engine,
network: network, network: network,
process: px, process: px,
newBlocks: make(chan cid.Cid, HasBlockBufferSize), newBlocks: make(chan cid.Cid, HasBlockBufferSize),
provideKeys: make(chan cid.Cid, provideKeysBufferSize), provideKeys: make(chan cid.Cid, provideKeysBufferSize),
pm: pm, pm: pm,
pqm: pqm, pqm: pqm,
sm: sm, sm: sm,
sim: sim, sim: sim,
notif: notif, notif: notif,
counters: new(counters), counters: new(counters),
dupMetric: dupHist, dupMetric: dupHist,
allMetric: allHist, allMetric: allHist,
sentHistogram: sentHistogram, sentHistogram: sentHistogram,
provideEnabled: true, provideEnabled: true,
provSearchDelay: defaultProvSearchDelay, provSearchDelay: defaultProvSearchDelay,
rebroadcastDelay: delay.Fixed(time.Minute), rebroadcastDelay: delay.Fixed(time.Minute),
engineBstoreWorkerCount: defaulEngineBlockstoreWorkerCount,
} }
// apply functional options before starting and running bitswap // apply functional options before starting and running bitswap
...@@ -194,12 +208,15 @@ func New(parent context.Context, network bsnet.BitSwapNetwork, ...@@ -194,12 +208,15 @@ func New(parent context.Context, network bsnet.BitSwapNetwork,
option(bs) option(bs)
} }
// Set up decision engine
bs.engine = decision.NewEngine(bstore, bs.engineBstoreWorkerCount, network.ConnectionManager(), network.Self(), bs.engineScoreLedger)
bs.pqm.Startup() bs.pqm.Startup()
network.SetDelegate(bs) network.SetDelegate(bs)
// Start up bitswaps async worker routines // Start up bitswaps async worker routines
bs.startWorkers(ctx, px) bs.startWorkers(ctx, px)
engine.StartWorkers(ctx, px) bs.engine.StartWorkers(ctx, px)
// bind the context and process. // bind the context and process.
// do it over here to avoid closing before all setup is done. // do it over here to avoid closing before all setup is done.
...@@ -270,6 +287,12 @@ type Bitswap struct { ...@@ -270,6 +287,12 @@ type Bitswap struct {
// how often to rebroadcast providing requests to find more optimized providers // how often to rebroadcast providing requests to find more optimized providers
rebroadcastDelay delay.D rebroadcastDelay delay.D
// how many worker threads to start for decision engine blockstore worker
engineBstoreWorkerCount int
// the score ledger used by the decision engine
engineScoreLedger deciface.ScoreLedger
} }
type counters struct { type counters struct {
......
...@@ -21,7 +21,7 @@ type blockstoreManager struct { ...@@ -21,7 +21,7 @@ type blockstoreManager struct {
// newBlockstoreManager creates a new blockstoreManager with the given context // newBlockstoreManager creates a new blockstoreManager with the given context
// and number of workers // and number of workers
func newBlockstoreManager(ctx context.Context, bs bstore.Blockstore, workerCount int) *blockstoreManager { func newBlockstoreManager(bs bstore.Blockstore, workerCount int) *blockstoreManager {
return &blockstoreManager{ return &blockstoreManager{
bs: bs, bs: bs,
workerCount: workerCount, workerCount: workerCount,
......
...@@ -25,7 +25,7 @@ func TestBlockstoreManagerNotFoundKey(t *testing.T) { ...@@ -25,7 +25,7 @@ func TestBlockstoreManagerNotFoundKey(t *testing.T) {
dstore := ds_sync.MutexWrap(delayed.New(ds.NewMapDatastore(), bsdelay)) dstore := ds_sync.MutexWrap(delayed.New(ds.NewMapDatastore(), bsdelay))
bstore := blockstore.NewBlockstore(ds_sync.MutexWrap(dstore)) bstore := blockstore.NewBlockstore(ds_sync.MutexWrap(dstore))
bsm := newBlockstoreManager(ctx, bstore, 5) bsm := newBlockstoreManager(bstore, 5)
bsm.start(process.WithTeardown(func() error { return nil })) bsm.start(process.WithTeardown(func() error { return nil }))
cids := testutil.GenerateCids(4) cids := testutil.GenerateCids(4)
...@@ -64,7 +64,7 @@ func TestBlockstoreManager(t *testing.T) { ...@@ -64,7 +64,7 @@ func TestBlockstoreManager(t *testing.T) {
dstore := ds_sync.MutexWrap(delayed.New(ds.NewMapDatastore(), bsdelay)) dstore := ds_sync.MutexWrap(delayed.New(ds.NewMapDatastore(), bsdelay))
bstore := blockstore.NewBlockstore(ds_sync.MutexWrap(dstore)) bstore := blockstore.NewBlockstore(ds_sync.MutexWrap(dstore))
bsm := newBlockstoreManager(ctx, bstore, 5) bsm := newBlockstoreManager(bstore, 5)
bsm.start(process.WithTeardown(func() error { return nil })) bsm.start(process.WithTeardown(func() error { return nil }))
exp := make(map[cid.Cid]blocks.Block) exp := make(map[cid.Cid]blocks.Block)
...@@ -148,7 +148,7 @@ func TestBlockstoreManagerConcurrency(t *testing.T) { ...@@ -148,7 +148,7 @@ func TestBlockstoreManagerConcurrency(t *testing.T) {
bstore := blockstore.NewBlockstore(ds_sync.MutexWrap(dstore)) bstore := blockstore.NewBlockstore(ds_sync.MutexWrap(dstore))
workerCount := 5 workerCount := 5
bsm := newBlockstoreManager(ctx, bstore, workerCount) bsm := newBlockstoreManager(bstore, workerCount)
bsm.start(process.WithTeardown(func() error { return nil })) bsm.start(process.WithTeardown(func() error { return nil }))
blkSize := int64(8 * 1024) blkSize := int64(8 * 1024)
...@@ -190,7 +190,7 @@ func TestBlockstoreManagerClose(t *testing.T) { ...@@ -190,7 +190,7 @@ func TestBlockstoreManagerClose(t *testing.T) {
dstore := ds_sync.MutexWrap(delayed.New(ds.NewMapDatastore(), bsdelay)) dstore := ds_sync.MutexWrap(delayed.New(ds.NewMapDatastore(), bsdelay))
bstore := blockstore.NewBlockstore(ds_sync.MutexWrap(dstore)) bstore := blockstore.NewBlockstore(ds_sync.MutexWrap(dstore))
bsm := newBlockstoreManager(ctx, bstore, 3) bsm := newBlockstoreManager(bstore, 3)
px := process.WithTeardown(func() error { return nil }) px := process.WithTeardown(func() error { return nil })
bsm.start(px) bsm.start(px)
...@@ -227,7 +227,7 @@ func TestBlockstoreManagerCtxDone(t *testing.T) { ...@@ -227,7 +227,7 @@ func TestBlockstoreManagerCtxDone(t *testing.T) {
dstore := ds_sync.MutexWrap(delayed.New(ds.NewMapDatastore(), bsdelay)) dstore := ds_sync.MutexWrap(delayed.New(ds.NewMapDatastore(), bsdelay))
bstore := blockstore.NewBlockstore(ds_sync.MutexWrap(dstore)) bstore := blockstore.NewBlockstore(ds_sync.MutexWrap(dstore))
bsm := newBlockstoreManager(context.Background(), bstore, 3) bsm := newBlockstoreManager(bstore, 3)
proc := process.WithTeardown(func() error { return nil }) proc := process.WithTeardown(func() error { return nil })
bsm.start(proc) bsm.start(proc)
......
...@@ -76,9 +76,6 @@ const ( ...@@ -76,9 +76,6 @@ const (
// Number of concurrent workers that pull tasks off the request queue // Number of concurrent workers that pull tasks off the request queue
taskWorkerCount = 8 taskWorkerCount = 8
// Number of concurrent workers that process requests to the blockstore
blockstoreWorkerCount = 128
) )
// Envelope contains a message for a Peer. // Envelope contains a message for a Peer.
...@@ -166,16 +163,16 @@ type Engine struct { ...@@ -166,16 +163,16 @@ type Engine struct {
sendDontHaves bool sendDontHaves bool
self peer.ID self peer.ID
} }
// NewEngine creates a new block sending engine for the given block store // NewEngine creates a new block sending engine for the given block store
func NewEngine(ctx context.Context, bs bstore.Blockstore, peerTagger PeerTagger, self peer.ID) *Engine { func NewEngine(bs bstore.Blockstore, bstoreWorkerCount int, peerTagger PeerTagger, self peer.ID, scoreLedger ScoreLedger) *Engine {
return newEngine(ctx, bs, peerTagger, self, maxBlockSizeReplaceHasWithBlock, nil) return newEngine(bs, bstoreWorkerCount, peerTagger, self, maxBlockSizeReplaceHasWithBlock, scoreLedger)
} }
// This constructor is used by the tests // This constructor is used by the tests
func newEngine(ctx context.Context, bs bstore.Blockstore, peerTagger PeerTagger, self peer.ID, func newEngine(bs bstore.Blockstore, bstoreWorkerCount int, peerTagger PeerTagger, self peer.ID,
maxReplaceSize int, scoreLedger ScoreLedger) *Engine { maxReplaceSize int, scoreLedger ScoreLedger) *Engine {
if scoreLedger == nil { if scoreLedger == nil {
...@@ -185,7 +182,7 @@ func newEngine(ctx context.Context, bs bstore.Blockstore, peerTagger PeerTagger, ...@@ -185,7 +182,7 @@ func newEngine(ctx context.Context, bs bstore.Blockstore, peerTagger PeerTagger,
e := &Engine{ e := &Engine{
ledgerMap: make(map[peer.ID]*ledger), ledgerMap: make(map[peer.ID]*ledger),
scoreLedger: scoreLedger, scoreLedger: scoreLedger,
bsm: newBlockstoreManager(ctx, bs, blockstoreWorkerCount), bsm: newBlockstoreManager(bs, bstoreWorkerCount),
peerTagger: peerTagger, peerTagger: peerTagger,
outbox: make(chan (<-chan *Envelope), outboxChanBuffer), outbox: make(chan (<-chan *Envelope), outboxChanBuffer),
workSignal: make(chan struct{}, 1), workSignal: make(chan struct{}, 1),
...@@ -215,12 +212,6 @@ func (e *Engine) SetSendDontHaves(send bool) { ...@@ -215,12 +212,6 @@ func (e *Engine) SetSendDontHaves(send bool) {
e.sendDontHaves = send e.sendDontHaves = send
} }
// Sets the scoreLedger to the given implementation. Should be called
// before StartWorkers().
func (e *Engine) UseScoreLedger(scoreLedger ScoreLedger) {
e.scoreLedger = scoreLedger
}
// Starts the score ledger. Before start the function checks and, // Starts the score ledger. Before start the function checks and,
// if it is unset, initializes the scoreLedger with the default // if it is unset, initializes the scoreLedger with the default
// implementation. // implementation.
......
...@@ -97,7 +97,7 @@ func newTestEngine(ctx context.Context, idStr string) engineSet { ...@@ -97,7 +97,7 @@ func newTestEngine(ctx context.Context, idStr string) engineSet {
func newTestEngineWithSampling(ctx context.Context, idStr string, peerSampleInterval time.Duration, sampleCh chan struct{}) engineSet { func newTestEngineWithSampling(ctx context.Context, idStr string, peerSampleInterval time.Duration, sampleCh chan struct{}) engineSet {
fpt := &fakePeerTagger{} fpt := &fakePeerTagger{}
bs := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) bs := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore()))
e := newEngine(ctx, bs, fpt, "localhost", 0, NewTestScoreLedger(peerSampleInterval, sampleCh)) e := newEngine(bs, 4, fpt, "localhost", 0, NewTestScoreLedger(peerSampleInterval, sampleCh))
e.StartWorkers(ctx, process.WithTeardown(func() error { return nil })) e.StartWorkers(ctx, process.WithTeardown(func() error { return nil }))
return engineSet{ return engineSet{
Peer: peer.ID(idStr), Peer: peer.ID(idStr),
...@@ -185,7 +185,7 @@ func peerIsPartner(p peer.ID, e *Engine) bool { ...@@ -185,7 +185,7 @@ func peerIsPartner(p peer.ID, e *Engine) bool {
func TestOutboxClosedWhenEngineClosed(t *testing.T) { func TestOutboxClosedWhenEngineClosed(t *testing.T) {
ctx := context.Background() ctx := context.Background()
t.SkipNow() // TODO implement *Engine.Close t.SkipNow() // TODO implement *Engine.Close
e := newEngine(ctx, blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())), &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil)) e := newEngine(blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())), 4, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil))
e.StartWorkers(ctx, process.WithTeardown(func() error { return nil })) e.StartWorkers(ctx, process.WithTeardown(func() error { return nil }))
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
...@@ -513,7 +513,7 @@ func TestPartnerWantHaveWantBlockNonActive(t *testing.T) { ...@@ -513,7 +513,7 @@ func TestPartnerWantHaveWantBlockNonActive(t *testing.T) {
testCases = onlyTestCases testCases = onlyTestCases
} }
e := newEngine(context.Background(), bs, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil)) e := newEngine(bs, 4, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil))
e.StartWorkers(context.Background(), process.WithTeardown(func() error { return nil })) e.StartWorkers(context.Background(), process.WithTeardown(func() error { return nil }))
for i, testCase := range testCases { for i, testCase := range testCases {
t.Logf("Test case %d:", i) t.Logf("Test case %d:", i)
...@@ -669,7 +669,7 @@ func TestPartnerWantHaveWantBlockActive(t *testing.T) { ...@@ -669,7 +669,7 @@ func TestPartnerWantHaveWantBlockActive(t *testing.T) {
testCases = onlyTestCases testCases = onlyTestCases
} }
e := newEngine(context.Background(), bs, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil)) e := newEngine(bs, 4, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil))
e.StartWorkers(context.Background(), process.WithTeardown(func() error { return nil })) e.StartWorkers(context.Background(), process.WithTeardown(func() error { return nil }))
var next envChan var next envChan
...@@ -854,7 +854,7 @@ func TestPartnerWantsThenCancels(t *testing.T) { ...@@ -854,7 +854,7 @@ func TestPartnerWantsThenCancels(t *testing.T) {
ctx := context.Background() ctx := context.Background()
for i := 0; i < numRounds; i++ { for i := 0; i < numRounds; i++ {
expected := make([][]string, 0, len(testcases)) expected := make([][]string, 0, len(testcases))
e := newEngine(ctx, bs, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil)) e := newEngine(bs, 4, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil))
e.StartWorkers(ctx, process.WithTeardown(func() error { return nil })) e.StartWorkers(ctx, process.WithTeardown(func() error { return nil }))
for _, testcase := range testcases { for _, testcase := range testcases {
set := testcase[0] set := testcase[0]
...@@ -879,7 +879,7 @@ func TestSendReceivedBlocksToPeersThatWantThem(t *testing.T) { ...@@ -879,7 +879,7 @@ func TestSendReceivedBlocksToPeersThatWantThem(t *testing.T) {
partner := libp2ptest.RandPeerIDFatal(t) partner := libp2ptest.RandPeerIDFatal(t)
otherPeer := libp2ptest.RandPeerIDFatal(t) otherPeer := libp2ptest.RandPeerIDFatal(t)
e := newEngine(context.Background(), bs, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil)) e := newEngine(bs, 4, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil))
e.StartWorkers(context.Background(), process.WithTeardown(func() error { return nil })) e.StartWorkers(context.Background(), process.WithTeardown(func() error { return nil }))
blks := testutil.GenerateBlocksOfSize(4, 8*1024) blks := testutil.GenerateBlocksOfSize(4, 8*1024)
...@@ -923,7 +923,7 @@ func TestSendDontHave(t *testing.T) { ...@@ -923,7 +923,7 @@ func TestSendDontHave(t *testing.T) {
partner := libp2ptest.RandPeerIDFatal(t) partner := libp2ptest.RandPeerIDFatal(t)
otherPeer := libp2ptest.RandPeerIDFatal(t) otherPeer := libp2ptest.RandPeerIDFatal(t)
e := newEngine(context.Background(), bs, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil)) e := newEngine(bs, 4, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil))
e.StartWorkers(context.Background(), process.WithTeardown(func() error { return nil })) e.StartWorkers(context.Background(), process.WithTeardown(func() error { return nil }))
blks := testutil.GenerateBlocksOfSize(4, 8*1024) blks := testutil.GenerateBlocksOfSize(4, 8*1024)
...@@ -987,7 +987,7 @@ func TestWantlistForPeer(t *testing.T) { ...@@ -987,7 +987,7 @@ func TestWantlistForPeer(t *testing.T) {
partner := libp2ptest.RandPeerIDFatal(t) partner := libp2ptest.RandPeerIDFatal(t)
otherPeer := libp2ptest.RandPeerIDFatal(t) otherPeer := libp2ptest.RandPeerIDFatal(t)
e := newEngine(context.Background(), bs, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil)) e := newEngine(bs, 4, &fakePeerTagger{}, "localhost", 0, NewTestScoreLedger(shortTerm, nil))
e.StartWorkers(context.Background(), process.WithTeardown(func() error { return nil })) e.StartWorkers(context.Background(), process.WithTeardown(func() error { return nil }))
blks := testutil.GenerateBlocksOfSize(4, 8*1024) blks := testutil.GenerateBlocksOfSize(4, 8*1024)
......
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