add database-aware MySQL pooling
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
namespace {
|
||||
|
||||
const u64 UCE_UNIT_ABI_VERSION = 10;
|
||||
const u64 UCE_UNIT_ABI_VERSION = 11;
|
||||
|
||||
struct SharedUnitFilesystemState
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "mysql-connector.h"
|
||||
|
||||
// Same-credential mysql_connect() calls lease one request-local connection.
|
||||
// Same-target mysql_connect() calls lease one request-local connection.
|
||||
// mysql_disconnect() releases a lease; cleanup_mysql_connections() owns the
|
||||
// actual close at request end, including exception/fatal recovery paths.
|
||||
static void mysql_register_request_connection(MySQL* db)
|
||||
@@ -15,8 +15,12 @@ static void mysql_register_request_connection(MySQL* db)
|
||||
connections.push_back(db);
|
||||
}
|
||||
|
||||
bool MySQL::connect(String host, String username, String password)
|
||||
bool MySQL::connect(String host, String username, String password, String database)
|
||||
{
|
||||
request_host = host;
|
||||
request_username = username;
|
||||
request_password = password;
|
||||
request_database = database;
|
||||
// Register regardless of outcome: tracking is about the wrapper's
|
||||
// lifetime, not the connection's. disconnect()/~MySQL() unregister.
|
||||
mysql_register_request_connection(this);
|
||||
@@ -32,7 +36,7 @@ bool MySQL::connect(String host, String username, String password)
|
||||
}
|
||||
|
||||
if (mysql_real_connect((MYSQL*)connection, host.c_str(), username.c_str(), password.c_str(),
|
||||
NULL, 0, NULL, 0) == NULL)
|
||||
database == "" ? NULL : database.c_str(), 0, NULL, 0) == NULL)
|
||||
{
|
||||
auto e = mysql_error((MYSQL*)connection);
|
||||
fprintf(stderr, "%s\n", e);
|
||||
@@ -59,7 +63,17 @@ bool MySQL::connect(String host, String username, String password)
|
||||
|
||||
bool MySQL::reset_connection()
|
||||
{
|
||||
if(!connection || mysql_reset_connection((MYSQL*)connection) != 0)
|
||||
if(!connection)
|
||||
return(false);
|
||||
MYSQL* mysql = (MYSQL*)connection;
|
||||
String selected_database = mysql->db == NULL ? "" : mysql->db;
|
||||
// RESET CONNECTION deliberately preserves the selected database. An
|
||||
// unqualified lease cannot safely inherit one selected by its prior request.
|
||||
if(request_database == "" && selected_database != "")
|
||||
return(false);
|
||||
if(mysql_reset_connection(mysql) != 0)
|
||||
return(false);
|
||||
if(request_database != "" && selected_database != request_database && mysql_select_db(mysql, request_database.c_str()) != 0)
|
||||
return(false);
|
||||
_preload_next_error_code = 0;
|
||||
affected_rows = 0;
|
||||
|
||||
@@ -27,10 +27,11 @@ struct MySQL {
|
||||
String request_host;
|
||||
String request_username;
|
||||
String request_password;
|
||||
String request_database;
|
||||
|
||||
std::vector<MySQLFieldInfo> field_info;
|
||||
|
||||
bool connect(String host = "localhost", String username = "root", String password = "");
|
||||
bool connect(String host = "localhost", String username = "root", String password = "", String database = "");
|
||||
bool reset_connection();
|
||||
void disconnect();
|
||||
String error();
|
||||
@@ -46,14 +47,14 @@ struct MySQL {
|
||||
|
||||
};
|
||||
|
||||
inline MySQL* mysql_connect(String host = "localhost", String username = "root", String password = "")
|
||||
inline MySQL* mysql_connect(String host = "localhost", String username = "root", String password = "", String database = "")
|
||||
{
|
||||
if(context)
|
||||
{
|
||||
for(void* raw : context->resources.mysql_connections)
|
||||
{
|
||||
MySQL* db = (MySQL*)raw;
|
||||
if(db && db->request_pooled && db->connection && db->request_host == host && db->request_username == username && db->request_password == password)
|
||||
if(db && db->request_pooled && db->connection && db->request_host == host && db->request_username == username && db->request_password == password && db->request_database == database)
|
||||
{
|
||||
db->request_leases++;
|
||||
return(db);
|
||||
@@ -67,7 +68,8 @@ inline MySQL* mysql_connect(String host = "localhost", String username = "root",
|
||||
db->request_host = host;
|
||||
db->request_username = username;
|
||||
db->request_password = password;
|
||||
db->connect(host, username, password);
|
||||
db->request_database = database;
|
||||
db->connect(host, username, password, database);
|
||||
return(db);
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -146,13 +146,18 @@ static DValue wasm_mysql_call(DValue request)
|
||||
return(wasm_sized_hostcall(request, uce_host_mysql));
|
||||
}
|
||||
|
||||
bool MySQL::connect(String host, String username, String password)
|
||||
bool MySQL::connect(String host, String username, String password, String database)
|
||||
{
|
||||
request_host = host;
|
||||
request_username = username;
|
||||
request_password = password;
|
||||
request_database = database;
|
||||
DValue request;
|
||||
request["op"] = "connect";
|
||||
request["host"] = host;
|
||||
request["username"] = username;
|
||||
request["password"] = password;
|
||||
request["database"] = database;
|
||||
DValue response = wasm_mysql_call(request);
|
||||
u64 handle = response["handle"].to_u64();
|
||||
connection = (void*)(uintptr_t)handle;
|
||||
@@ -804,7 +809,7 @@ void uce_free(void* ptr)
|
||||
|
||||
u32 uce_wasm_core_abi_version()
|
||||
{
|
||||
return(6);
|
||||
return(7);
|
||||
}
|
||||
|
||||
int uce_wasm_core_init()
|
||||
|
||||
@@ -254,7 +254,7 @@ int main(int argc, char** argv)
|
||||
|
||||
CHECK(call_i32(core, "uce_wasm_core_init") == 0, "core init failed");
|
||||
call_i32(core, "uce_wasm_core_reset_request");
|
||||
CHECK(call_i32(core, "uce_wasm_core_abi_version") == 6, "unexpected ABI version");
|
||||
CHECK(call_i32(core, "uce_wasm_core_abi_version") == 7, "unexpected ABI version");
|
||||
|
||||
wasm_memory_t* memory = core.memory();
|
||||
int32_t root = call_i32(core, "uce_dv_root");
|
||||
@@ -302,7 +302,7 @@ int main(int argc, char** argv)
|
||||
int32_t output_ptr = call_i32(core, "uce_wasm_output_data");
|
||||
CHECK(read_bytes(memory, output_ptr, output_len) == out, "output plumbing mismatch");
|
||||
|
||||
printf("W1 core.wasm smoke: abi=6 encoded=%d output=%d\n", encoded_len, output_len);
|
||||
printf("W1 core.wasm smoke: abi=7 encoded=%d output=%d\n", encoded_len, output_len);
|
||||
printf("W1 EXIT CRITERION: PASS\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
+7
-5
@@ -968,14 +968,14 @@ public:
|
||||
delete db;
|
||||
}
|
||||
|
||||
MySQL* mysql_checkout(const String& host, const String& username, const String& password, bool& reused, bool& persistent)
|
||||
MySQL* mysql_checkout(const String& host, const String& username, const String& password, const String& database, bool& reused, bool& persistent)
|
||||
{
|
||||
reused = false;
|
||||
persistent = false;
|
||||
for(size_t i = 0; i < mysql_persistent_pool.size(); i++)
|
||||
{
|
||||
MySQL* db = mysql_persistent_pool[i];
|
||||
if(!db || !db->connection || db->request_host != host || db->request_username != username || db->request_password != password)
|
||||
if(!db || !db->connection || db->request_host != host || db->request_username != username || db->request_password != password || db->request_database != database)
|
||||
continue;
|
||||
if(db->reset_connection())
|
||||
{
|
||||
@@ -1000,7 +1000,8 @@ public:
|
||||
db->request_host = host;
|
||||
db->request_username = username;
|
||||
db->request_password = password;
|
||||
if(!db->connect(host, username, password) || !db->connection)
|
||||
db->request_database = database;
|
||||
if(!db->connect(host, username, password, database) || !db->connection)
|
||||
return(db);
|
||||
if(persistent)
|
||||
{
|
||||
@@ -3705,9 +3706,10 @@ private:
|
||||
String host = request["host"].to_string();
|
||||
String username = request["username"].to_string();
|
||||
String password = request["password"].to_string();
|
||||
String database = request["database"].to_string();
|
||||
MySQL* db = 0;
|
||||
for(auto* pooled : self->mysql_request_pool)
|
||||
if(pooled && pooled->connection && pooled->request_host == host && pooled->request_username == username && pooled->request_password == password)
|
||||
if(pooled && pooled->connection && pooled->request_host == host && pooled->request_username == username && pooled->request_password == password && pooled->request_database == database)
|
||||
{
|
||||
db = pooled;
|
||||
connection_source = "request";
|
||||
@@ -3718,7 +3720,7 @@ private:
|
||||
{
|
||||
bool reused = false;
|
||||
bool persistent = false;
|
||||
db = self->worker.mysql_checkout(host, username, password, reused, persistent);
|
||||
db = self->worker.mysql_checkout(host, username, password, database, reused, persistent);
|
||||
connection_source = reused ? "worker" : "new";
|
||||
ok = db && db->connection;
|
||||
if(ok && db->connection)
|
||||
|
||||
Reference in New Issue
Block a user