VictoriaMetrics/lib/storage/table_timing_test.go
Aliaksandr Valialkin aac3dccfd1
lib/fs: replace MkdirAllIfNotExist->MustMkdirIfNotExist and MkdirAllFailIfExist->MustMkdirFailIfExist
Callers of these functions log the returned error and then exit. The returned error already contains the path
to directory, which was failed to be created. So let's just log the error together with the call stack
inside these functions. This leaves the debuggability of the returned error at the same level
while allows simplifying the code at callers' side.

While at it, properly use MustMkdirFailIfExist instead of MustMkdirIfNotExist inside inmemoryPart.MustStoreToDisk().
It is expected that the inmemoryPart.MustStoreToDick() must fail if there is already a directory under the given path.
2023-04-13 22:22:08 -07:00

113 lines
2.9 KiB
Go

package storage
import (
"fmt"
"math/rand"
"os"
"testing"
"time"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/cgroup"
)
func BenchmarkTableAddRows(b *testing.B) {
for _, tsidsCount := range []int{1e0, 1e1, 1e2, 1e3, 1e4} {
b.Run(fmt.Sprintf("tsidsCount_%d", tsidsCount), func(b *testing.B) {
for _, rowsPerInsert := range []int{1, 1e1, 1e2, 1e3, 1e4, 1e5} {
b.Run(fmt.Sprintf("rowsPerInsert_%d", rowsPerInsert), func(b *testing.B) {
benchmarkTableAddRows(b, rowsPerInsert, tsidsCount)
})
}
})
}
}
func benchmarkTableAddRows(b *testing.B, rowsPerInsert, tsidsCount int) {
rows := make([]rawRow, rowsPerInsert)
startTimestamp := timestampFromTime(time.Now())
timestamp := startTimestamp
value := float64(100)
rng := rand.New(rand.NewSource(1))
for i := 0; i < rowsPerInsert; i++ {
r := &rows[i]
r.PrecisionBits = defaultPrecisionBits
r.TSID.MetricID = uint64(rng.Intn(tsidsCount) + 1)
r.Timestamp = timestamp
r.Value = value
timestamp += 10 + rng.Int63n(2)
value += float64(int(rng.NormFloat64() * 5))
}
timestampDelta := timestamp - startTimestamp
insertsCount := int(1e3)
rowsCountExpected := insertsCount * len(rows)
b.ResetTimer()
b.ReportAllocs()
b.SetBytes(int64(rowsCountExpected))
tablePath := "benchmarkTableAddRows"
strg := newTestStorage()
for i := 0; i < b.N; i++ {
tb, err := openTable(tablePath, strg)
if err != nil {
b.Fatalf("cannot open table %q: %s", tablePath, err)
}
workCh := make(chan struct{}, insertsCount)
for j := 0; j < insertsCount; j++ {
workCh <- struct{}{}
}
close(workCh)
doneCh := make(chan struct{})
gomaxprocs := cgroup.AvailableCPUs()
for j := 0; j < gomaxprocs; j++ {
go func(goroutineID int) {
// Make per-goroutine rows copy with distinct timestamps.
rowsCopy := append([]rawRow{}, rows...)
for k := range rowsCopy {
r := &rowsCopy[k]
r.Timestamp += int64(goroutineID)
r.Value += float64(goroutineID)
}
for range workCh {
// Update rowsCopy to the next timestamp chunk.
for q := range rowsCopy {
r := &rowsCopy[q]
r.Timestamp += timestampDelta
r.Value++
}
// Add updated rowsCopy.
tb.MustAddRows(rowsCopy)
}
doneCh <- struct{}{}
}(j)
}
for j := 0; j < gomaxprocs; j++ {
<-doneCh
}
tb.MustClose()
// Open the table from files and verify the rows count on it
tb, err = openTable(tablePath, strg)
if err != nil {
b.Fatalf("cannot open table %q: %s", tablePath, err)
}
var m TableMetrics
tb.UpdateMetrics(&m)
if rowsCount := m.TotalRowsCount(); rowsCount != uint64(rowsCountExpected) {
b.Fatalf("unexpected rows count in the final table %q: got %d; want %d", tablePath, rowsCount, rowsCountExpected)
}
tb.MustClose()
// Remove the table.
if err := os.RemoveAll(tablePath); err != nil {
b.Fatalf("cannot remove table %q: %s", tablePath, err)
}
}
}