Skip to content
This repository was archived by the owner on Dec 8, 2021. It is now read-only.

Commit 9aceb93

Browse files
authored
bug: reduce number of admin operations for smoke test (#1125)
Use a single operation to create the database and all the tables that might be needed. This reduces the number of admin operations in the smoke tests by a factor of 28. Because each smoke test then becomes "fast" (a couple of seconds) there is no need to parallelize them, which simplifies a lot of the locking strategy.
1 parent 6e82ef3 commit 9aceb93

File tree

2 files changed

+79
-112
lines changed

2 files changed

+79
-112
lines changed

google/cloud/spanner/benchmarks/multiple_rows_cpu_benchmark.cc

Lines changed: 77 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class Experiment {
6868
public:
6969
virtual ~Experiment() = default;
7070

71+
virtual std::string AdditionalDdlStatement() = 0;
7172
virtual Status SetUp(Config const& config, cs::Database const& database) = 0;
7273
virtual Status TearDown(Config const& config,
7374
cs::Database const& database) = 0;
@@ -123,7 +124,17 @@ int main(int argc, char* argv[]) {
123124
std::cout << config << std::flush;
124125

125126
cs::DatabaseAdminClient admin_client;
126-
auto created = admin_client.CreateDatabase(database, {});
127+
std::vector<std::string> additional_statements = [&available, generator] {
128+
std::vector<std::string> statements;
129+
for (auto const& kv : available) {
130+
auto experiment = kv.second(generator);
131+
auto s = experiment->AdditionalDdlStatement();
132+
if (s.empty()) continue;
133+
statements.push_back(std::move(s));
134+
}
135+
return statements;
136+
}();
137+
auto created = admin_client.CreateDatabase(database, additional_statements);
127138
std::cout << "# Waiting for database creation to complete " << std::flush;
128139
for (;;) {
129140
auto status = created.wait_for(std::chrono::seconds(1));
@@ -294,37 +305,19 @@ class ExperimentImpl {
294305

295306
static int constexpr kColumnCount = 10;
296307

297-
Status CreateTable(Config const&, cs::Database const& database,
298-
std::string const& table_name) {
308+
std::string CreateTableStatement(std::string const& table_name) {
299309
std::string statement = "CREATE TABLE " + table_name;
300310
statement += " (Key INT64 NOT NULL,\n";
301311
for (int i = 0; i != kColumnCount; ++i) {
302312
statement +=
303313
"Data" + std::to_string(i) + " " + Traits::SpannerDataType() + ",\n";
304314
}
305315
statement += ") PRIMARY KEY (Key)";
306-
cs::DatabaseAdminClient admin_client;
307-
auto created = admin_client.UpdateDatabase(database, {statement});
308-
std::cout << "# Waiting for table creation to complete " << std::flush;
309-
for (;;) {
310-
auto status = created.wait_for(std::chrono::seconds(1));
311-
if (status == std::future_status::ready) break;
312-
std::cout << '.' << std::flush;
313-
}
314-
std::cout << " DONE\n";
315-
auto db = created.get();
316-
if (!db) {
317-
std::cerr << "Error creating table: " << db.status() << "\n";
318-
return std::move(db).status();
319-
}
320-
return {};
316+
return statement;
321317
}
322318

323319
Status FillTable(Config const& config, cs::Database const& database,
324320
std::string const& table_name) {
325-
auto status = CreateTable(config, database, table_name);
326-
if (!status.ok()) return status;
327-
328321
// We need to populate some data or all the requests to read will fail.
329322
cs::Client client(cs::MakeConnection(database));
330323
std::cout << "# Populating database " << std::flush;
@@ -424,6 +417,24 @@ class ExperimentImpl {
424417
std::cout << "# " << s << std::endl;
425418
}
426419

420+
std::pair<std::vector<cs::Client>,
421+
std::vector<std::shared_ptr<cs::internal::SpannerStub>>>
422+
CreateClientsAndStubs(Config const& config, cs::Database const& database) {
423+
std::vector<cs::Client> clients;
424+
std::vector<std::shared_ptr<cs::internal::SpannerStub>> stubs;
425+
std::cout << "# Creating clients and stubs " << std::flush;
426+
for (int i = 0; i != config.maximum_clients; ++i) {
427+
auto options = cs::ConnectionOptions().set_channel_pool_domain(
428+
"task:" + std::to_string(i));
429+
clients.emplace_back(cs::Client(cs::MakeConnection(database, options)));
430+
stubs.emplace_back(
431+
cs::internal::CreateDefaultSpannerStub(options, /*channel_id=*/0));
432+
std::cout << '.' << std::flush;
433+
}
434+
std::cout << " DONE\n";
435+
return {clients, stubs};
436+
}
437+
427438
private:
428439
Status FillTableTask(Config const& config, cs::Client client,
429440
std::string const& table_name, int task_count,
@@ -446,7 +457,7 @@ class ExperimentImpl {
446457
auto mutation = cs::InsertOrUpdateMutationBuilder(table_name, column_names);
447458
int current_mutations = 0;
448459

449-
auto maybe_flush = [&, this](bool force) -> Status {
460+
auto maybe_flush = [&](bool force) -> Status {
450461
if (current_mutations == 0) {
451462
return {};
452463
}
@@ -458,7 +469,7 @@ class ExperimentImpl {
458469
[&m](cs::Transaction const&) { return cs::Mutations{m}; });
459470
if (!result) {
460471
std::lock_guard<std::mutex> lk(mu_);
461-
std::cerr << "# Error in Commit() " << result.status() << "\n";
472+
std::cout << "# Error in Commit() " << result.status() << "\n";
462473
return std::move(result).status();
463474
}
464475
mutation = cs::InsertOrUpdateMutationBuilder(table_name, column_names);
@@ -475,6 +486,7 @@ class ExperimentImpl {
475486
if (key % task_count != task_id) continue;
476487
// Have one of the threads report progress about 50 times.
477488
if (task_id == 0 && key % report_period == 0) {
489+
std::lock_guard<std::mutex> lk(mu_);
478490
std::cout << '.' << std::flush;
479491
}
480492
mutation.EmplaceRow(key, value0, value1, value2, value3, value4, value5,
@@ -510,6 +522,10 @@ class ReadExperiment : public Experiment {
510522
: impl_(generator),
511523
table_name_("ReadExperiment_" + Traits::TableSuffix()) {}
512524

525+
std::string AdditionalDdlStatement() override {
526+
return impl_.CreateTableStatement(table_name_);
527+
}
528+
513529
Status SetUp(Config const& config, cs::Database const& database) override {
514530
return impl_.FillTable(config, database, table_name_);
515531
}
@@ -520,16 +536,7 @@ class ReadExperiment : public Experiment {
520536
// Create enough clients and stubs for the worst case
521537
std::vector<cs::Client> clients;
522538
std::vector<std::shared_ptr<cs::internal::SpannerStub>> stubs;
523-
std::cout << "# Creating clients and stubs " << std::flush;
524-
for (int i = 0; i != config.maximum_clients; ++i) {
525-
auto options = cs::ConnectionOptions().set_channel_pool_domain(
526-
"task:" + std::to_string(i));
527-
clients.emplace_back(cs::Client(cs::MakeConnection(database, options)));
528-
stubs.emplace_back(
529-
cs::internal::CreateDefaultSpannerStub(options, /*channel_id=*/0));
530-
std::cout << '.' << std::flush;
531-
}
532-
std::cout << " DONE\n";
539+
std::tie(clients, stubs) = impl_.CreateClientsAndStubs(config, database);
533540

534541
// Capture some overall getrusage() statistics as comments.
535542
SimpleTimer overall;
@@ -593,7 +600,7 @@ class ReadExperiment : public Experiment {
593600
if (!session) {
594601
std::ostringstream os;
595602
os << "SESSION ERROR = " << session.status();
596-
impl_.LogError(os.str());
603+
impl_.LogError(std::move(os).str());
597604
return {};
598605
}
599606

@@ -733,26 +740,20 @@ class SelectExperiment : public Experiment {
733740
: impl_(generator),
734741
table_name_("SelectExperiment_" + Traits::TableSuffix()) {}
735742

743+
std::string AdditionalDdlStatement() override {
744+
return impl_.CreateTableStatement(table_name_);
745+
}
746+
736747
Status SetUp(Config const& config, cs::Database const& database) override {
737748
return impl_.FillTable(config, database, table_name_);
738749
}
739750

740751
Status TearDown(Config const&, cs::Database const&) override { return {}; }
741752

742753
Status Run(Config const& config, cs::Database const& database) override {
743-
// Create enough clients and stubs for the worst case
744754
std::vector<cs::Client> clients;
745755
std::vector<std::shared_ptr<cs::internal::SpannerStub>> stubs;
746-
std::cout << "# Creating clients and stubs " << std::flush;
747-
for (int i = 0; i != config.maximum_clients; ++i) {
748-
auto options = cs::ConnectionOptions().set_channel_pool_domain(
749-
"task:" + std::to_string(i));
750-
clients.emplace_back(cs::Client(cs::MakeConnection(database, options)));
751-
stubs.emplace_back(
752-
cs::internal::CreateDefaultSpannerStub(options, /*channel_id=*/0));
753-
std::cout << '.' << std::flush;
754-
}
755-
std::cout << " DONE\n";
756+
std::tie(clients, stubs) = impl_.CreateClientsAndStubs(config, database);
756757

757758
// Capture some overall getrusage() statistics as comments.
758759
SimpleTimer overall;
@@ -816,7 +817,7 @@ class SelectExperiment : public Experiment {
816817
if (!session) {
817818
std::ostringstream os;
818819
os << "SESSION ERROR = " << session.status();
819-
impl_.LogError(os.str());
820+
impl_.LogError(std::move(os).str());
820821
return {};
821822
}
822823

@@ -973,26 +974,20 @@ class UpdateExperiment : public Experiment {
973974
: impl_(generator),
974975
table_name_("UpdateExperiment_" + Traits::TableSuffix()) {}
975976

977+
std::string AdditionalDdlStatement() override {
978+
return impl_.CreateTableStatement(table_name_);
979+
}
980+
976981
Status SetUp(Config const& config, cs::Database const& database) override {
977982
return impl_.FillTable(config, database, table_name_);
978983
}
979984

980985
Status TearDown(Config const&, cs::Database const&) override { return {}; }
981986

982987
Status Run(Config const& config, cs::Database const& database) override {
983-
// Create enough clients and stubs for the worst case
984988
std::vector<cs::Client> clients;
985989
std::vector<std::shared_ptr<cs::internal::SpannerStub>> stubs;
986-
std::cout << "# Creating clients and stubs " << std::flush;
987-
for (int i = 0; i != config.maximum_clients; ++i) {
988-
auto options = cs::ConnectionOptions().set_channel_pool_domain(
989-
"task:" + std::to_string(i));
990-
clients.emplace_back(cs::Client(cs::MakeConnection(database, options)));
991-
stubs.emplace_back(
992-
cs::internal::CreateDefaultSpannerStub(options, /*channel_id=*/0));
993-
std::cout << '.' << std::flush;
994-
}
995-
std::cout << " DONE\n";
990+
std::tie(clients, stubs) = impl_.CreateClientsAndStubs(config, database);
996991

997992
// Capture some overall getrusage() statistics as comments.
998993
SimpleTimer overall;
@@ -1058,7 +1053,7 @@ class UpdateExperiment : public Experiment {
10581053
if (!session) {
10591054
std::ostringstream os;
10601055
os << "SESSION ERROR = " << session.status();
1061-
impl_.LogError(os.str());
1056+
impl_.LogError(std::move(os).str());
10621057
return {};
10631058
}
10641059

@@ -1240,26 +1235,18 @@ class MutationExperiment : public Experiment {
12401235
: impl_(generator),
12411236
table_name_("MutationExperiment_" + Traits::TableSuffix()) {}
12421237

1243-
Status SetUp(Config const& config, cs::Database const& database) override {
1244-
return impl_.CreateTable(config, database, table_name_);
1238+
std::string AdditionalDdlStatement() override {
1239+
return impl_.CreateTableStatement(table_name_);
12451240
}
12461241

1242+
Status SetUp(Config const&, cs::Database const&) override { return {}; }
1243+
12471244
Status TearDown(Config const&, cs::Database const&) override { return {}; }
12481245

12491246
Status Run(Config const& config, cs::Database const& database) override {
1250-
// Create enough clients and stubs for the worst case
12511247
std::vector<cs::Client> clients;
12521248
std::vector<std::shared_ptr<cs::internal::SpannerStub>> stubs;
1253-
std::cout << "# Creating clients and stubs " << std::flush;
1254-
for (int i = 0; i != config.maximum_clients; ++i) {
1255-
auto options = cs::ConnectionOptions().set_channel_pool_domain(
1256-
"task:" + std::to_string(i));
1257-
clients.emplace_back(cs::Client(cs::MakeConnection(database, options)));
1258-
stubs.emplace_back(
1259-
cs::internal::CreateDefaultSpannerStub(options, /*channel_id=*/0));
1260-
std::cout << '.' << std::flush;
1261-
}
1262-
std::cout << " DONE\n";
1249+
std::tie(clients, stubs) = impl_.CreateClientsAndStubs(config, database);
12631250

12641251
random_keys_.resize(config.table_size);
12651252
std::iota(random_keys_.begin(), random_keys_.end(), 0);
@@ -1332,7 +1319,7 @@ class MutationExperiment : public Experiment {
13321319
if (!session) {
13331320
std::ostringstream os;
13341321
os << "SESSION ERROR = " << session.status();
1335-
impl_.LogError(os.str());
1322+
impl_.LogError(std::move(os).str());
13361323
return {};
13371324
}
13381325

@@ -1473,13 +1460,15 @@ class RunAllExperiment : public Experiment {
14731460
public:
14741461
explicit RunAllExperiment(google::cloud::internal::DefaultPRNG generator)
14751462
: generator_(generator) {}
1463+
1464+
std::string AdditionalDdlStatement() override { return {}; }
14761465
Status SetUp(Config const&, cs::Database const&) override { return {}; }
14771466
Status TearDown(Config const&, cs::Database const&) override { return {}; }
14781467

1479-
Status Run(Config const& cfg, cs::Database const& /*database*/) override {
1468+
Status Run(Config const& cfg, cs::Database const& database) override {
14801469
// Smoke test all the experiments by running a very small version of each.
14811470

1482-
std::vector<std::future<google::cloud::Status>> tasks;
1471+
Status last_error;
14831472
for (auto& kv : AvailableExperiments()) {
14841473
// Do not recurse, skip this experiment.
14851474
if (kv.first == "run-all") continue;
@@ -1496,42 +1485,22 @@ class RunAllExperiment : public Experiment {
14961485

14971486
auto experiment = kv.second(generator_);
14981487

1499-
// TODO(#1119) - tests disabled until we can stay within admin op quota
1500-
#if 0
1501-
tasks.push_back(std::async(
1502-
std::launch::async,
1503-
[](Config config, cs::Database const& database,
1504-
std::mutex& mu, std::unique_ptr<Experiment> experiment) {
1505-
{
1506-
std::lock_guard<std::mutex> lk(mu);
1507-
std::cout << "# Smoke test for experiment\n";
1508-
std::cout << config << "\n" << std::flush;
1509-
}
1510-
auto status = experiment->SetUp(config, database);
1511-
if (!status.ok()) {
1512-
std::lock_guard<std::mutex> lk(mu);
1513-
std::cout << "# ERROR in SetUp: " << status << "\n";
1514-
return status;
1515-
}
1516-
config.use_only_clients = true;
1517-
experiment->Run(config, database);
1518-
config.use_only_stubs = true;
1519-
experiment->Run(config, database);
1520-
experiment->TearDown(config, database);
1521-
return google::cloud::Status();
1522-
},
1523-
config, database, std::ref(mu_), std::move(experiment)));
1524-
#endif
1525-
}
1526-
1527-
Status status;
1528-
for (auto& task : tasks) {
1529-
auto s = task.get();
1530-
if (!s.ok()) {
1531-
status = std::move(s);
1488+
std::cout << "# Smoke test for experiment\n";
1489+
std::cout << config << "\n" << std::flush;
1490+
auto status = experiment->SetUp(config, database);
1491+
if (!status.ok()) {
1492+
std::cout << "# ERROR in SetUp: " << status << "\n";
1493+
last_error = status;
1494+
continue;
15321495
}
1496+
config.use_only_clients = true;
1497+
experiment->Run(config, database);
1498+
config.use_only_stubs = true;
1499+
experiment->Run(config, database);
1500+
experiment->TearDown(config, database);
15331501
}
1534-
return status;
1502+
1503+
return last_error;
15351504
}
15361505

15371506
private:

google/cloud/spanner/benchmarks/single_row_throughput_benchmark.cc

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,8 @@ class RunAllExperiment : public Experiment {
660660
public:
661661
void SetUp(Config const&, cloud_spanner::Database const&) override {}
662662

663-
void Run(Config const& cfg, cloud_spanner::Database const& /*database*/,
664-
SampleSink const&) override {
663+
void Run(Config const& cfg, cloud_spanner::Database const& database,
664+
SampleSink const& sink) override {
665665
// Smoke test all the experiments by running a very small version of each.
666666
for (auto& kv : AvailableExperiments()) {
667667
// Do not recurse, skip this experiment.
@@ -672,10 +672,8 @@ class RunAllExperiment : public Experiment {
672672
config.iteration_duration = std::chrono::seconds(1);
673673
std::cout << "# Smoke test for experiment: " << kv.first << "\n";
674674
// TODO(#1119) - tests disabled until we can stay within admin op quota
675-
#if 0
676675
kv.second->SetUp(config, database);
677676
kv.second->Run(config, database, sink);
678-
#endif
679677
}
680678
}
681679
};

0 commit comments

Comments
 (0)