From 9843b520c1ed06f2233eefa10d4de8073fb33c24 Mon Sep 17 00:00:00 2001 From: Christian Dietrich Date: Wed, 3 Jul 2013 22:10:18 +0200 Subject: [PATCH] dbcampaign: select multiple variants/benchmark pairs The variant/benchmark selection now can use SQL LIKE syntax, all unfinished pilots from all selected variants are sent to the clients. E.g.: ./cored-voter-server -v x86-cored-voter -b simple-% -p basic Will select the fsppilots in the variants: - x86-cored-voter/simple-ip/basic - x86-cored-voter/simple-instr/basic The variant and benchmark information is now sent within the fsppilot. Change-Id: I287bfcddc478d0b79d89e156d6f5bf8188674532 --- src/core/comm/DatabaseCampaignMessage.proto | 2 + src/core/cpn/DatabaseCampaign.cc | 109 +++++++++++--------- src/core/cpn/DatabaseCampaign.hpp | 15 ++- src/core/util/Database.cc | 44 +++++--- src/core/util/Database.hpp | 14 +++ 5 files changed, 124 insertions(+), 60 deletions(-) diff --git a/src/core/comm/DatabaseCampaignMessage.proto b/src/core/comm/DatabaseCampaignMessage.proto index ae1e3d09..e66266cc 100644 --- a/src/core/comm/DatabaseCampaignMessage.proto +++ b/src/core/comm/DatabaseCampaignMessage.proto @@ -11,4 +11,6 @@ message DatabaseCampaignMessage { required int32 injection_instr = 4 [(sql_ignore) = true]; optional int32 injection_instr_absolute = 5 [(sql_ignore) = true]; required int32 data_address = 6 [(sql_ignore) = true]; + required string variant = 7 [(sql_ignore) = true]; + required string benchmark = 8 [(sql_ignore) = true]; } \ No newline at end of file diff --git a/src/core/cpn/DatabaseCampaign.cc b/src/core/cpn/DatabaseCampaign.cc index 2acf6326..cb8bf998 100644 --- a/src/core/cpn/DatabaseCampaign.cc +++ b/src/core/cpn/DatabaseCampaign.cc @@ -63,8 +63,7 @@ bool DatabaseCampaign::run() { pruner = "basic"; db = Database::cmdline_connect(); - variant_id = db->get_variant_id(variant, benchmark); - log_send << "Variant to use " << variant << "/" << benchmark << " (ID: " << variant_id << ")" << std::endl; + log_send << "Variant to use " << variant << "/" << benchmark << std::endl; fspmethod_id = db->get_fspmethod_id(pruner); log_send << "Pruner to use " << pruner << " (ID: " << fspmethod_id << ")" << std::endl; @@ -80,56 +79,17 @@ bool DatabaseCampaign::run() { boost::thread collect_thread(&DatabaseCampaign::collect_result_thread, this); #endif - /* Gather all unfinished jobs */ - int experiment_count; - std::string sql_select = "SELECT pilot_id, g.fspmethod_id, g.variant_id, p.injection_instr, p.injection_instr_absolute, g.data_address"; - std::stringstream ss; - ss << " FROM fspgroup g" - << " INNER JOIN fsppilot p ON p.id = g.pilot_id " - << " WHERE p.known_outcome = 0 " - << " AND g.fspmethod_id = " << fspmethod_id - << " AND g.variant_id = " << variant_id - << " AND (SELECT COUNT(*) FROM " + db_connect.result_table() + " as r WHERE r.pilot_id = g.pilot_id) < 8" - << " ORDER BY p.injection_instr"; - std::string sql_body = ss.str(); - - /* Get the number of unfinished experiments */ - MYSQL_RES *count = db->query(("SELECT COUNT(*) " + sql_body).c_str(), true); - MYSQL_ROW row = mysql_fetch_row(count); - experiment_count = atoi(row[0]); - - - MYSQL_RES *pilots = db->query_stream ((sql_select + sql_body).c_str()); - - log_send << "Found " << experiment_count << " unfinished experiments in database." << std::endl; - - sent_pilots = 0; - while ((row = mysql_fetch_row(pilots)) != 0) { - unsigned pilot_id = atoi(row[0]); - unsigned injection_instr = atoi(row[3]); - unsigned data_address = atoi(row[5]); - - DatabaseCampaignMessage pilot; - pilot.set_pilot_id(pilot_id); - pilot.set_fspmethod_id(fspmethod_id); - pilot.set_variant_id(variant_id); - pilot.set_injection_instr(injection_instr); - if (row[4]) { - unsigned injection_instr_absolute = atoi(row[4]); - pilot.set_injection_instr_absolute(injection_instr_absolute); - } - pilot.set_data_address(data_address); - - this->cb_send_pilot(pilot); - - if ((++sent_pilots) % 1000 == 0) { - log_send << "pushed " << sent_pilots << " pilots into the queue" << std::endl; + std::vector variants = db->get_variants(variant, benchmark); + for (std::vector::const_iterator it = variants.begin(); + it != variants.end(); ++it) { + if(!run_variant(*it)) { + log_send << "run_variant failed for " << it->variant << "/" << it->benchmark <query(("SELECT COUNT(*) " + sql_body).c_str(), true); + MYSQL_ROW row = mysql_fetch_row(count); + experiment_count = atoi(row[0]); + + + MYSQL_RES *pilots = db->query_stream ((sql_select + sql_body).c_str()); + + log_send << "Found " << experiment_count << " unfinished experiments in database. (" + << variant.variant << "/" << variant.benchmark << ")" << std::endl; + + sent_pilots = 0; + while ((row = mysql_fetch_row(pilots)) != 0) { + unsigned pilot_id = atoi(row[0]); + unsigned injection_instr = atoi(row[3]); + unsigned data_address = atoi(row[5]); + + + DatabaseCampaignMessage pilot; + pilot.set_pilot_id(pilot_id); + pilot.set_fspmethod_id(fspmethod_id); + pilot.set_variant_id(variant.id); + pilot.set_injection_instr(injection_instr); + pilot.set_variant(variant.variant); + pilot.set_benchmark(variant.benchmark); + if (row[4]) { + unsigned injection_instr_absolute = atoi(row[4]); + pilot.set_injection_instr_absolute(injection_instr_absolute); + } + pilot.set_data_address(data_address); + + this->cb_send_pilot(pilot); + + if ((++sent_pilots) % 1000 == 0) { + log_send << "pushed " << sent_pilots << " pilots into the queue" << std::endl; + } + } + return true; + +} diff --git a/src/core/cpn/DatabaseCampaign.hpp b/src/core/cpn/DatabaseCampaign.hpp index b4f40e2e..f81815d1 100644 --- a/src/core/cpn/DatabaseCampaign.hpp +++ b/src/core/cpn/DatabaseCampaign.hpp @@ -24,7 +24,6 @@ class DatabaseCampaign : public Campaign { Database *db; // !< The database connection object DatabaseProtobufAdapter db_connect; - int variant_id; // !< Which variant do we work on (from CMDLINE) int fspmethod_id; // !< Which fspmethod should be put out to the clients void collect_result_thread(); @@ -41,6 +40,20 @@ public: */ virtual bool run(); + /** + * Is called by run() for every variant, returned by the variant + * filter (SQL LIKE). + * @return \c true if the campaign was successful, \c false otherwise + */ + virtual bool run_variant(fail::Database::Variant); + + /** + * How many results have to are expected from each fsppilot. If + * there are less result rows, the pilot will be again sent to the clients + * @return \c exptected number of results + */ + virtual int expected_number_of_results(std::string variant, std::string benchmark) { return 8;} + /** * Callback function that can be used to add command line options * to the campaign diff --git a/src/core/util/Database.cc b/src/core/util/Database.cc index f567882d..bf18560d 100644 --- a/src/core/util/Database.cc +++ b/src/core/util/Database.cc @@ -74,36 +74,56 @@ my_ulonglong Database::affected_rows() } -int Database::get_variant_id(const std::string &variant, const std::string &benchmark) -{ +std::vector Database::get_variants(const std::string &variant, const std::string &benchmark) { + std::vector result; + if (!query("CREATE TABLE IF NOT EXISTS variant (" " id int(11) NOT NULL AUTO_INCREMENT," " variant varchar(255) NOT NULL," " benchmark varchar(255) NOT NULL," " PRIMARY KEY (id)," "UNIQUE KEY variant (variant,benchmark))")) { - return 0; + return result; } - int variant_id; std::stringstream ss; // FIXME SQL injection possible - ss << "SELECT id FROM variant WHERE variant LIKE '" << variant << "' AND benchmark LIKE '" << benchmark << "'"; + ss << "SELECT id, variant, benchmark FROM variant WHERE variant LIKE '" << variant << "' AND benchmark LIKE '" << benchmark << "'"; MYSQL_RES *variant_id_res = query(ss.str().c_str(), true); + if (!variant_id_res) { - return 0; + return result; } else if (mysql_num_rows(variant_id_res)) { - MYSQL_ROW row = mysql_fetch_row(variant_id_res); - variant_id = atoi(row[0]); - } else { - ss.str(""); + for (unsigned int i = 0; i < mysql_num_rows(variant_id_res); ++i) { + MYSQL_ROW row = mysql_fetch_row(variant_id_res); + Variant var; + var.id = atoi(row[0]); + var.variant = std::string(row[1]); + var.benchmark = std::string(row[2]); + result.push_back(var); + } + } + + return result; +} + +int Database::get_variant_id(const std::string &variant, const std::string &benchmark) +{ + std::vector variants = get_variants(variant, benchmark); + if (variants.size() == 0) { + // Insert a new variant + std::stringstream ss; ss << "INSERT INTO variant (variant, benchmark) VALUES ('" << variant << "', '" << benchmark << "')"; if (!query(ss.str().c_str())) { return 0; } - variant_id = mysql_insert_id(handle); + return mysql_insert_id(handle); + } else if (variants.size() == 1) { + return variants[0].id; + } else { + LOG << "Variant identifier " << variant << "/" << benchmark << " is ambigious!" << std::endl; + return 0; } - return variant_id; } int Database::get_fspmethod_id(const std::string &method) diff --git a/src/core/util/Database.hpp b/src/core/util/Database.hpp index 96a99f58..0a520022 100644 --- a/src/core/util/Database.hpp +++ b/src/core/util/Database.hpp @@ -5,6 +5,7 @@ #include #endif +#include #include #include #include @@ -31,6 +32,12 @@ namespace fail { Database(const std::string &username, const std::string &host, const std::string &database); ~Database() { mysql_close(handle); } + struct Variant { + int id; + std::string variant; + std::string benchmark; + }; + /** * Get the variant id for a specific variant/benchmark pair, * if it isn't defined in the database (variant table), it is @@ -38,6 +45,13 @@ namespace fail { */ int get_variant_id(const std::string &variant, const std::string &benchmark); + /** + * Get all variants that fit the given patterns (will be + * queried with SQL LIKE). + */ + std::vector get_variants(const std::string &variant, const std::string &benchmark); + + /** * Get the fault space pruning method id for a specific * pruning method, if it isn't defined in the database