Assigning vacant ports from destroyed instances before assigning a new port (#6)

This commit is contained in:
Savinda Senevirathne
2021-06-10 10:53:35 +05:30
committed by GitHub
parent 913d219d94
commit 44528cab1f
5 changed files with 172 additions and 129 deletions

View File

@@ -1,6 +1,7 @@
#include "sqlite.hpp"
#include "salog.hpp"
#include "util/util.hpp"
#include "conf.hpp"
namespace sqlite
{
@@ -16,10 +17,6 @@ namespace sqlite
constexpr const char *PRIMARY_KEY = "PRIMARY KEY";
constexpr const char *NOT_NULL = "NOT NULL";
constexpr const char *VALUES = "VALUES";
constexpr const char *SELECT_ALL = "SELECT * FROM ";
constexpr const char *SQLITE_MASTER = "sqlite_master";
constexpr const char *WHERE = " WHERE ";
constexpr const char *AND = " AND ";
constexpr const char *INSTANCE_TABLE = "instances";
@@ -28,6 +25,18 @@ namespace sqlite
"peer_port, user_port, pubkey, contract_id"
") VALUES(?,?,?,?,?,?,?,?,?)";
constexpr const char *GET_VACANT_PORTS_FROM_HP = "SELECT DISTINCT peer_port, user_port FROM "
"instances WHERE status == ? AND user_port NOT IN"
"(SELECT user_port FROM instances WHERE status != ?)";
constexpr const char *GET_MAX_PORTS_FROM_HP = "SELECT max(peer_port), max(user_port) FROM instances WHERE status != ?";
constexpr const char *UPDATE_STATUS_IN_HP = "UPDATE instances SET status = ? WHERE name = ?";
constexpr const char *IS_CONTAINER_EXISTS = "SELECT * FROM instances WHERE name = ?";
constexpr const char *IS_TABLE_EXISTS = "SELECT * FROM sqlite_master WHERE type='table' AND name = ?";
/**
* Opens a connection to a given databse and give the db pointer.
* @param db_name Database name to be connected.
@@ -223,23 +232,11 @@ namespace sqlite
*/
bool is_table_exists(sqlite3 *db, std::string_view table_name)
{
std::string sql;
// Reserving the space for the query before construction.
sql.reserve(sizeof(SELECT_ALL) + sizeof(SQLITE_MASTER) + sizeof(WHERE) + sizeof(AND) + table_name.size() + 19);
sql.append(SELECT_ALL);
sql.append(SQLITE_MASTER);
sql.append(WHERE);
sql.append("type='table'");
sql.append(AND);
sql.append("name='");
sql.append(table_name);
sql.append("'");
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, sql.data(), -1, &stmt, 0) == SQLITE_OK &&
stmt != NULL && sqlite3_step(stmt) == SQLITE_ROW)
if (sqlite3_prepare_v2(db, IS_TABLE_EXISTS, -1, &stmt, 0) == SQLITE_OK &&
stmt != NULL && sqlite3_bind_text(stmt, 1, table_name.data(), table_name.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_step(stmt) == SQLITE_ROW)
{
// Finalize and distroys the statement.
sqlite3_finalize(stmt);
@@ -303,20 +300,19 @@ namespace sqlite
* Inserts a hp instance record.
* @param db Pointer to the db.
* @param info HP instance information.
* @param status Current status of the instance.
* @returns returns 0 on success, or -1 on error.
*/
int insert_hp_instance_row(sqlite3 *db, std::string_view owner_pubkey, const hp::instance_info &info, std::string_view status)
int insert_hp_instance_row(sqlite3 *db, const hp::instance_info &info)
{
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, INSERT_INTO_HP_INSTANCE, -1, &stmt, 0) == SQLITE_OK && stmt != NULL &&
sqlite3_bind_text(stmt, 1, owner_pubkey.data(), owner_pubkey.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_bind_text(stmt, 1, info.owner_pubkey.data(), info.owner_pubkey.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_bind_int64(stmt, 2, util::get_epoch_milliseconds()) == SQLITE_OK &&
sqlite3_bind_text(stmt, 3, status.data(), status.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_bind_text(stmt, 3, info.status.data(), info.status.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_bind_text(stmt, 4, info.name.data(), info.name.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_bind_text(stmt, 5, info.ip.data(), info.ip.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_bind_int64(stmt, 6, info.peer_port) == SQLITE_OK &&
sqlite3_bind_int64(stmt, 7, info.user_port) == SQLITE_OK &&
sqlite3_bind_int64(stmt, 6, info.assigned_ports.peer_port) == SQLITE_OK &&
sqlite3_bind_int64(stmt, 7, info.assigned_ports.user_port) == SQLITE_OK &&
sqlite3_bind_text(stmt, 8, info.pubkey.data(), info.pubkey.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_bind_text(stmt, 9, info.contract_id.data(), info.contract_id.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_step(stmt) == SQLITE_DONE)
@@ -330,45 +326,33 @@ namespace sqlite
}
/**
* Checks whether the container exist in the database and checks against the given status.
* Checks whether the container exist in the database and populate the instance information.
* @param db Pointer to the db.
* @param container_name Name of the container to be checked.
* @param status Status to check the container status against.
* @returns 0 if not found, 1 if container exists but not in given status and 2 if container exist in given status.
* @param info HP instance information.
* @returns 0 if not found, 1 if container exists .
*/
int is_container_exists_in_status(sqlite3 *db, std::string_view container_name, std::string_view status)
int is_container_exists(sqlite3 *db, std::string_view container_name, hp::instance_info &info)
{
std::string sql;
// Reserving the space for the query before construction.
sql.reserve(sizeof(SELECT_ALL) + sizeof(SQLITE_MASTER) + sizeof(WHERE) + sizeof(AND) + container_name.size() + 7);
sql.append(SELECT_ALL);
sql.append(INSTANCE_TABLE);
sql.append(WHERE);
sql.append("name='");
sql.append(container_name);
sql.append("'");
sqlite3_stmt *stmt;
int result = 0; // Not exist.
if (sqlite3_prepare_v2(db, sql.data(), -1, &stmt, 0) == SQLITE_OK &&
stmt != NULL && sqlite3_step(stmt) == SQLITE_ROW)
if (sqlite3_prepare_v2(db, IS_CONTAINER_EXISTS, -1, &stmt, 0) == SQLITE_OK &&
stmt != NULL && sqlite3_bind_text(stmt, 1, container_name.data(), container_name.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_step(stmt) == SQLITE_ROW)
{
const std::string current_status(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2)));
// Populate only the necessary fields.
info.status = std::string(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2)));
info.assigned_ports.peer_port = sqlite3_column_int64(stmt, 5);
info.assigned_ports.user_port = sqlite3_column_int64(stmt, 6);
// Finalize and distroys the statement.
sqlite3_finalize(stmt);
if (current_status == status)
result = 2;
else
result = 1;
return result;
return 1;
}
// Finalize and distroys the statement.
sqlite3_finalize(stmt);
return result;
return 0; // Not found
}
/**
@@ -380,55 +364,71 @@ namespace sqlite
*/
int update_status_in_container(sqlite3 *db, std::string_view container_name, std::string_view status)
{
std::string sql;
// Reserving the space for the query before construction.
sql.reserve(sizeof(INSTANCE_TABLE) + status.length() + sizeof(WHERE) + container_name.size() + 30);
sql.append("UPDATE ");
sql.append(INSTANCE_TABLE);
sql.append(" SET status = '");
sql.append(status);
sql.append("'");
sql.append(WHERE);
sql.append("name='");
sql.append(container_name);
sql.append("'");
return sqlite::exec_sql(db, sql);
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, UPDATE_STATUS_IN_HP, -1, &stmt, 0) == SQLITE_OK && stmt != NULL &&
sqlite3_bind_text(stmt, 1, status.data(), status.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_bind_text(stmt, 2, container_name.data(), container_name.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_step(stmt) == SQLITE_DONE)
{
sqlite3_finalize(stmt);
return 0;
}
LOG_ERROR << "Error updating container status for " << container_name;
return -1;
}
/**
* Get the max port already used for the instances. Ports used for already destroyed instances are excluded.
* Get the max peer and user ports assigned for instances excluding destroyed instances.
* @param db Database connection.
* @param column_name Name of the column. Should be one of ['peer_port', 'user_port'].
* @return The port number. 0 is returned if no data found on database or on database error.
* @param max_ports Container holding max peer and user ports.
*/
int get_max_port(sqlite3 *db, std::string_view column_name)
void get_max_ports(sqlite3 *db, hp::ports &max_ports)
{
std::string sql;
// Reserving the space for the query before construction.
sql.reserve(sizeof(INSTANCE_TABLE) + column_name.length() + sizeof(WHERE) + sizeof(hp::CONTAINER_STATES[hp::STATES::DESTROYED]) + 29);
sql.append("SELECT max(")
.append(column_name)
.append(") from ")
.append(INSTANCE_TABLE)
.append(WHERE)
.append("status !='")
.append(hp::CONTAINER_STATES[hp::STATES::DESTROYED])
.append("'");
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, sql.data(), -1, &stmt, 0) == SQLITE_OK &&
stmt != NULL && sqlite3_step(stmt) == SQLITE_ROW)
if (sqlite3_prepare_v2(db, GET_MAX_PORTS_FROM_HP, -1, &stmt, 0) == SQLITE_OK && stmt != NULL &&
sqlite3_bind_text(stmt, 1, hp::CONTAINER_STATES[hp::STATES::DESTROYED], sizeof(hp::CONTAINER_STATES[hp::STATES::DESTROYED]), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_step(stmt) == SQLITE_ROW)
{
const int result = sqlite3_column_int64(stmt, 0);
// Finalize and distroys the statement.
sqlite3_finalize(stmt);
return result;
const uint16_t peer_port = sqlite3_column_int64(stmt, 0);
const uint16_t user_port = sqlite3_column_int64(stmt, 1);
max_ports = {peer_port, user_port};
}
// Initialize with default config values if either of the ports are zero.
if (max_ports.peer_port == 0 || max_ports.user_port == 0)
{
max_ports = {(uint16_t)(conf::cfg.hp.init_peer_port - 1), (uint16_t)(conf::cfg.hp.init_user_port - 1)};
}
// Finalize and distroys the statement.
sqlite3_finalize(stmt);
}
/**
* Populate the given vector with vacant ports of destroyed instances which are not already assigned.
* @param db Database connection.
* @param vacant_ports Ports vector to hold port pairs from database.
*/
void get_vacant_ports(sqlite3 *db, std::vector<hp::ports> &vacant_ports)
{
sqlite3_stmt *stmt;
std::string_view destroy_status(hp::CONTAINER_STATES[hp::STATES::DESTROYED]);
if (sqlite3_prepare_v2(db, GET_VACANT_PORTS_FROM_HP, -1, &stmt, 0) == SQLITE_OK && stmt != NULL &&
sqlite3_bind_text(stmt, 1, destroy_status.data(), destroy_status.length(), SQLITE_STATIC) == SQLITE_OK &&
sqlite3_bind_text(stmt, 2, destroy_status.data(), destroy_status.length(), SQLITE_STATIC) == SQLITE_OK)
{
while (stmt != NULL && sqlite3_step(stmt) == SQLITE_ROW)
{
const uint16_t peer_port = sqlite3_column_int64(stmt, 0);
const uint16_t user_port = sqlite3_column_int64(stmt, 1);
vacant_ports.push_back({peer_port, user_port});
}
}
// Finalize and distroys the statement.
sqlite3_finalize(stmt);
return 0;
}
}