Protects against time loop calls both externally and internally

generic v0.9
marcelb 1 week ago
parent 27074f9269
commit e23e1f8cea
  1. 15
      README.md
  2. 22
      lib/mysql.hpp
  3. 87
      src/mysql.cpp
  4. 13
      test/test.cpp

@ -12,8 +12,8 @@ A small framework for basic MySQL database operations via MySQL/Connector++
- Native C++ containers: vector, tuple - Native C++ containers: vector, tuple
- Response object - Response object
- Thread safe - Thread safe
- Exceptions - Exceptions and log error callback
- Can use external periodic maintenance for connection management - Can use external time loop for connection management
## Installation ## Installation
@ -85,13 +85,16 @@ using namespace marcelb::asynco;
/** /**
* Init * 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] () { periodic mysql_maintenance ( [&mydb] () {
cout << "IZVRŠAVA SE ENGINE" << endl;
mydb.periodic_maintenance(); mydb.periodic_maintenance();
}, MYSQL_PERIODIC_INTERNAL_TIME); }, MYSQL_PERIODIC_INTERNAL_TIME);
mydb.set_on_error( [](const string& error) {
cout << error << endl; // print or log
});
/** /**
* You can call multiple queries asynchronously * You can call multiple queries asynchronously
*/ */
@ -134,10 +137,6 @@ wait(a2);
wait(a3); wait(a3);
``` ```
## To do
- On error, implement virtual/friend function
## License ## License
[APACHE 2.0](http://www.apache.org/licenses/LICENSE-2.0/) [APACHE 2.0](http://www.apache.org/licenses/LICENSE-2.0/)

@ -8,6 +8,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <tuple> #include <tuple>
#include "ctime"
#include <mysql_driver.h> #include <mysql_driver.h>
#include <mysql_connection.h> #include <mysql_connection.h>
@ -38,7 +39,7 @@ namespace mysql {
* external - expects periodic_maintenance() to be run periodically outside the library * external - expects periodic_maintenance() to be run periodically outside the library
* *
*/ */
enum class periodical_engine { enum class time_loop_type {
internal, internal,
external external
}; };
@ -103,9 +104,10 @@ class MySQL {
string path, username, password, database; string path, username, password, database;
uint32_t pool_size; uint32_t pool_size;
uint32_t connect_trys = 3; uint32_t connect_trys = 3;
bool run_engin = true; bool run_tloop = true;
future<void> periodic_engin; future<void> tloop_future;
periodical_engine engine_type; time_loop_type tloop_type;
time_t last_loop_time = time(nullptr);
function<void(const string&)> on_error; function<void(const string&)> on_error;
/** /**
@ -149,7 +151,13 @@ class MySQL {
*/ */
void disconnect_pool(); void disconnect_pool();
public: /**
* Internal tloop periodic
*/
void _tloop();
public:
/** /**
* MySQL constructor, * MySQL constructor,
@ -157,7 +165,7 @@ class MySQL {
* username, password, database name, * username, password, database name,
* and number of active connections (optional) * 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. * please call this function in it for proper operation at a certain time interval.
* You can use the default MYSQL_PERIODIC_INTERNAL_TIME * You can use the default MYSQL_PERIODIC_INTERNAL_TIME
*/ */
void periodic_maintenance(); void tloop();
/** /**
* Destruktor * Destruktor

@ -1,22 +1,22 @@
#include "../lib/mysql.hpp" #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; path = _path;
username = _username; username = _username;
password = _password; password = _password;
database = _db; database = _db;
pool_size = _available > 0 ? _available : 1; pool_size = _available > 0 ? _available : 1;
engine_type = _engine_type; tloop_type = _engine_type;
drv = get_mysql_driver_instance(); drv = get_mysql_driver_instance();
connect_pool(); connect_pool();
if (engine_type == periodical_engine::internal) { if (tloop_type == time_loop_type::internal) {
periodic_engin = async(launch::async, [&](){ tloop_future = async(launch::async, [&](){
while (run_engin) { while (run_tloop) {
usleep(MYSQL_PERIODIC_INTERNAL_TIME*1000); usleep(MYSQL_PERIODIC_INTERNAL_TIME*1000);
periodic_maintenance(); _tloop();
} }
return; return;
}); });
@ -72,7 +72,6 @@ void marcelb::mysql::MySQL::disconnect_pool() {
bool marcelb::mysql::MySQL::disconnect_connection(Connection* connection) { bool marcelb::mysql::MySQL::disconnect_connection(Connection* connection) {
bool status = !connection->isClosed(); bool status = !connection->isClosed();
if (status) { if (status) {
try { try {
connection->close(); connection->close();
@ -94,13 +93,30 @@ bool marcelb::mysql::MySQL::disconnect_connection(Connection* connection) {
return status; return status;
} }
void marcelb::mysql::MySQL::_tloop() {
/** for (size_t i = 0; i < pool_size && run_tloop; i++) {
* Broj pokušaja usljed povezivanja s bazom od 1 do unlimited; 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) { void marcelb::mysql::MySQL::set_connect_trys(const uint32_t _trys) {
lock_guard<mutex> lock(io); // lock_guard<mutex> lock(io);
connect_trys = _trys; connect_trys = _trys;
} }
@ -109,6 +125,9 @@ void marcelb::mysql::MySQL::set_on_error(function<void(const string&)> _on_erro
} }
Connection* marcelb::mysql::MySQL::occupy_connection() { 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<mutex> lock(io); unique_lock<mutex> lock(io);
while (connection_pool.empty()) { while (connection_pool.empty()) {
condition.wait(lock); condition.wait(lock);
@ -116,20 +135,6 @@ Connection* marcelb::mysql::MySQL::occupy_connection() {
Connection *connection = connection_pool.front(); Connection *connection = connection_pool.front();
connection_pool.pop(); connection_pool.pop();
return connection; 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) { void marcelb::mysql::MySQL::release_connection(Connection* connection) {
@ -139,35 +144,23 @@ void marcelb::mysql::MySQL::release_connection(Connection* connection) {
} }
marcelb::mysql::MySQL::~MySQL() { marcelb::mysql::MySQL::~MySQL() {
if (engine_type == periodical_engine::internal) { if (tloop_type == time_loop_type::internal) {
run_engin = false; run_tloop = false;
periodic_engin.get(); tloop_future.get();
} else { } else {
run_engin = false; run_tloop = false;
} }
disconnect_pool(); disconnect_pool();
} }
void marcelb::mysql::MySQL::periodic_maintenance() { void marcelb::mysql::MySQL::tloop() {
for (size_t i = 0; i < pool_size && run_engin; i++) { if (tloop_type == time_loop_type::internal) {
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) { if (on_error) {
on_error(error.what() + string(", SQL state: ") + error.getSQLState() + string(", Error code: ") + to_string(error.getErrorCode())); on_error("Can't start external call tloop, internal is active!");
}
} }
return;
} }
_tloop();
} }

@ -13,17 +13,18 @@ using namespace marcelb::asynco;
int main() { int main() {
try { try {
// MySQL mydb("tcp://192.168.2.10:3306", "dinio", "H€r5elfInd1aH@nds", "dinio", 10, periodical_engine::external); 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, periodical_engine::external); // 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); // MySQL mydb("tcp://bitelex.ddns.net:3306", "dinio", "H€r5elfInd1aH@nds", "dinio", 5);
mydb.set_on_error( [](const string& error) { mydb.set_on_error( [](const string& error) {
cout << error << endl; cout << error << endl;
}); });
// periodic mysql_maintenance ( [&mydb] () { periodic mysql_tloop ( [&mydb] () {
// mydb.periodic_maintenance(); mydb.tloop();
// }, MYSQL_PERIODIC_INTERNAL_TIME); }, MYSQL_PERIODIC_INTERNAL_TIME);
sleep(5); sleep(5);

Loading…
Cancel
Save