#include #include #include #include #include #include #include #include #include #include #include "db_functions.h" #include "avail_mem.h" #include "keyvalue.h" #include "db.h" #include "../ag_gen/exploit.h" #include "../ag_gen/edge.h" #include "../ag_gen/quality.h" #include "../ag_gen/topology.h" #include "../ag_gen/asset.h" #include "../ag_gen/factbase.h" #include "../ag_gen/network_state.h" #include static DB db; //static DB db2; //static DB db3; //static DB db4; void init_db(std::string connect_str) { db.connect(connect_str); //db.connect("dbname=ag_parallel user=mingli password=N7SBaxkXdoA5venS"); //db2.connect("postgresql://catherine:1234@localhost:5432/ag_parallel"); //db3.connect("postgresql://mingli:f5410116@localhost:5432/ag_parallel"); //db4.connect("postgresql://rosemary:110726@localhost:5432/ag_parallel"); /*db.exec("BEGIN;"); db.execAsync("DELETE FROM factbase_item WHERE TRUE;"); db.execAsync("DELETE FROM edge_asset_binding WHERE TRUE;"); db.execAsync("DELETE FROM edge WHERE TRUE;"); db.execAsync("DELETE FROM factbase WHERE TRUE;"); db.execAsync("DELETE FROM keyvalue WHERE TRUE;"); db.execAsync("DELETE FROM exploit_postcondition WHERE TRUE;"); db.execAsync("DELETE FROM exploit_precondition WHERE TRUE;"); db.execAsync("DELETE FROM exploit WHERE TRUE;"); db.execAsync("DELETE FROM quality WHERE TRUE;"); db.execAsync("DELETE FROM topology WHERE TRUE;"); db.execAsync("DELETE FROM asset WHERE TRUE;"); db.execAsync("COMMIT;");*/ } void import_models(std::string nm, std::string xp) { db.exec(nm); db.exec(xp); } int get_max_factbase_id() { std::vector res = db.exec("SELECT MAX(id) FROM factbase;"); return stoi(res[0][0]); } std::vector fetch_keyvalues() { std::vector rows = db.exec("SELECT property FROM keyvalue;"); std::vector kvs{}; for(auto &row : rows) { kvs.push_back(row[0]); } return kvs; } Keyvalue fetch_kv() { auto kv_raw = fetch_keyvalues(); Keyvalue kv{}; kv.populate(kv_raw); return kv; } void delete_edges(std::vector edge_ids) { std::ostringstream ss; ss << "("; std::copy(edge_ids.begin(), edge_ids.end() - 1, std::ostream_iterator(ss, ", ")); ss << edge_ids.back() << ")"; std::string ids = ss.str(); std::string sql = "DELETE FROM edge_asset_binding WHERE edge_id IN " + ids + "; DELETE FROM edge WHERE id IN" + ids + ";"; db.exec(sql); } GraphInfo fetch_graph_info() { std::vector factbase_rows = db.exec("SELECT id FROM factbase ORDER BY id;"); std::vector edge_rows = db.exec("SELECT * FROM edge ORDER BY id;"); std::vector factbase_ids; factbase_ids.resize(factbase_rows.size()); std::transform(factbase_rows.begin(), factbase_rows.end(), factbase_ids.begin(), [](Row row){ return std::stoi(row[0]); }); std::vector> edges; for (auto& row : edge_rows) { int id = std::stoi(row[0]); int from_node = std::stoi(row[1]); int to_node = std::stoi(row[2]); int exploit_id = std::stoi(row[3]); std::array arr = {id, from_node, to_node, exploit_id}; edges.push_back(arr); } return std::make_pair(factbase_ids, edges); } std::vector>> fetch_all_factbase_items() { std::vector>> fi; std::vector firows = db.exec("SELECT * FROM factbase_item;"); if (firows.empty()) throw CustomDBException(); int current_index = -1; for (auto firow : firows) { int index = stoi(firow[0]); if (index != current_index) { current_index = index; fi.emplace_back(); } size_t st; sscanf(firow[1].c_str(), "%zu", &st); fi[index].push_back(make_pair(st, firow[2])); } return fi; } std::vector> fetch_one_factbase_items(int index) { std::vector> fi; std::vector firows = db.exec("SELECT f,type FROM factbase_item WHERE factbase_id=" + std::to_string(index) + ";"); if (firows.empty()) throw CustomDBException(); for (auto firow : firows) { size_t st; sscanf(firow[0].c_str(), "%zu", &st); fi.push_back(std::make_pair(st, firow[1])); } return fi; } std::vector fetch_unique_values() { //from the database to fetch all the values and properties and put them in a string vector std::string keyvaluesql = "SELECT property FROM quality\n" "UNION DISTINCT\n" "SELECT value FROM quality\n" "UNION DISTINCT\n" //"SELECT op FROM quality\n" //"UNION DISTINCT\n" "SELECT property FROM exploit_postcondition\n" "UNION DISTINCT\n" "SELECT value FROM exploit_postcondition\n" "UNION DISTINCT\n" "SELECT property FROM topology\n" "UNION DISTINCT\n" "SELECT value FROM topology;";//all the values and properties will be distinct from each other std::vector rows = db.exec(keyvaluesql); std::vector attrs; //this will be a set of values and properties for(auto &row : rows) { attrs.push_back(row[0]); } return attrs; } /** * @brief Fetches all possible quality attributes. * * @return Returns a vector of strings with all possible quality attributes. */ std::vector fetch_quality_attributes() { std::vector attrs; std::vector qrows = db.exec("SELECT DISTINCT property FROM quality;"); std::vector erows = db.exec("SELECT DISTINCT property FROM exploit_postcondition;"); for (auto &row : qrows) { std::string prop = row[0]; attrs.push_back(prop); } for (auto &row : erows) { std::string prop = row[0]; attrs.push_back(prop); } return attrs; } /** * @brief Fetches all possible quality values. * * @return Returns */ std::vector fetch_quality_values() { std::vector vals; std::vector qrows = db.exec("SELECT DISTINCT value FROM quality;"); std::vector erows = db.exec("SELECT DISTINCT value FROM exploit_postcondition;"); for (auto &row : qrows) { std::string val = row[0]; vals.push_back(val); } for (auto &row : erows) { std::string val = row[0]; vals.push_back(val); } return vals; } std::vector fetch_topology_attributes() { std::vector attrs; std::vector rows = db.exec("SELECT DISTINCT property FROM topology;"); for (auto &row : rows) { std::string prop = row[0]; attrs.push_back(prop); } return attrs; } /** * @brief Fetches all possible topology values. * * @return Returns a vector of strings with all possible topology values */ std::vector fetch_topology_values() { std::vector vals; std::vector rows = db.exec("SELECT DISTINCT value FROM topology;"); for (auto &row : rows) { std::string val = row[0]; vals.push_back(val); } return vals; } /** * @brief Fetches the preconditions of an Exploit from the database. */ std::unordered_map< int, std::tuple, std::vector>> fetch_exploit_preconds() { std::vector rows = db.exec("SELECT * FROM exploit_precondition;"); std::unordered_map< int, std::tuple, std::vector>> precond_map; int curr_id = -1; std::vector preconds_q; std::vector preconds_t; for (auto &row : rows) { int type = stoi(row[2]); int exploit_id = stoi(row[1]); if (exploit_id != curr_id) { if (curr_id != -1) { std::tuple, std::vector> tup{preconds_q, preconds_t}; precond_map[curr_id] = tup; preconds_q.clear(); preconds_t.clear(); } curr_id = exploit_id; } if (type == 0) {//type 0 is quality-typed precondition int param1 = stoi(row[3]); std::string property = row[5]; std::string value = row[6]; std::string op = row[7]; ParameterizedQuality qual{param1, property, value, op}; preconds_q.push_back(qual); } else { //type 1 is topology-typed precondition int param1 = stoi(row[3]); int param2 = stoi(row[4]); std::string property = row[5]; std::string value = row[6]; std::string op = row[7]; std::string dir_str = row[8]; DIRECTION_T dir; if(dir_str == "->") { dir = FORWARD_T; } else if (dir_str == "<-") { dir = BACKWARD_T; } else if (dir_str == "<->") { dir = BIDIRECTION_T; } else { std::cerr << "Unknown direction '" << dir_str << "'" << std::endl; exit(1); } ParameterizedTopology topo{param1, param2, dir, property, op, value}; //parameterized into a struct preconds_t.push_back(topo); } } std::tuple, std::vector> tup{ preconds_q, preconds_t}; precond_map[curr_id] = tup;//the last exploit's preconditions (quality and topology) also needs to put in the unordered map return precond_map; //the unordered map use the exploit id as the key, the value of each item is the parameterized quality and topology } /** * @brief Fetches the postconditions of an Exploit from the database. */ std::unordered_map< int, std::tuple, std::vector>> fetch_exploit_postconds() { std::vector rows = db.exec("SELECT * FROM exploit_postcondition;"); std::unordered_map< int, std::tuple, std::vector>> postcond_map; int curr_id = -1; std::vector postconds_q; //PostconditionQ and PostconditionT are defined in exploit.h std::vector postconds_t; for (auto &row : rows) { int type = stoi(row[2]);//type 0 change on quality, 1 change on topology(seldom) int exploit_id = stoi(row[1]); std::string action_str = row[9]; ACTION_T action; // std::cout << action_str << "\n"; if(action_str == "add" || action_str == "insert") { action = ADD_T; } else if (action_str == "update") { action = UPDATE_T; } else if (action_str == "delete") { action = DELETE_T; } else { std::cout << "Bad Action '" << action_str << "'" << std::endl; exit(1); } if (exploit_id != curr_id) { if (curr_id != -1) { std::tuple, std::vector> tup{postconds_q, postconds_t}; postcond_map[curr_id] = tup; postconds_q.clear(); postconds_t.clear(); } curr_id = exploit_id; } if (type == 0) { int param1 = stoi(row[3]); std::string property = row[5]; std::string value = row[6]; std::string op = row[7]; ParameterizedQuality qual{param1, property, value, op}; postconds_q.push_back(std::make_tuple(action, qual)); } else { int param1 = stoi(row[3]); int param2 = stoi(row[4]); std::string property = row[5]; std::string value = row[6]; std::string op = row[7]; std::string dir_str = row[8]; DIRECTION_T dir; if(dir_str == "->") { dir = FORWARD_T; } else if (dir_str == "<-") { dir = BACKWARD_T; } else if (dir_str == "<->") { dir = BIDIRECTION_T; } else { std::cerr << "Unknown direction '" << dir_str << "'" << std::endl; exit(1); } ParameterizedTopology topo{param1, param2, dir, property, op, value}; postconds_t.push_back(std::make_tuple(action, topo)); } } std::tuple, std::vector> tup{ postconds_q, postconds_t}; postcond_map[curr_id] = tup; return postcond_map; } std::vector fetch_all_exploits() { std::vector exploits; std::vector rows = db.exec("SELECT * FROM exploit;"); auto pre = fetch_exploit_preconds(); auto post = fetch_exploit_postconds(); for (auto &row : rows) { int id = std::stoi(row[0]); std::string name = row[1]; int num_params = std::stoi(row[2]); std::string group = row[3]; auto preconds = pre[id]; auto postconds = post[id]; //Use Exploit class's obj exploit to store each exploit's complete info, especially pre-and-post conditions Exploit exploit(id, name, num_params, group, preconds, postconds); exploits.push_back(exploit);//push into exploits vector } return exploits; //the vector will be returned to the calling function. } /** * @brief Gets all of the qualities for the Asset * @details Grabs all of the qualities in the database associated with * the Asset's ID and gives them to the Asset */ std::unordered_map> fetch_asset_qualities(Keyvalue &facts) { std::vector rows = db.exec("SELECT * FROM quality;"); std::unordered_map> qmap; int curr_id = -1; std::vector qualities; for (auto &row : rows) { int asset_id = std::stoi(row[0]); std::string property = row[1]; std::string op = row[2]; std::string value = row[3]; // cout << "op: " << op << endl; if (asset_id != curr_id) { if (curr_id != -1) { //a new asset's quality has been reached qmap[curr_id] = qualities; //all the old qualities are put in the old asset's element in the unordered map qualities.clear(); //clear the qualities for the new asset } curr_id = asset_id; //unconditional update curr_id to asset_id whenever a new asset is reached } // Quality qual(asset_id, property, "=", value); // qualities.push_back(qual); qualities.emplace_back(asset_id, property, op, value, facts);//each asset's qualities will be put in a dedicated Quality vector } qmap[curr_id] = qualities;//the last asset's qualities must be put in the unordered map too return qmap; } /** * @brief Gets all of the Assets under the network * @details Grabs all of the Assets in the database under the network given in * the argument and returns a vector of those Assets * * @param network Name of the network to grab from */ std::vector fetch_all_assets(Keyvalue &facts) { std::vector rows = db.exec("SELECT * FROM asset;"); std::vector new_assets; //use class Asset (in asset.h) to define a vector, each element will be an object auto qmap = fetch_asset_qualities(facts); //combine each asset with all its qualities for (auto &row : rows) { int id = std::stoi(row[0]); std::string name = row[1]; auto q = qmap[id]; //this returns a Quality vector, which includes all the records in the quality table related to the current id. new_assets.emplace_back(name, q); } return new_assets; } std::vector fetch_all_qualities(Keyvalue &facts) { std::vector qualities; std::vector rows = db.exec("SELECT * FROM quality;"); for (auto &row : rows) { int asset_id = std::stoi(row[0]); //stoi means string to integer, since rows is a vector of string vectors. The smallest elements in rows are string type. std::string property = row[1]; std::string op = row[2]; std::string value = row[3]; Quality qual(asset_id, property, op, value, facts); //associate each record from quality table with the facts(the hash_table and fact string vector). qualities.push_back(qual); } return qualities; } std::vector fetch_all_topologies(Keyvalue &facts) { std::vector topologies; std::vector rows = db.exec("SELECT * FROM topology;"); for (auto &row : rows) { int from_asset = std::stoi(row[0]); int to_asset = std::stoi(row[1]); std::string dir_str = row[2]; DIRECTION_T dir; //DIRECTION_T is a user defined enum type (in topology.h), it has three different values: FORWARD_T 0, BACKWARD_T 1, and BIDIRECTION_T 2 if(dir_str == "->") { dir = FORWARD_T; } else if (dir_str == "<-") { dir = BACKWARD_T; } else if (dir_str == "<->") { dir = BIDIRECTION_T; } else { std::cerr << "Unknown direction '" << dir_str << "'" << std::endl; exit(1); } std::string property = row[3]; std::string op = row[4]; std::string value = row[5]; Topology t(from_asset, to_asset, dir, property, op, value, facts); //associate each record from topology table with the facts topologies.push_back(t); } return topologies; } Keyvalue fetch_facts() { //Keyvalue is a class name(defined in Keyvalue.h), this function will return an Keyvalue obj Keyvalue initfacts; // initfacts.populate(fetch_quality_attributes()); // initfacts.populate(fetch_quality_values()); // initfacts.populate(fetch_topology_attributes()); // initfacts.populate(fetch_topology_values()); initfacts.populate(fetch_unique_values()); return initfacts; } // void save_ag_to_db(std::vector &factbase_items, // std::vector &factbases, std::vector &edges, // Keyvalue &factlist) { void save_ag_to_db(AGGenInstance &instance, bool save_keyvalue){ std::vector& factbase_items = instance.factbase_items; std::vector& factbases = instance.factbases; std::vector& edges = instance.edges; auto tot_sys_mem = getTotalSystemMemory(); Keyvalue& factlist = instance.facts; struct timeval t1,t2; /** backup cout buffer and redirect to states.txt **/ std::ofstream out("states.txt"); auto *coutbuf = std::cout.rdbuf(); std::cout.rdbuf(out.rdbuf()); //this part takes 0.3s gettimeofday(&t1,NULL); db.exec("BEGIN;"); if (!factbases.empty()){ //printf("The size of the factbases is %ld\n",factbases.size()); std::string factbase_sql_query = "INSERT INTO factbase VALUES "; int factbase_counter = 0; int flag = 0; double fbsize = 0; for (int i = 0; i < factbases.size(); ++i) { /** redirect state info printing to states.txt file **/ factbases[i].print(); if (i == 0 || flag == 1) { factbase_sql_query += "(" + std::to_string(factbases[i].get_id()) + ",'" + std::to_string(factbases[i].hash(factlist)) + "')"; flag = 0; } else { factbase_sql_query += ",(" + std::to_string(factbases[i].get_id()) + ",'" + std::to_string(factbases[i].hash(factlist)) + "')"; } //Break up query due to memory constraints. Suboptimal approach. factbase_counter += 1; fbsize = sizeof(factbase_sql_query); if (fbsize/tot_sys_mem >= 0.1){ factbase_sql_query += ";"; db.execAsync(factbase_sql_query); flag = 1; factbase_sql_query = "INSERT INTO factbase VALUES "; db.exec("COMMIT;"); db.exec("BEGIN;"); } } factbase_sql_query += ";"; db.execAsync(factbase_sql_query); } db.execAsync("COMMIT;"); /** reset cout buffer **/ std::cout.rdbuf(coutbuf); //gettimeofday(&t2,NULL); //printf("The preparation of factbases took %lf ms\n",(t2.tv_sec-t1.tv_sec)*1000.0+(t2.tv_usec-t1.tv_usec)/1000.0); //this part takes 1.5s //gettimeofday(&t1,NULL); //potentially bug in forming the string for db storage, check if the first record has a comma before it /*FACTBASE ITEMS if (!factbase_items.empty()) { int fis=factbase_items.size(); //fis=4; //#pragma omp parallel for num_threads(4)\ //default(none) shared(factbase_items,fis,db,db2,db3,db4,std::cout) schedule(static,1) #pragma omp parallel for num_threads(1)\ default(none) shared(factbase_items,fis,db,std::cout) //for(int k=0;k<4;k++){ for(int k=0; k<1; k++) { std::string item_sql_query = "INSERT INTO factbase_item VALUES "; std::string quality_sql_query = ""; std::string topology_sql_query = ""; int sql_index=0; *///FACTBASE ITEMS /* for (int j = 0; j(fbi); auto items = std::get<0>(fbi); auto quals = std::get<0>(items); auto topo = std::get<1>(items); for (auto qi : quals) { */ //UNCOMMENT FOR FACTBASE ITEM STORAGE /* int fbi_counter = 0; int fbi_q_flag = 0; int fbi_t_flag = 0; for (int j = 0, sql_index = 0; j < factbase_items.size(); ++j) { auto fbi = factbase_items[j]; int id = std::get<1>(fbi); auto items = std::get<0>(fbi); auto quals = std::get<0>(items); auto topo = std::get<1>(items); for (auto qi : quals) { if (sql_index == 0 || fbi_q_flag == 1){ quality_sql_query += "(" + std::to_string(id) + "," + std::to_string(qi.get_encoding()) + ",'quality')"; fbi_q_flag = 0; } else quality_sql_query += ",(" + std::to_string(id) + "," + std::to_string(qi.get_encoding()) + ",'quality')"; sql_index++; } for (auto ti : topo) { if (sql_index == 0 || fbi_t_flag == 1) { topology_sql_query += "(" + std::to_string(id) + "," + std::to_string(ti.get_encoding()) + ",'topology')"; fbi_t_flag = 0; } else topology_sql_query += ",(" + std::to_string(id) + "," + std::to_string(ti.get_encoding()) + ",'topology')"; sql_index++; } //Break up query due to memory constraints. Suboptimal approach. fbi_counter += 1; if (fbi_counter >= 500){ item_sql_query += quality_sql_query + topology_sql_query + "ON CONFLICT DO NOTHING;"; db.exec("BEGIN;"); db.execAsync(item_sql_query); db.execAsync("COMMIT;"); fbi_q_flag = 1; fbi_t_flag = 1; item_sql_query = "INSERT INTO factbase_item VALUES "; quality_sql_query = ""; topology_sql_query = ""; } } item_sql_query += quality_sql_query + topology_sql_query + "ON CONFLICT DO NOTHING;"; int thrd_num=omp_get_thread_num(); if(thrd_num==0){ db.exec("BEGIN;"); db.execAsync(item_sql_query); db.execAsync("COMMIT;"); } else if(thrd_num==1){ //db2.exec("BEGIN;"); //db2.execAsync(item_sql_query); //db2.execAsync("COMMIT;"); } else if(thrd_num==2){ //db3.exec("BEGIN;"); //db3.execAsync(item_sql_query); //db3.execAsync("COMMIT;"); } else { //db4.exec("BEGIN;"); //db4.execAsync(item_sql_query); //db4.execAsync("COMMIT;"); } } } gettimeofday(&t2,NULL); //printf("The saving of factbase and items took %lf ms\n",(t2.tv_sec-t1.tv_sec)*1000.0+(t2.tv_usec-t1.tv_usec)/1000.0); *///FACTBASE ITEMS //this part takes 42.0s //probably where to apply parallelization, this part takes most of the db saving time (>=80%) gettimeofday(&t1,NULL); int edge_counter = 0; int edge_flag = 0; if (!edges.empty()) { std::vector edge_queries; edge_queries.resize(edges.size()); //convert each edge into a string which will be used by db insert std::transform(edges.begin(), edges.end(), edge_queries.begin(), to_query);//to_query is a unary operation on all the elements in edges. It is defined in db_function. struct timeval t3,t4; //---first way to build the map std::unordered_map eq; gettimeofday(&t3,NULL); auto ei = edge_queries.begin(); //returns an iterator, not the 1st element! //std::cout<<"The first element should be "<= 0.1 || easql/tot_sys_mem >= 0.1){ edge_sql_query += "ON CONFLICT DO NOTHING;"; edge_assets_sql_query += "ON CONFLICT DO NOTHING;"; db.execAsync(edge_sql_query); db.execAsync(edge_assets_sql_query); edge_flag = 1; edge_sql_query = "INSERT INTO edge VALUES "; edge_assets_sql_query = "INSERT INTO edge_asset_binding VALUES "; } } edge_sql_query += " ON CONFLICT DO NOTHING;"; edge_assets_sql_query += " ON CONFLICT DO NOTHING;"; struct timeval t5,t6,t7; gettimeofday(&t5,NULL); db.execAsync(edge_sql_query);//33.7s gettimeofday(&t6,NULL); db.execAsync(edge_assets_sql_query); //7.6s gettimeofday(&t7,NULL); // printf("The saving of edges took %lf ms\n",(t6.tv_sec-t5.tv_sec)*1000.0+(t6.tv_usec-t5.tv_usec)/1000.0); //printf("The saving of edges_assets_bingding took %lf ms\n",(t7.tv_sec-t6.tv_sec)*1000.0+(t7.tv_usec-t6.tv_usec)/1000.0); //----second method to store into db //---------------------------------- //---------------------------------- /* std::vector unique_eq; int unique_idx[eq.size()]; int jj=0; for(auto ei: eq) { unique_eq.push_back(ei.first); unique_idx[jj]=ei.second; jj++; } gettimeofday(&t4,NULL); //printf("The preparation of eq took %lf ms\n",(t4.tv_sec-t3.tv_sec)*1000.0+(t4.tv_usec-t3.tv_usec)/1000.0); struct timeval t5,t6; gettimeofday(&t5,NULL); //jj=6; //#pragma omp parallel for num_threads(2)\ //default(none) shared(jj,unique_idx,edges,unique_eq,std::cout,db,db2,db3,db4) #pragma omp parallel for num_threads(1)\ default(none) shared(jj,unique_idx,edges,unique_eq,std::cout,db) for(int k=0;k<2;k++) { std::string edge_sql_query = "INSERT INTO edge VALUES "; std::string edge_assets_sql_query = "INSERT INTO edge_asset_binding VALUES "; std::cout << "TEST CONDITION: " << ((jj/2)+(k==1)?(jj%2):0); for(int i=0;i keyvalue_vector = factlist.get_str_vector(); size_t count = 0; for(auto &value : keyvalue_vector) { if(count == 0) out << "(" << std::to_string(count++) << ",'" << value << "')"; else out << ",(" << std::to_string(count++) << ",'" << value << "')"; cnt1=cnt1+1; } out << ";"; db.execAsync(out.str()); } db.execAsync("COMMIT;"); gettimeofday(&t2,NULL); //printf("The saving of keyvalue took %lf ms\n",(t2.tv_sec-t1.tv_sec)*1000.0+(t2.tv_usec-t1.tv_usec)/1000.0); } void save_unexplored_to_db(NetworkState netstate) { int fid = netstate.get_id(); const Factbase fb = netstate.get_factbase(); auto facts_tuple = fb.get_facts_tuple(); auto qualities = std::get<0>(facts_tuple); auto topologies = std::get<1>(facts_tuple); std::string qual_sql_query = "INSERT INTO unex_state_q VALUES "; std::string top_sql_query = "INSERT INTO unex_state_t VALUES "; int i = 0; for(auto qual : qualities) { auto asset_id = qual.get_asset_id(); auto name = qual.get_name(); auto op = qual.get_op(); auto val = qual.get_value(); if (i==0) { qual_sql_query += "(" + std::to_string(fid) + "," \ + std::to_string(asset_id) + "," + "'" + name + "'" + ","\ + "'" + op +"'" + "," + "'" + val + "'" + ")"; } else { qual_sql_query += ",(" + std::to_string(fid) + "," \ + std::to_string(asset_id) + "," + "'" + name + "'" + ","\ + "'" + op +"'" + "," + "'" + val + "'" + ")"; } ++i; } i = 0; for (auto ti : topologies) { auto from_id = ti.get_from_asset_id(); auto to_id = ti.get_to_asset_id(); auto dir = ti.get_dir(); auto prop = ti.get_property(); auto op = ti.get_op(); auto val = ti.get_value(); if (i == 0) { top_sql_query += "(" + std::to_string(fid) + "," \ + std::to_string(from_id) + ","\ + std::to_string(to_id) + ","\ + std::to_string(dir) + ","\ + "'" + prop + "'" + ","\ + "'" + op + "'" + ","\ + "'" + val + "'" + ")"; } else { top_sql_query += ",(" + std::to_string(fid) + "," \ + std::to_string(from_id) + ","\ + std::to_string(to_id) + ","\ + std::to_string(dir) + ","\ + "'" + prop + "'" + ","\ + "'" + op + "'" + ","\ + "'" + val + "'" + ")"; } ++i; } qual_sql_query += " ON CONFLICT DO NOTHING;"; top_sql_query += " ON CONFLICT DO NOTHING;"; struct timeval t1,t2; gettimeofday(&t1,NULL); db.execAsync(qual_sql_query); db.execAsync(top_sql_query); gettimeofday(&t2,NULL); //printf("The saving of unexplored states took %lf ms\n",(t2.tv_sec-t1.tv_sec)*1000.0+(t2.tv_usec-t1.tv_usec)/1000.0); } //Fetch Qualities, Topologies, reform into a factbase, then return the factbase NetworkState fetch_unexplored(Keyvalue &facts){ std::vector qualities; std::vector topologies; int id; //Pulls the fid from the first row in the unex_state Table, deletes all rows with this fid, then returns all deleted rows std::string qdel_str = "DELETE FROM unex_state_q WHERE fid=(SELECT fid FROM unex_state_q LIMIT 1) RETURNING *;"; std::string tdel_str = "DELETE FROM unex_state_t WHERE fid=(SELECT fid FROM unex_state_t LIMIT 1) RETURNING *;"; std::vector qrows = db.exec(qdel_str); for (auto &row : qrows) { int fid = std::stoi(row[0]); int asset_id = std::stoi(row[1]); std::string property = row[2]; std::string op = row[3]; std::string value = row[4]; Quality qual(asset_id, property, op, value, facts); //associate each record from unex_state table with the facts(the hash_table and fact string vector). qualities.push_back(qual); id = fid; } std::vector trows = db.exec(tdel_str); for (auto &row : trows) { //int fid = std::stoi(row[0]); int from_asset = std::stoi(row[1]); int to_asset = std::stoi(row[2]); std::string dir_str = row[3]; DIRECTION_T dir; //DIRECTION_T is a user defined enum type (in topology.h), it has three different values: FORWARD_T 0, BACKWARD_T 1, and BIDIRECTION_T 2 if(dir_str == "->" || dir_str == "0") { dir = FORWARD_T; } else if (dir_str == "<-" || dir_str == "1") { dir = BACKWARD_T; } else if (dir_str == "<->" || dir_str == "2") { dir = BIDIRECTION_T; } else { std::cerr << "Unknown direction '" << dir_str << "'" << std::endl; exit(1); } std::string property = row[4]; std::string op = row[5]; std::string value = row[6]; Topology t(from_asset, to_asset, dir, property, op, value, facts); //associate each record from topology table with the facts topologies.push_back(t); } NetworkState fetched_state(qualities, topologies); fetched_state.force_set_id(id); return fetched_state; } bool unex_empty() { std::vector row = db.exec("SELECT count(*) FROM unex_state_q LIMIT 1;"); for (auto &r : row){ auto count = std::stoi(r[0]); if (count == 0) return true; else return false; } } int get_num_states() { std::vector row = db.exec("SELECT count(*) AS exact_count FROM factbase;"); for (auto &r : row) { return std::stoi(r[0]); } } int get_num_edges() { std::vector row = db.exec("SELECT count(*) AS exact_count FROM edge;"); for (auto &r : row) { return std::stoi(r[0]); } }