forked from TrueCloudLab/frostfs-node
Evgenii Stratonikov
f2e5dead7e
1. In redo() we save the old state. 2. If we do redo() for the same operation twice, the old state will be overritten with the new one. 3. This in turn affects undo() and subsequent isAncestor() check. Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
72 lines
1.5 KiB
Go
72 lines
1.5 KiB
Go
package pilorama
|
|
|
|
import (
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
|
|
cidSDK "git.frostfs.info/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
|
|
})
|
|
|
|
b.operations = removeDuplicatesInPlace(b.operations)
|
|
var lm Move
|
|
return b.forest.applyOperation(bLog, bTree, b.operations, &lm)
|
|
})
|
|
for i := range b.results {
|
|
b.results[i] <- err
|
|
}
|
|
}
|
|
|
|
func removeDuplicatesInPlace(a []*Move) []*Move {
|
|
equalCount := 0
|
|
for i := 1; i < len(a); i++ {
|
|
if a[i].Time == a[i-1].Time {
|
|
equalCount++
|
|
} else {
|
|
a[i-equalCount] = a[i]
|
|
}
|
|
}
|
|
return a[:len(a)-equalCount]
|
|
}
|