Skip to content
This repository has been archived by the owner on Jun 12, 2020. It is now read-only.

Commit

Permalink
Merge pull request #4 from tgstation/FixBuild
Browse files Browse the repository at this point in the history
Fixups
  • Loading branch information
Cyberboss authored Jun 14, 2018
2 parents 29149b4 + c068c09 commit 3448edc
Show file tree
Hide file tree
Showing 19 changed files with 375 additions and 200 deletions.
34 changes: 29 additions & 5 deletions src/BSQL/API.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#include "BSQL.h"

namespace {
std::unique_ptr<Library> library;
std::string lastCreatedConnection, lastCreatedOperation, lastCreatedOperationConnectionId, lastRow, returnValueHolder;
}
std::unique_ptr<Library> library;
std::string lastCreatedConnection, lastCreatedOperation, lastCreatedOperationConnectionId, lastRow, returnValueHolder;

const char* TryLoadQuery(const int argumentCount, const char* const* const args, Query** query) noexcept {
if (argumentCount != 2)
Expand Down Expand Up @@ -256,7 +254,7 @@ extern "C" {
auto operation(connection->GetOperation(operationIdentifier));
if (!operation)
return nullptr;
return operation->IsComplete(true) ? "DONE" : "NOTDONE";
return operation->IsComplete(false) ? "DONE" : "NOTDONE";
}
catch (std::bad_alloc&) {
return "Out of memory!";
Expand Down Expand Up @@ -312,4 +310,30 @@ extern "C" {
return nullptr;
}
}

BYOND_FUNC BlockOnOperation(const int argumentCount, const char* const* const args) noexcept {
if (argumentCount != 2)
return "Invalid arguments!";
const auto& connectionIdentifier(args[0]), operationIdentifier(args[1]);
if (!connectionIdentifier)
return "Invalid connection identifier!";
if (!operationIdentifier)
return "Invalid operation identifier!";
if (!library)
return "Library not initialized!";
try {
auto connection(library->GetConnection(connectionIdentifier));
if (!connection)
return "Connection identifier does not exist!";
auto op(connection->GetOperation(operationIdentifier));
if (!op)
return "Operation identifier does not exist!";
while (!op->IsComplete(false))
std::this_thread::sleep_for(std::chrono::milliseconds(1));
return nullptr;
}
catch (std::bad_alloc&) {
return "Out of memory!";
}
}
}
6 changes: 5 additions & 1 deletion src/BSQL/BSQL.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@

#include <mysql/mysql.h>

#include <atomic>
#include <chrono>
#include <deque>
#include <limits>
#include <map>
#include <memory>
#include <mutex>
#include <queue>
#include <stack>
#include <string>
#include <thread>

class Library;

#include "Operation.h"
#include "Query.h"
#include "Connection.h"
Expand Down
6 changes: 5 additions & 1 deletion src/BSQL/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ Query.cpp
)

