diff --git a/benchmarks/callaghanbench/benchmark.go b/benchmarks/callaghanbench/benchmark.go new file mode 100644 index 0000000..acd7173 --- /dev/null +++ b/benchmarks/callaghanbench/benchmark.go @@ -0,0 +1,95 @@ +package main + +import "github.com/Shopify/mybench" + +// https://github.com/mdcallag/mytools/blob/3c57ee97431112bdc167fc9c0ef032b24cb3c485/bench/ibench/iibench.py#L357-L390 +// https://github.com/mdcallag/mytools/blob/3c57ee97431112bdc167fc9c0ef032b24cb3c485/bench/ibench/iibench.py#L517 +func NewTablePurchaseIndex(idGen mybench.DataGenerator) mybench.Table { + + return mybench.InitializeTable(mybench.Table{ + Name: "purchase_index", + Columns: []*mybench.Column{ + { + Name: "transactionid", + Definition: "bigint not null auto_increment", + Generator: idGen, + }, + { + Name: "dateandtime", + Definition: "datetime", + Generator: mybench.NewNowGenerator(), + }, + { + Name: "cashregisterid", + Definition: "int not null", + // https://github.com/mdcallag/mytools/blob/3c57ee97431112bdc167fc9c0ef032b24cb3c485/bench/ibench/iibench.py#L496 + Generator: mybench.NewUniformIntGenerator(0, 1000), + }, + { + Name: "customerid", + Definition: "int not null", + // https://github.com/mdcallag/mytools/blob/3c57ee97431112bdc167fc9c0ef032b24cb3c485/bench/ibench/iibench.py#L498 + Generator: mybench.NewUniformIntGenerator(0, 100000), + }, + { + Name: "productid", + Definition: "int not null", + // https://github.com/mdcallag/mytools/blob/3c57ee97431112bdc167fc9c0ef032b24cb3c485/bench/ibench/iibench.py#L497 + Generator: mybench.NewUniformIntGenerator(0, 10000), + }, + { + Name: "price", + Definition: "float not null", + // https://github.com/mdcallag/mytools/blob/3c57ee97431112bdc167fc9c0ef032b24cb3c485/bench/ibench/iibench.py#L499 + // This is not implemented to be accurate. The generator implemented by + // Mark Callaghan is dependent on customer id. Specifically it's: + // + // (UniformFloat(0, 500) + customerid) / 100.0 + // + // TODO: mybench should have a way to generate values dependent on + // another value, but then the generators may have to be specified in a + // DAG, which can be a pain. + Generator: mybench.NewUniformFloatGenerator(0, 5), + }, + { + Name: "data", + Definition: "varchar(4000)", + // https://github.com/mdcallag/mytools/blob/3c57ee97431112bdc167fc9c0ef032b24cb3c485/bench/ibench/iibench.py#L500 + // TODO: this is not accurately translated. + Generator: mybench.NewUniformLengthStringGenerator(10, 11), + }, + }, + PrimaryKey: []string{"transactionid"}, + }) +} + +type CallaghanBench struct { + *mybench.BenchmarkConfig + + InitialNumRows int64 +} + +func (b CallaghanBench) Name() string { + return "CallaghanBench" +} + +func (b CallaghanBench) RunLoader() error { + idGen := mybench.NewNullGenerator() + table := NewTablePurchaseIndex(idGen) + table.ReloadData( + b.BenchmarkConfig.DatabaseConfig, + b.InitialNumRows, + 200, + b.BenchmarkConfig.RateControlConfig.Concurrency, + ) + return nil +} + +func (b CallaghanBench) Workloads() ([]mybench.AbstractWorkload, error) { + idGen := mybench.NewNullGenerator() + table := NewTablePurchaseIndex(idGen) + + return []mybench.AbstractWorkload{ + NewInsert(table), + }, nil +} diff --git a/benchmarks/callaghanbench/main.go b/benchmarks/callaghanbench/main.go new file mode 100644 index 0000000..e1da746 --- /dev/null +++ b/benchmarks/callaghanbench/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "flag" + + "github.com/Shopify/mybench" +) + +func main() { + benchmarkInterface := CallaghanBench{ + BenchmarkConfig: mybench.NewBenchmarkConfig(), + } + + flag.Parse() + err := mybench.Run(benchmarkInterface) + if err != nil { + panic(err) + } +} diff --git a/benchmarks/callaghanbench/workloads.go b/benchmarks/callaghanbench/workloads.go new file mode 100644 index 0000000..99d165a --- /dev/null +++ b/benchmarks/callaghanbench/workloads.go @@ -0,0 +1,69 @@ +package main + +import ( + "bytes" + "fmt" + + "github.com/Shopify/mybench" +) + +type Insert struct { + mybench.WorkloadConfig + mybench.NoContextData + + batchSize int + table mybench.Table +} + +func (w *Insert) Event(ctx mybench.WorkerContext[mybench.NoContextData]) error { + // https://github.com/mdcallag/mytools/blob/3c57ee97431112bdc167fc9c0ef032b24cb3c485/bench/ibench/iibench.py#L707-L731 + var valuesBuf bytes.Buffer + for i := 0; i < w.batchSize; i++ { + valuesBuf.WriteByte('(') + + dateandtime := w.table.Generate(ctx.Rand, "dateandtime").(string) + valuesBuf.WriteString(fmt.Sprintf("'%s'", dateandtime)) + valuesBuf.WriteByte(',') + + cashregisterid := w.table.Generate(ctx.Rand, "cashregisterid").(int64) + valuesBuf.WriteString(fmt.Sprintf("%d", cashregisterid)) + valuesBuf.WriteByte(',') + + customerid := w.table.Generate(ctx.Rand, "customerid").(int64) + valuesBuf.WriteString(fmt.Sprintf("%d", customerid)) + valuesBuf.WriteByte(',') + + productid := w.table.Generate(ctx.Rand, "productid").(int64) + valuesBuf.WriteString(fmt.Sprintf("%d", productid)) + valuesBuf.WriteByte(',') + + price := w.table.Generate(ctx.Rand, "price").(float64) + valuesBuf.WriteString(fmt.Sprintf("%f", price)) + valuesBuf.WriteByte(',') + + data := w.table.Generate(ctx.Rand, "data").(string) + valuesBuf.WriteString(fmt.Sprintf("'%s'", data)) + + valuesBuf.WriteByte(')') + if i != w.batchSize-1 { + valuesBuf.WriteByte(',') + } + } + + query := fmt.Sprintf("insert into purchase_index (dateandtime, cashregisterid, customerid, productid, price, data) values %s", valuesBuf.String()) + _, err := ctx.Conn.Execute(query) + return err +} + +func NewInsert(table mybench.Table) mybench.AbstractWorkload { + workloadInterface := &Insert{ + WorkloadConfig: mybench.WorkloadConfig{ + Name: "Insert", + WorkloadScale: 1.0, + }, + batchSize: 1000, + table: table, + } + + return mybench.NewWorkload[mybench.NoContextData](workloadInterface) +}