From e23e1f8cea1ffa8d621c07a3d84a9a3178521c66 Mon Sep 17 00:00:00 2001 From: marcelb Date: Thu, 12 Sep 2024 18:36:21 +0200 Subject: [PATCH] Protects against time loop calls both externally and internally --- README.md | 15 ++++----- lib/mysql.hpp | 22 +++++++++---- src/mysql.cpp | 89 ++++++++++++++++++++++++--------------------------- test/test.cpp | 13 ++++---- 4 files changed, 70 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 540d2e6..fb6d407 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ A small framework for basic MySQL database operations via MySQL/Connector++ - Native C++ containers: vector, tuple - Response object - Thread safe -- Exceptions -- Can use external periodic maintenance for connection management +- Exceptions and log error callback +- Can use external time loop for connection management ## Installation @@ -85,13 +85,16 @@ using namespace marcelb::asynco; /** * Init */ -MySQL mydb("tcp://192.168.2.10:3306", "user_nm", "passss", "my_db", 5, periodical_engine::external); +MySQL mydb("tcp://192.168.2.10:3306", "user_nm", "passss", "my_db", 5, time_loop_type::external); periodic mysql_maintenance ( [&mydb] () { - cout << "IZVRŠAVA SE ENGINE" << endl; mydb.periodic_maintenance(); }, MYSQL_PERIODIC_INTERNAL_TIME); +mydb.set_on_error( [](const string& error) { + cout << error << endl; // print or log +}); + /** * You can call multiple queries asynchronously */ @@ -134,10 +137,6 @@ wait(a2); wait(a3); ``` -## To do - -- On error, implement virtual/friend function - ## License [APACHE 2.0](http://www.apache.org/licenses/LICENSE-2.0/) diff --git a/lib/mysql.hpp b/lib/mysql.hpp index 04e8b1b..dc07a36 100644 --- a/lib/mysql.hpp +++ b/lib/mysql.hpp @@ -8,6 +8,7 @@ #include #include #include +#include "ctime" #include #include @@ -38,7 +39,7 @@ namespace mysql { * external - expects periodic_maintenance() to be run periodically outside the library * */ -enum class periodical_engine { +enum class time_loop_type { internal, external }; @@ -103,9 +104,10 @@ class MySQL { string path, username, password, database; uint32_t pool_size; uint32_t connect_trys = 3; - bool run_engin = true; - future periodic_engin; - periodical_engine engine_type; + bool run_tloop = true; + future tloop_future; + time_loop_type tloop_type; + time_t last_loop_time = time(nullptr); function on_error; /** @@ -149,7 +151,13 @@ class MySQL { */ void disconnect_pool(); - public: + /** + * Internal tloop periodic + */ + + void _tloop(); + +public: /** * MySQL constructor, @@ -157,7 +165,7 @@ class MySQL { * username, password, database name, * and number of active connections (optional) */ - MySQL(const string _path, const string _username, const string _password, const string _db, const uint32_t _available = 1, const periodical_engine _engine_type = periodical_engine::internal); + MySQL(const string _path, const string _username, const string _password, const string _db, const uint32_t _available = 1, const time_loop_type _engine_type = time_loop_type::internal); /** @@ -223,7 +231,7 @@ class MySQL { * please call this function in it for proper operation at a certain time interval. * You can use the default MYSQL_PERIODIC_INTERNAL_TIME */ - void periodic_maintenance(); + void tloop(); /** * Destruktor diff --git a/src/mysql.cpp b/src/mysql.cpp index d0e76b3..7883909 100644 --- a/src/mysql.cpp +++ b/src/mysql.cpp @@ -1,22 +1,22 @@ #include "../lib/mysql.hpp" -marcelb::mysql::MySQL::MySQL(const string _path, const string _username, const string _password, const string _db, const uint32_t _available, const periodical_engine _engine_type) { +marcelb::mysql::MySQL::MySQL(const string _path, const string _username, const string _password, const string _db, const uint32_t _available, const time_loop_type _engine_type) { path = _path; username = _username; password = _password; database = _db; pool_size = _available > 0 ? _available : 1; - engine_type = _engine_type; + tloop_type = _engine_type; drv = get_mysql_driver_instance(); connect_pool(); - if (engine_type == periodical_engine::internal) { - periodic_engin = async(launch::async, [&](){ - while (run_engin) { + if (tloop_type == time_loop_type::internal) { + tloop_future = async(launch::async, [&](){ + while (run_tloop) { usleep(MYSQL_PERIODIC_INTERNAL_TIME*1000); - periodic_maintenance(); + _tloop(); } return; }); @@ -72,7 +72,6 @@ void marcelb::mysql::MySQL::disconnect_pool() { bool marcelb::mysql::MySQL::disconnect_connection(Connection* connection) { bool status = !connection->isClosed(); - if (status) { try { connection->close(); @@ -94,13 +93,30 @@ bool marcelb::mysql::MySQL::disconnect_connection(Connection* connection) { return status; } - -/** - * Broj pokušaja usljed povezivanja s bazom od 1 do unlimited; -*/ +void marcelb::mysql::MySQL::_tloop() { + for (size_t i = 0; i < pool_size && run_tloop; i++) { + try { + Connection *conn = occupy_connection(); + if (conn->isValid()) { + release_connection(conn); + } else { + if (!conn->isClosed()){ + conn->close(); + } + Connection *n_conn = create_connection(); + release_connection(n_conn); + } + } catch (const SQLException &error) { + if (on_error) { + on_error(error.what() + string(", SQL state: ") + error.getSQLState() + string(", Error code: ") + to_string(error.getErrorCode())); + } + } + } + last_loop_time = time(nullptr); +} void marcelb::mysql::MySQL::set_connect_trys(const uint32_t _trys) { - lock_guard lock(io); + // lock_guard lock(io); connect_trys = _trys; } @@ -109,6 +125,9 @@ void marcelb::mysql::MySQL::set_on_error(function _on_erro } Connection* marcelb::mysql::MySQL::occupy_connection() { + if (last_loop_time + (MYSQL_PERIODIC_INTERNAL_TIME/1000)*3 < time(nullptr) && on_error) { // ako je zadnje vrijeme + 3 intervala manje od trenutnog vremena emitiraj grešku + on_error("The time loop is not executing properly"); + } unique_lock lock(io); while (connection_pool.empty()) { condition.wait(lock); @@ -116,20 +135,6 @@ Connection* marcelb::mysql::MySQL::occupy_connection() { Connection *connection = connection_pool.front(); connection_pool.pop(); return connection; - - // while (true) { - // while(connection_pool.size()) { - // io.lock(); - // Connection* connection = connection_pool.front(); - // connection_pool.pop(); - // if (connection->isValid()) { - // io.unlock(); - // return connection; - // } - // io.unlock(); - // } - // usleep(1000); - // } } void marcelb::mysql::MySQL::release_connection(Connection* connection) { @@ -139,35 +144,23 @@ void marcelb::mysql::MySQL::release_connection(Connection* connection) { } marcelb::mysql::MySQL::~MySQL() { - if (engine_type == periodical_engine::internal) { - run_engin = false; - periodic_engin.get(); + if (tloop_type == time_loop_type::internal) { + run_tloop = false; + tloop_future.get(); } else { - run_engin = false; + run_tloop = false; } disconnect_pool(); } -void marcelb::mysql::MySQL::periodic_maintenance() { - for (size_t i = 0; i < pool_size && run_engin; i++) { - try { - - Connection *conn = occupy_connection(); - if (conn->isValid()) { - release_connection(conn); - } else { - if (!conn->isClosed()){ - conn->close(); - } - Connection *n_conn = create_connection(); - release_connection(n_conn); - } - } catch (const SQLException &error) { - if (on_error) { - on_error(error.what() + string(", SQL state: ") + error.getSQLState() + string(", Error code: ") + to_string(error.getErrorCode())); - } +void marcelb::mysql::MySQL::tloop() { + if (tloop_type == time_loop_type::internal) { + if (on_error) { + on_error("Can't start external call tloop, internal is active!"); } + return; } + _tloop(); } \ No newline at end of file diff --git a/test/test.cpp b/test/test.cpp index 4856e52..5ebb1bd 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -13,17 +13,18 @@ using namespace marcelb::asynco; int main() { try { - // MySQL mydb("tcp://192.168.2.10:3306", "dinio", "H€r5elfInd1aH@nds", "dinio", 10, periodical_engine::external); - // MySQL mydb("tcp://bitelex.ddns.net:3306", "dinio", "H€r5elfInd1aH@nds", "dinio", 10, periodical_engine::external); - MySQL mydb("tcp://bitelex.ddns.net:3306", "dinio", "H€r5elfInd1aH@nds", "dinio", 5); + MySQL mydb("tcp://192.168.2.10:3306", "dinio", "H€r5elfInd1aH@nds", "dinio", 5, time_loop_type::internal); + // MySQL mydb("tcp://bitelex.ddns.net:3306", "dinio", "H€r5elfInd1aH@nds", "dinio", 10, time_loop_type::external); + // MySQL mydb("tcp://bitelex.ddns.net:3306", "dinio", "H€r5elfInd1aH@nds", "dinio", 5); mydb.set_on_error( [](const string& error) { cout << error << endl; }); - // periodic mysql_maintenance ( [&mydb] () { - // mydb.periodic_maintenance(); - // }, MYSQL_PERIODIC_INTERNAL_TIME); + periodic mysql_tloop ( [&mydb] () { + mydb.tloop(); + }, MYSQL_PERIODIC_INTERNAL_TIME); + sleep(5);