forked from TrueCloudLab/frostfs-node
Evgenii Stratonikov
58367e4df6
To achieve high performance we must choose proper values for both batch size and delay. For user operations we want to set low delay. However it would prevent tree synchronization operations to form big enough batches. For these operations, batching gives the most benefit not only in terms of on-CPU execution cost, but also by speeding up transaction persist (`fsync`). In this commit we try merging batches that are already _triggered_, but not yet _started to execute_. This way we can still query batches for execution after the provided delay while also allowing multiple formed batches to execute faster. Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
59 lines
1.3 KiB
Go
59 lines
1.3 KiB
Go
package pilorama
|
|
|
|
import (
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
|
|
cidSDK "github.com/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
"go.etcd.io/bbolt"
|
|
)
|
|
|
|
type batch struct {
|
|
forest *boltForest
|
|
timer *time.Timer
|
|
// mtx protects timer and operations fields.
|
|
// Because mtx can be taken inside a transaction,
|
|
// transactions MUST NOT be executed with the mutex taken to avoid a deadlock.
|
|
mtx sync.Mutex
|
|
start sync.Once
|
|
cid cidSDK.ID
|
|
treeID string
|
|
results []chan<- error
|
|
operations []*Move
|
|
}
|
|
|
|
func (b *batch) trigger() {
|
|
b.mtx.Lock()
|
|
if b.timer != nil {
|
|
b.timer.Stop()
|
|
}
|
|
b.mtx.Unlock()
|
|
b.start.Do(b.run)
|
|
}
|
|
|
|
func (b *batch) run() {
|
|
fullID := bucketName(b.cid, b.treeID)
|
|
err := b.forest.db.Update(func(tx *bbolt.Tx) error {
|
|
bLog, bTree, err := b.forest.getTreeBuckets(tx, fullID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
b.mtx.Lock()
|
|
b.timer = nil
|
|
b.mtx.Unlock()
|
|
|
|
// Sorting without a mutex is ok, because we append to this slice only if timer is non-nil.
|
|
// See (*boltForest).addBatch for details.
|
|
sort.Slice(b.operations, func(i, j int) bool {
|
|
return b.operations[i].Time < b.operations[j].Time
|
|
})
|
|
|
|
var lm Move
|
|
return b.forest.applyOperation(bLog, bTree, b.operations, &lm)
|
|
})
|
|
for i := range b.operations {
|
|
b.results[i] <- err
|
|
}
|
|
}
|