if(WIN32) #vcpkg
#use static crt
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
find_library(MARIA_LIBRARY libmariadb)
find_path(MARIA_INCLUDE_DIR mysql/mysql.h)
add_precompiled_header(BSQL BSQL.h FORCEINCLUDE)
set(WSLIB ws2_32)
else() #system package
set_target_properties(BSQL PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
find_path(MARIA_INCLUDE_DIR NAMES "mysql.h" PATHS "/usr/include/mysql")
Expand All @@ -25,5 +29,5 @@ endif()

include_directories(${MARIA_INCLUDE_DIR})

target_link_libraries(BSQL ${MARIA_LIBRARY})
target_link_libraries(BSQL ${MARIA_LIBRARY} ${WSLIB})

9 changes: 8 additions & 1 deletion src/BSQL/Connection.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "BSQL.h"

Connection::Connection(Type type) :
Connection::Connection(Type type, Library& library) :
library(library),
type(type),
identifierCounter(0)
{}
Expand All @@ -12,6 +13,12 @@ std::string Connection::AddOp(std::unique_ptr<Operation>&& operation) {
}

bool Connection::ReleaseOperation(const std::string& identifier) {
auto op(GetOperation(identifier));
if (!op)
return false;
auto thread(op->GetActiveThread());
if (thread)
library.RegisterZombieThread(std::move(*thread));
return operations.erase(identifier) > 0;
}

Expand Down
3 changes: 2 additions & 1 deletion src/BSQL/Connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ class Connection {
public:
const Type type;
protected:
Library & library;
std::map<std::string, std::unique_ptr<Operation>> operations;
private:
unsigned long long identifierCounter;
protected:
Connection(Type type);
Connection(Type type, Library& library);

std::string AddOp(std::unique_ptr<Operation>&& operation);
public:
Expand Down
25 changes: 22 additions & 3 deletions src/BSQL/Library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@

Library::Library() noexcept :
identifierCounter(0)
{}
{
mysql_library_init(0, nullptr, nullptr);
}

Library::~Library() noexcept {
for (auto& I : zombieThreads)
I.join();
//https://jira.mariadb.org/browse/CONC-336
//mysql_library_end();
}

Connection* Library::GetConnection(const std::string& identifier) noexcept {
auto iter(connections.find(identifier));
Expand All @@ -23,7 +32,7 @@ std::string Library::CreateConnection(Connection::Type type) noexcept {
switch (type)
{
case Connection::Type::MySql:
connections.emplace(identifier, std::make_unique<MySqlConnection>());
connections.emplace(identifier, std::make_unique<MySqlConnection>(*this));
break;
case Connection::Type::SqlServer:
--identifierCounter;
Expand All @@ -35,4 +44,14 @@ std::string Library::CreateConnection(Connection::Type type) noexcept {
}
}
return std::string();
}
}

void Library::RegisterZombieThread(std::thread&& thread) noexcept {
try {
zombieThreads.emplace_back(std::move(thread));
}
catch(std::bad_alloc&) {
//gotta wait then
thread.join();
}
}
6 changes: 3 additions & 3 deletions src/BSQL/Library.h
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#pragma once

class Library {
public:
static const char* GoodReturn;
static const char* BadReturn;
private:
unsigned long long identifierCounter;

std::map<std::string, std::unique_ptr<Connection>> connections;
std::deque<std::thread> zombieThreads;
public:
Library() noexcept;
~Library() noexcept;

std::string CreateConnection(Connection::Type connectionType) noexcept;
Connection* GetConnection(const std::string& identifier) noexcept;
bool ReleaseConnection(const std::string& identifier) noexcept;
void RegisterZombieThread(std::thread&& thread) noexcept;
};
71 changes: 49 additions & 22 deletions src/BSQL/MySqlConnectOperation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,65 @@

MySqlConnectOperation::MySqlConnectOperation(MySqlConnection& connPool, const std::string& address, const unsigned short port, const std::string& username, const std::string& password, const std::string& database) :
connPool(connPool),
mysql(mysql_init(nullptr)),
complete(false)
mysql(nullptr),
complete(false),
state(std::make_shared<ClassState>()),
connectThread(&MySqlConnectOperation::DoConnect, this, address, port, username, password, database, InitMySql(), state)
{
if (mysql == nullptr)
}

MYSQL* MySqlConnectOperation::InitMySql() {
const auto res(mysql_init(nullptr));
if (!res)
throw std::bad_alloc();
mysql_options(mysql, MYSQL_OPT_NONBLOCK, 0);
mysql_real_connect_start(&ret, mysql, address.c_str(), username.c_str(), password.c_str(), database.empty() ? nullptr : database.c_str(), port, nullptr, 0);
return res;
}

MySqlConnectOperation::~MySqlConnectOperation() {
while (!IsComplete(false))
std::this_thread::sleep_for(std::chrono::milliseconds(100));
void MySqlConnectOperation::DoConnect(const std::string address, const unsigned short port, const std::string username, const std::string password, const std::string database, MYSQL* localMySql, std::shared_ptr<ClassState> localState) {
mysql_thread_init();
const auto result(mysql_real_connect(localMySql, address.c_str(), username.c_str(), password.c_str(), database.empty() ? nullptr : database.c_str(), port, nullptr, 0));
localState->lock.lock();
if (localState->alive) {
error = mysql_error(localMySql);
errnum = mysql_errno(localMySql);
if (result)
mysql = localMySql;
complete = true;
}
if (!result || !localState->alive)
mysql_close(localMySql);
mysql_thread_end();
localState->lock.unlock();
}

bool MySqlConnectOperation::IsQuery() {
return false;
}

bool MySqlConnectOperation::IsComplete(bool noOps) {
if (complete)
return true;
const auto status(mysql_real_connect_cont(&ret, mysql, 0));
complete = status == 0;
if (complete) {
if (!ret) {
error = "mysql_real_connect() returns error: " + std::string(mysql_error(mysql));
mysql_close(mysql); //don't use connPool Kill since it's never seen this connection
}
else
connPool.ReleaseConnection(mysql);
}
else
bool MySqlConnectOperation::IsComplete(bool noSkip) {
if (!complete)
return false;

if (mysql) {
auto tmp(mysql);
mysql = nullptr; //recursion issue
connPool.ReleaseConnection(tmp);
}

return true;
}

std::thread* MySqlConnectOperation::GetActiveThread() {
state->lock.lock();

if (IsComplete(false)) {
state->lock.unlock();
connectThread.join();
return nullptr;
}

state->alive = false;
state->lock.unlock();

return &connectThread;
}
12 changes: 9 additions & 3 deletions src/BSQL/MySqlConnectOperation.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@
class MySqlConnectOperation : public Operation {
private:
MySqlConnection& connPool;
MYSQL* ret, *mysql;
MYSQL *mysql;

bool complete;
std::shared_ptr<ClassState> state;
std::thread connectThread;
private:
static MYSQL* InitMySql();
void DoConnect(const std::string address, const unsigned short port, const std::string username, const std::string password, const std::string database, MYSQL* localMySql, std::shared_ptr<ClassState> localState);
public:
MySqlConnectOperation(MySqlConnection& connPool, const std::string& address, const unsigned short port, const std::string& username, const std::string& password, const std::string& database);
MySqlConnectOperation(const MySqlConnectOperation&) = delete;
MySqlConnectOperation(MySqlConnectOperation&&) = delete;
~MySqlConnectOperation() override;
~MySqlConnectOperation() override = default;

bool IsComplete(bool noOps) override;
bool IsComplete(bool noSkip) override;
bool IsQuery() override;
std::thread* GetActiveThread() override;
};
Loading

0 comments on commit 3448edc

Please sign in to comment.