99 lines
2.5 KiB
Go
99 lines
2.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"slices"
|
|
"time"
|
|
)
|
|
|
|
// Simulates the bisync modifyListing graceful shutdown rollback logic.
|
|
// BEFORE: slices.Contains(toKeep, f) inside loop over combinedList = O(C*K)
|
|
// AFTER: map[string]struct{} lookup = O(C)
|
|
|
|
func generateFileNames(n int) []string {
|
|
names := make([]string, n)
|
|
for i := range n {
|
|
names[i] = fmt.Sprintf("path/to/file_%06d.dat", i)
|
|
}
|
|
return names
|
|
}
|
|
|
|
// BEFORE: linear search with slices.Contains
|
|
func rollbackBefore(combinedList, toKeep []string) []string {
|
|
var toRollback []string
|
|
for _, f := range combinedList {
|
|
if !slices.Contains(toKeep, f) {
|
|
toRollback = append(toRollback, f)
|
|
}
|
|
}
|
|
return toRollback
|
|
}
|
|
|
|
// AFTER: hash set lookup
|
|
func rollbackAfter(combinedList, toKeep []string) []string {
|
|
toKeepSet := make(map[string]struct{}, len(toKeep))
|
|
for _, k := range toKeep {
|
|
toKeepSet[k] = struct{}{}
|
|
}
|
|
var toRollback []string
|
|
for _, f := range combinedList {
|
|
if _, ok := toKeepSet[f]; !ok {
|
|
toRollback = append(toRollback, f)
|
|
}
|
|
}
|
|
return toRollback
|
|
}
|
|
|
|
func main() {
|
|
rand.Seed(42)
|
|
|
|
for _, N := range []int{100, 500, 2000, 10000} {
|
|
allFiles := generateFileNames(N)
|
|
// 30% kept, 70% to rollback
|
|
keepCount := N * 3 / 10
|
|
perm := rand.Perm(N)
|
|
toKeep := make([]string, keepCount)
|
|
for i := range keepCount {
|
|
toKeep[i] = allFiles[perm[i]]
|
|
}
|
|
// combinedList = 4x file lists (simulating oldSrc + oldDst + srcList + dstList)
|
|
combinedList := make([]string, 0, N*4)
|
|
for range 4 {
|
|
combinedList = append(combinedList, allFiles...)
|
|
}
|
|
|
|
// Correctness: both must produce same rollback set
|
|
resultBefore := rollbackBefore(combinedList, toKeep)
|
|
resultAfter := rollbackAfter(combinedList, toKeep)
|
|
if len(resultBefore) != len(resultAfter) {
|
|
fmt.Printf("FAIL N=%d: length mismatch %d vs %d\n", N, len(resultBefore), len(resultAfter))
|
|
return
|
|
}
|
|
for i := range resultBefore {
|
|
if resultBefore[i] != resultAfter[i] {
|
|
fmt.Printf("FAIL N=%d: mismatch at index %d\n", N, i)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Benchmark BEFORE
|
|
start := time.Now()
|
|
iters := 5
|
|
for range iters {
|
|
rollbackBefore(combinedList, toKeep)
|
|
}
|
|
dBefore := time.Since(start)
|
|
|
|
// Benchmark AFTER
|
|
start = time.Now()
|
|
for range iters {
|
|
rollbackAfter(combinedList, toKeep)
|
|
}
|
|
dAfter := time.Since(start)
|
|
|
|
ratio := float64(dBefore) / float64(dAfter)
|
|
fmt.Printf("PASS N=%d (combined=%d, keep=%d): before=%v after=%v ratio=%.1fx\n",
|
|
N, len(combinedList), keepCount, dBefore/time.Duration(iters), dAfter/time.Duration(iters), ratio)
|
|
}
|
|
}
|