Skip to content

Commit

Permalink
movr: Add stats collection to movr workload run
Browse files Browse the repository at this point in the history
This PR adds tracking stats for each kind of query in the movr workload
so that output is displayed from cockroach workload run. Additionally,
this refactors the movr workload to define the work as functions on a
worker struct. This hopefully will avoid a common gotcha of having
different workers sharing the same not threadsafe histograms object.

Release justification: low risk nice to have feature

Release note: None
  • Loading branch information
Rohan Yadav committed Sep 30, 2019
1 parent 12c640b commit 460f9e7
Show file tree
Hide file tree
Showing 2 changed files with 316 additions and 201 deletions.
201 changes: 0 additions & 201 deletions pkg/workload/movr/movr.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
package movr

import (
"context"
gosql "database/sql"
"math"
"strings"
Expand All @@ -21,7 +20,6 @@ import (
"github.com/cockroachdb/cockroach/pkg/util/uuid"
"github.com/cockroachdb/cockroach/pkg/workload"
"github.com/cockroachdb/cockroach/pkg/workload/faker"
"github.com/cockroachdb/cockroach/pkg/workload/histogram"
"github.com/pkg/errors"
"github.com/spf13/pflag"
"golang.org/x/exp/rand"
Expand Down Expand Up @@ -518,202 +516,3 @@ func (g *movr) movrPromoCodesInitialRow(rowIdx int) []interface{} {
rulesJSON, // rules
}
}

type rideInfo struct {
id string
city string
}

// Ops implements the Opser interface
func (g *movr) Ops(urls []string, reg *histogram.Registry) (workload.QueryLoad, error) {
// Initialize the faker in case it hasn't been setup already.
g.fakerOnce.Do(func() {
g.faker = faker.NewFaker()
})
sqlDatabase, err := workload.SanitizeUrls(g, g.connFlags.DBOverride, urls)
if err != nil {
return workload.QueryLoad{}, err
}
db, err := gosql.Open(`postgres`, strings.Join(urls, ` `))
if err != nil {
return workload.QueryLoad{}, err
}

ql := workload.QueryLoad{SQLDatabase: sqlDatabase}

rng := rand.New(rand.NewSource(g.seed))
readPercentage := 0.90
activeRides := []rideInfo{}

getRandomUser := func(city string) (string, error) {
id, err := uuid.NewV4()
if err != nil {
return "", err
}
var user string
q := `
SELECT
IFNULL(a, b)
FROM
(
SELECT
(SELECT id FROM users WHERE city = $1 AND id > $2 ORDER BY id LIMIT 1)
AS a,
(SELECT id FROM users WHERE city = $1 ORDER BY id LIMIT 1) AS b
);
`
err = db.QueryRow(q, city, id.String()).Scan(&user)
return user, err
}

getRandomPromoCode := func() (string, error) {
id, err := uuid.NewV4()
if err != nil {
return "", err
}
q := `
SELECT
IFNULL(a, b)
FROM
(
SELECT
(SELECT code FROM promo_codes WHERE code > $1 ORDER BY code LIMIT 1)
AS a,
(SELECT code FROM promo_codes ORDER BY code LIMIT 1) AS b
);
`
var code string
err = db.QueryRow(q, id.String()).Scan(&code)
return code, err
}

getRandomVehicle := func(city string) (string, error) {
id, err := uuid.NewV4()
if err != nil {
return "", err
}
q := `
SELECT
IFNULL(a, b)
FROM
(
SELECT
(SELECT id FROM vehicles WHERE city = $1 AND id > $2 ORDER BY id LIMIT 1)
AS a,
(SELECT id FROM vehicles WHERE city = $1 ORDER BY id LIMIT 1) AS b
);
`
var vehicle string
err = db.QueryRow(q, city, id.String()).Scan(&vehicle)
return vehicle, err
}

movrQuerySimulation := func(ctx context.Context) error {
activeCity := randCity(rng)
if rng.Float64() <= readPercentage {
q := `SELECT city, id FROM vehicles WHERE city = $1`
_, err := db.Exec(q, activeCity)
return err
}
// Simulate vehicle location updates.
for i, ride := range activeRides {
if i >= 10 {
break
}
lat, long := randLatLong(rng)
q := `UPSERT INTO vehicle_location_histories VALUES ($1, $2, now(), $3, $4)`
_, err := db.Exec(q, ride.city, ride.id, lat, long)
if err != nil {
return err
}
}

id, err := uuid.NewV4()
if err != nil {
return err
}

// Do write operations.
if rng.Float64() < 0.03 {
q := `INSERT INTO promo_codes VALUES ($1, NULL, NULL, NULL, NULL)`
_, err = db.Exec(q, id.String())
return err
} else if rng.Float64() < 0.1 {
// Apply a promo code to an account.
user, err := getRandomUser(activeCity)
if err != nil {
return err
}

code, err := getRandomPromoCode()
if err != nil {
return err
}

// See if the promo code has been used.
var count int
q := `SELECT count(*) FROM user_promo_codes WHERE city = $1 AND user_id = $2 AND code = $3`
err = db.QueryRow(q, activeCity, user, code).Scan(&count)
if err != nil {
return err
}

// If is has not been, apply the promo code.
if count == 0 {
q = `INSERT INTO user_promo_codes VALUES ($1, $2, $3, NULL, NULL)`
_, err = db.Exec(q, activeCity, user, code)
return err
}
return nil
} else if rng.Float64() < 0.3 {
q := `INSERT INTO users VALUES ($1, $2, NULL, NULL, NULL)`
_, err = db.Exec(q, id.String(), activeCity)
return err
} else if rng.Float64() < 0.1 {
// Simulate adding a new vehicle to the population.
ownerID, err := getRandomUser(activeCity)
if err != nil {
return err
}

typ := randVehicleType(rng)
q := `INSERT INTO vehicles VALUES ($1, $2, $3, $4, NULL, NULL, NULL, NULL)`
_, err = db.Exec(q, id.String(), activeCity, typ, ownerID)
return err
} else if rng.Float64() < 0.5 {
// Simulate a user starting a ride.
rider, err := getRandomUser(activeCity)
if err != nil {
return err
}

vehicle, err := getRandomVehicle(activeCity)
if err != nil {
return err
}

q := `INSERT INTO rides VALUES ($1, $2, $2, $3, $4, $5, NULL, now(), NULL, NULL)`
_, err = db.Exec(q, id.String(), activeCity, rider, vehicle, g.faker.StreetAddress(rng))
if err != nil {
return err
}
activeRides = append(activeRides, rideInfo{id.String(), activeCity})
return err
} else {
// Simulate a ride ending.
if len(activeRides) > 1 {
ride := activeRides[0]
activeRides = activeRides[1:]
q := `UPDATE rides SET end_address = $3, end_time = now() WHERE city = $1 AND id = $2`
_, err := db.Exec(q, ride.city, ride.id, g.faker.StreetAddress(rng))
return err
}
}

return nil
}

ql.WorkerFns = append(ql.WorkerFns, movrQuerySimulation)

return ql, nil
}
Loading

0 comments on commit 460f9e7

Please sign in to comment.