func main() { var database databases.Database var workload workloads.Workload // Read configuration file config := ReadConfig() // Create driver instance switch config.Database.Driver { case "MongoDB": database = &databases.MongoDB{} default: log.Fatal("Unsupported competitor") } switch config.Workload.Type { case "DefaultWorkload": workload = &workloads.DefaultWorkload{} default: log.Fatal("Unsupported workload type") } // Initialize database and workload database.Init(config.Database) workload.Init(config.Workload) // Run concurrent workload wg := sync.WaitGroup{} wgStats := sync.WaitGroup{} state := workloads.State{} state.Records = config.Workload.Records // Initialize benchmark events state.Init() // Start concurrent goroutines state.Events["Started"] = time.Now() for worker := 0; worker < config.Workload.Workers; worker++ { wg.Add(1) go workload.RunWorkload(database, &state, &wg) } // Continuously report performance stats wgStats.Add(2) go state.ReportThroughput(config.Workload, &wgStats) go state.MeasureLatency(database, workload, config.Workload, &wgStats) wg.Wait() state.Events["Finished"] = time.Now() wgStats.Wait() // Close active connections (if any) and report final summary database.Shutdown() state.ReportSummary() }
func (state *State) MeasureLatency(database databases.Database, workload Workload, config Config, wg *sync.WaitGroup) { defer wg.Done() for state.Operations < config.Operations { if config.CreatePercentage > 0 { state.Operations++ state.Records++ key := workload.GenerateNewKey(state.Records) value := workload.GenerateValue(key, config.IndexableFields, config.ValueSize) t0 := time.Now() database.Create(key, value) t1 := time.Now() state.Latency["Create"].AddSample(summstat.Sample(t1.Sub(t0))) } if config.ReadPercentage > 0 { state.Operations++ key := workload.GenerateExistingKey(state.Records) t0 := time.Now() database.Read(key) t1 := time.Now() state.Latency["Read"].AddSample(summstat.Sample(t1.Sub(t0))) } if config.UpdatePercentage > 0 { state.Operations++ key := workload.GenerateExistingKey(state.Records) value := workload.GenerateValue(key, config.IndexableFields, config.ValueSize) t0 := time.Now() database.Update(key, value) t1 := time.Now() state.Latency["Update"].AddSample(summstat.Sample(t1.Sub(t0))) } if config.DeletePercentage > 0 { state.Operations++ key := workload.GenerateKeyForRemoval() t0 := time.Now() database.Delete(key) t1 := time.Now() state.Latency["Delete"].AddSample(summstat.Sample(t1.Sub(t0))) } if config.QueryPercentage > 0 { state.Operations++ fieldName, fieldValue, limit := workload.GenerateQuery(config.IndexableFields, state.Records) t0 := time.Now() database.Query(fieldName, fieldValue, limit) t1 := time.Now() state.Latency["Query"].AddSample(summstat.Sample(t1.Sub(t0))) } time.Sleep(time.Second) } }
// Sequentially send 100 requests func (workload *DefaultWorkload) DoBatch(db databases.Database, state *State) { batch := workload.PrepareBatch() for _, v := range batch { // Increase number of passed operarions *before* batch // execution in order to normally share key space with // other workers if state.Operations < workload.Config.Operations { var err error state.Operations++ switch v { case "c": state.Records++ key := workload.GenerateNewKey(state.Records) value := workload.GenerateValue(key, workload.Config.IndexableFields, workload.Config.ValueSize) err = db.Create(key, value) case "r": key := workload.GenerateExistingKey(state.Records) err = db.Read(key) case "u": key := workload.GenerateExistingKey(state.Records) value := workload.GenerateValue(key, workload.Config.IndexableFields, workload.Config.ValueSize) err = db.Update(key, value) case "d": key := workload.GenerateKeyForRemoval() err = db.Delete(key) case "q": fieldName, fieldValue, limit := workload.GenerateQuery( workload.Config.IndexableFields, state.Records) err = db.Query(fieldName, fieldValue, limit) } if err != nil { state.Errors[v]++ state.Errors["total"]++ } } } }