Skip to content

Commit

Permalink
gemini: possible to run without oracle
Browse files Browse the repository at this point in the history
If you do not provide a host config for the Oracle the queries,
both read and writes will only be performed against the Test system.
No validations will then be performed of course.
  • Loading branch information
Henrik Johansson committed Jul 25, 2019
1 parent c6a1a0e commit dcad380
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 25 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

# Unreleased

- Added the possibility to run without any validations against the Oracle. Simply do not
supply a host for the Oracle and Gemini will assume you want to only run against Test.
- Replication strategy is now configurable via the CLI argument `--replication-strategy`.

# 1.4.4
Expand Down
6 changes: 4 additions & 2 deletions cmd/gemini/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,9 @@ func createClusters(consistency gocql.Consistency) (*gocql.ClusterConfig, *gocql
testCluster.Timeout = 5 * time.Second
testCluster.RetryPolicy = retryPolicy
testCluster.Consistency = consistency
if len(oracleClusterHost) == 0 {
return testCluster, nil
}
oracleCluster := gocql.NewCluster(oracleClusterHost...)
oracleCluster.Timeout = 5 * time.Second
oracleCluster.RetryPolicy = retryPolicy
Expand Down Expand Up @@ -327,8 +330,7 @@ func init() {
rootCmd.Version = version + ", commit " + commit + ", date " + date
rootCmd.Flags().StringSliceVarP(&testClusterHost, "test-cluster", "t", []string{}, "Host names or IPs of the test cluster that is system under test")
rootCmd.MarkFlagRequired("test-cluster")
rootCmd.Flags().StringSliceVarP(&oracleClusterHost, "oracle-cluster", "o", []string{}, "Host names or IPs of the oracle cluster that provides correct answers")
rootCmd.MarkFlagRequired("oracle-cluster")
rootCmd.Flags().StringSliceVarP(&oracleClusterHost, "oracle-cluster", "o", []string{}, "Host names or IPs of the oracle cluster that provides correct answers. If omitted no oracle will be used")
rootCmd.Flags().StringVarP(&schemaFile, "schema", "", "", "Schema JSON config file")
rootCmd.Flags().StringVarP(&mode, "mode", "m", mixedMode, "Query operation mode. Mode options: write, read, mixed (default)")
rootCmd.Flags().Uint64VarP(&concurrency, "concurrency", "c", 10, "Number of threads per table to run concurrently")
Expand Down
25 changes: 13 additions & 12 deletions docs/cli-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,35 @@ Gemini has a large number of CLI arguments and this document is an attempt to do
part of the so called `Oracle` which is to say the super stable bug free cluster that Gemini uses as
the blueprint for it's validations.

2. ___--test-cluster___, ___-t___: This parameter takes a comma separated list of hosts that are
part of the ___SUT___ or commonly, ___system under test___.

## Optional arguments

1. ___---mode___, ___-m___: This is a string parameter with the acceptable values "mixed","read" and "write".
1. ___--test-cluster___, ___-t___: This parameter takes a comma separated list of hosts that are
part of the ___SUT___ or commonly, ___system under test___. If omitted then Gemini will not use the Oracle
at all and simply execute a lot of queries against the ___SUT___.

2. ___---mode___, ___-m___: This is a string parameter with the acceptable values "mixed","read" and "write".

2. ___--concurrency___, ___-c___: An int describing the number of concurrent jobs in the case of "read"
3. ___--concurrency___, ___-c___: An int describing the number of concurrent jobs in the case of "read"
or "write" mode. In the case of "mixed" mode it represents half of the number of jobs that will be executed
concurrently.

3. ___--schema___: The path to a file containing a JSON representation of the schema to be
4. ___--schema___: The path to a file containing a JSON representation of the schema to be
used during a run.

4. ___--seed___, ___-s___: The seed parameter denotes the seed from where to start the random number
5. ___--seed___, ___-s___: The seed parameter denotes the seed from where to start the random number
generators that Gemini is using.

5. ___--drop-schema___, ___-d___: Boolean value that instructs Gemini to issue a __DROP SCHEMA__
6. ___--drop-schema___, ___-d___: Boolean value that instructs Gemini to issue a __DROP SCHEMA__
statement before starting to run. Make sure you use it with care.

6. ___--fail-fast___, ___-f___: Boolean value that instructs Gemini to stop running as soon as it
7. ___--fail-fast___, ___-f___: Boolean value that instructs Gemini to stop running as soon as it
encounters a validation error. If set to false, then Gemini will collect the errors and report them
once normal program end is reached.

7. ___--duration___: The duration of a run. Defaults to 30 seconds.
8. ___--duration___: The duration of a run. Defaults to 30 seconds.

8. ___--warmup___: The duration of the warmup phase during which only additive mutations will be
9. ___--warmup___: The duration of the warmup phase during which only additive mutations will be
performed. Default is 30 seconds.

9. ___--outfile___: Path to a file where Gemini should store it's result. If not provided then
10. ___--outfile___: Path to a file where Gemini should store it's result. If not provided then
standard out is used.
62 changes: 51 additions & 11 deletions store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,26 @@ func New(schema *gemini.Schema, testCluster *gocql.ClusterConfig, oracleCluster
Help: "How many CQL requests processed, partitioned by system and CQL query type aka 'method' (batch, delete, insert, update).",
}, []string{"system", "method"},
)

var oracleStore storeLoader
var validations bool
if oracleCluster != nil {
oracleStore = &cqlStore{
session: newSession(oracleCluster),
schema: schema,
system: "oracle",
ops: ops,
maxRetriesMutate: cfg.MaxRetriesMutate + 10,
maxRetriesMutateSleep: cfg.MaxRetriesMutateSleep,
logger: logger,
}
validations = true
} else {
oracleStore = &noOpStore{
system: "oracle",
}
}

return &delegatingStore{
testStore: &cqlStore{
session: newSession(testCluster),
Expand All @@ -64,22 +84,40 @@ func New(schema *gemini.Schema, testCluster *gocql.ClusterConfig, oracleCluster
maxRetriesMutateSleep: cfg.MaxRetriesMutateSleep,
logger: logger,
},
oracleStore: &cqlStore{
session: newSession(oracleCluster),
schema: schema,
system: "oracle",
ops: ops,
maxRetriesMutate: cfg.MaxRetriesMutate + 10,
maxRetriesMutateSleep: cfg.MaxRetriesMutateSleep,
logger: logger,
},
logger: logger.Named("delegating_store"),
oracleStore: oracleStore,
validations: validations,
logger: logger.Named("delegating_store"),
}
}

type noOpStore struct {
system string
}

func (n *noOpStore) mutate(context.Context, qb.Builder, time.Time, ...interface{}) error {
return nil
}

func (n *noOpStore) load(context.Context, qb.Builder, []interface{}) ([]map[string]interface{}, error) {
return nil, nil
}

func (n *noOpStore) Close() error {
return nil
}

func (n *noOpStore) name() string {
return n.system
}

func (n *noOpStore) close() error {
return nil
}

type delegatingStore struct {
oracleStore storeLoader
testStore storeLoader
validations bool
logger *zap.Logger
}

Expand Down Expand Up @@ -109,7 +147,9 @@ func (ds delegatingStore) Check(ctx context.Context, table *gemini.Table, builde
if err != nil {
return errors.Wrapf(err, "unable to load check data from the oracle store")
}

if !ds.validations {
return nil
}
if len(testRows) != len(oracleRows) {
testSet := strset.New(pks(table, testRows)...)
oracleSet := strset.New(pks(table, oracleRows)...)
Expand Down

0 comments on commit dcad380

Please sign in to comment.