Add resend_count in db Model and refactor mutex use in model/table/ModelBase until no I hadn't expected concurrency in running db functions

This commit is contained in:
Dario 2020-06-15 15:42:20 +02:00
parent 582aba5bcd
commit 5f9ec065af
5 changed files with 39 additions and 29 deletions

View File

@ -24,6 +24,7 @@
\brief Container Wrapper class for mutex protected container \brief Container Wrapper class for mutex protected container
changed to poco mutex for gradido login server changed to poco mutex for gradido login server
default mutex from poco is recursive so it is some heavy thing
\author Dario Rekowski \author Dario Rekowski
@ -50,8 +51,8 @@ namespace UniLib {
inline const std::string& getLastSucceededLock() { return mLastSucceededLock; } inline const std::string& getLastSucceededLock() { return mLastSucceededLock; }
protected: protected:
mutable Poco::Mutex mWorkMutex;
private: private:
Poco::Mutex mWorkMutex;
std::string mLastSucceededLock; std::string mLastSucceededLock;
}; };
} }

View File

@ -7,25 +7,25 @@ using namespace Poco::Data::Keywords;
namespace model { namespace model {
namespace table { namespace table {
EmailOptIn::EmailOptIn(const Poco::UInt64& code, int user_id, EmailOptInType type/* = EMAIL_OPT_IN_REGISTER*/) EmailOptIn::EmailOptIn(const Poco::UInt64& code, int user_id, EmailOptInType type/* = EMAIL_OPT_IN_REGISTER*/)
: mUserId(user_id), mEmailVerificationCode(code), mType(type) : mUserId(user_id), mEmailVerificationCode(code), mType(type), mResendCount(0)
{ {
} }
EmailOptIn::EmailOptIn(const Poco::UInt64& code, EmailOptInType type/* = EMAIL_OPT_IN_REGISTER*/) EmailOptIn::EmailOptIn(const Poco::UInt64& code, EmailOptInType type/* = EMAIL_OPT_IN_REGISTER*/)
: mUserId(0), mEmailVerificationCode(code), mType(type) : mUserId(0), mEmailVerificationCode(code), mType(type), mResendCount(0)
{ {
} }
EmailOptIn::EmailOptIn() EmailOptIn::EmailOptIn()
: mUserId(0), mEmailVerificationCode(0) : mUserId(0), mEmailVerificationCode(0), mResendCount(0)
{ {
} }
EmailOptIn::EmailOptIn(const EmailOptInTuple& tuple) EmailOptIn::EmailOptIn(const EmailOptInTuple& tuple)
: ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mEmailVerificationCode(tuple.get<2>()), mType(tuple.get<3>()) : ModelBase(tuple.get<0>()), mUserId(tuple.get<1>()), mEmailVerificationCode(tuple.get<2>()), mType(tuple.get<3>()), mResendCount(tuple.get<4>())
{ {
} }
@ -42,8 +42,8 @@ namespace model {
lock(); lock();
insert << "INSERT INTO " << getTableName() insert << "INSERT INTO " << getTableName()
<< " (user_id, verification_code, email_opt_in_type_id) VALUES(?,?,?)" << " (user_id, verification_code, email_opt_in_type_id, resend_count) VALUES(?,?,?,?)"
, use(mUserId), use(mEmailVerificationCode), bind(mType); , use(mUserId), use(mEmailVerificationCode), bind(mType), bind(mResendCount);
unlock(); unlock();
return insert; return insert;
} }
@ -53,9 +53,9 @@ namespace model {
{ {
Poco::Data::Statement select(session); Poco::Data::Statement select(session);
select << "SELECT id, user_id, verification_code, email_opt_in_type_id FROM " << getTableName() select << "SELECT id, user_id, verification_code, email_opt_in_type_id, resend_count FROM " << getTableName()
<< " where " << fieldName << " = ?" << " where " << fieldName << " = ?"
, into(mID), into(mUserId), into(mEmailVerificationCode), into(mType); , into(mID), into(mUserId), into(mEmailVerificationCode), into(mType), into(mResendCount);
return select; return select;
@ -76,7 +76,7 @@ namespace model {
{ {
Poco::Data::Statement select(session); Poco::Data::Statement select(session);
select << "SELECT id, user_id, verification_code, email_opt_in_type_id FROM " << getTableName() select << "SELECT id, user_id, verification_code, email_opt_in_type_id, resend_count FROM " << getTableName()
<< " where " << fieldName << " = ?"; << " where " << fieldName << " = ?";
@ -90,7 +90,7 @@ namespace model {
throw Poco::NullValueException("EmailOptIn::_loadFromDB fieldNames empty or contain only one field"); throw Poco::NullValueException("EmailOptIn::_loadFromDB fieldNames empty or contain only one field");
} }
select << "SELECT user_id, verification_code, email_opt_in_type_id FROM " << getTableName() select << "SELECT user_id, verification_code, email_opt_in_type_id, resend_count FROM " << getTableName()
<< " where " << fieldNames[0] << " = ? "; << " where " << fieldNames[0] << " = ? ";
if (conditionType == MYSQL_CONDITION_AND) { if (conditionType == MYSQL_CONDITION_AND) {
for (int i = 1; i < fieldNames.size(); i++) { for (int i = 1; i < fieldNames.size(); i++) {
@ -106,12 +106,19 @@ namespace model {
addError(new ParamError("EmailOptIn::_loadFromDB", "condition type not implemented", conditionType)); addError(new ParamError("EmailOptIn::_loadFromDB", "condition type not implemented", conditionType));
} }
//<< " where " << fieldName << " = ?" //<< " where " << fieldName << " = ?"
select , into(mUserId), into(mEmailVerificationCode), into(mType); select , into(mUserId), into(mEmailVerificationCode), into(mType), into(mResendCount);
return select; return select;
} }
size_t EmailOptIn::addResendCountAndUpdate()
{
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
mResendCount++;
return updateIntoDB("resend_count", mResendCount);
}
std::string EmailOptIn::toString() std::string EmailOptIn::toString()
{ {
std::stringstream ss; std::stringstream ss;

View File

@ -17,7 +17,7 @@ namespace model {
EMAIL_OPT_IN_REGISTER_DIRECT = 3 EMAIL_OPT_IN_REGISTER_DIRECT = 3
}; };
typedef Poco::Tuple<int, int, Poco::UInt64, int> EmailOptInTuple; typedef Poco::Tuple<int, int, Poco::UInt64, int, int> EmailOptInTuple;
class EmailOptIn : public ModelBase class EmailOptIn : public ModelBase
{ {
@ -34,10 +34,13 @@ namespace model {
inline Poco::UInt64 getCode() const { return mEmailVerificationCode; } inline Poco::UInt64 getCode() const { return mEmailVerificationCode; }
inline int getUserId() const { return mUserId; } inline int getUserId() const { return mUserId; }
inline int getResendCount() const { Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex); return mResendCount; }
inline EmailOptInType getType() const { return static_cast<EmailOptInType>(mType);} inline EmailOptInType getType() const { return static_cast<EmailOptInType>(mType);}
inline void setCode(Poco::UInt64 code) { mEmailVerificationCode = code; } inline void setCode(Poco::UInt64 code) { mEmailVerificationCode = code; }
inline void setUserId(int user_Id) { mUserId = user_Id; } inline void setUserId(int user_Id) { mUserId = user_Id; }
size_t addResendCountAndUpdate();
static const char* typeToString(EmailOptInType type); static const char* typeToString(EmailOptInType type);
protected: protected:
Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName);
@ -50,6 +53,7 @@ namespace model {
// data type must be a multiple of 4 // data type must be a multiple of 4
Poco::UInt64 mEmailVerificationCode; Poco::UInt64 mEmailVerificationCode;
int mType; int mType;
int mResendCount;
}; };

View File

@ -42,6 +42,7 @@ namespace model {
{ {
//printf("ModelBase::insertIntoDB with table: %s\n", getTableName()); //printf("ModelBase::insertIntoDB with table: %s\n", getTableName());
auto cm = ConnectionManager::getInstance(); auto cm = ConnectionManager::getInstance();
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
Poco::Data::Statement insert = _insertIntoDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER)); Poco::Data::Statement insert = _insertIntoDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER));
size_t resultCount = 0; size_t resultCount = 0;
@ -53,11 +54,9 @@ namespace model {
try { try {
return select.execute() == 1; return select.execute() == 1;
} }
catch (Poco::Exception& ex) { catch (Poco::Exception& ex) {
lock("ModelBase::insertIntoDB");
addError(new ParamError(getTableName(), "mysql error by select id", ex.displayText().data())); addError(new ParamError(getTableName(), "mysql error by select id", ex.displayText().data()));
addError(new ParamError(getTableName(), "data set: ", toString().data())); addError(new ParamError(getTableName(), "data set: ", toString().data()));
unlock();
} }
} }
else { else {
@ -66,10 +65,8 @@ namespace model {
} }
} }
catch (Poco::Exception& ex) { catch (Poco::Exception& ex) {
lock("ModelBase::insertIntoDB2");
addError(new ParamError(getTableName(), "mysql error by insert", ex.displayText().data())); addError(new ParamError(getTableName(), "mysql error by insert", ex.displayText().data()));
addError(new ParamError(getTableName(), "data set: ", toString().data())); addError(new ParamError(getTableName(), "data set: ", toString().data()));
unlock();
} }
//printf("data valid: %s\n", toString().data()); //printf("data valid: %s\n", toString().data());
return false; return false;
@ -77,10 +74,9 @@ namespace model {
bool ModelBase::deleteFromDB() bool ModelBase::deleteFromDB()
{ {
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
if (mID == 0) { if (mID == 0) {
lock();
addError(new Error(getTableName(), "id is zero, couldn't delete from db")); addError(new Error(getTableName(), "id is zero, couldn't delete from db"));
unlock();
return false; return false;
} }
auto cm = ConnectionManager::getInstance(); auto cm = ConnectionManager::getInstance();
@ -102,23 +98,21 @@ namespace model {
void ModelBase::duplicate() void ModelBase::duplicate()
{ {
lock(); Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
mReferenceCount++; mReferenceCount++;
//printf("[ModelBase::duplicate] new value: %d\n", mReferenceCount); //printf("[ModelBase::duplicate] new value: %d\n", mReferenceCount);
unlock();
} }
void ModelBase::release() void ModelBase::release()
{ {
lock(); Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
mReferenceCount--; mReferenceCount--;
//printf("[ModelBase::release] new value: %d\n", mReferenceCount); //printf("[ModelBase::release] new value: %d\n", mReferenceCount);
if (0 == mReferenceCount) { if (0 == mReferenceCount) {
unlock();
delete this; delete this;
return; return;
} }
unlock();
} }

View File

@ -13,6 +13,7 @@
#include "Poco/JSON/Object.h" #include "Poco/JSON/Object.h"
#include <shared_mutex>
//using namespace Poco::Data::Keywords; //using namespace Poco::Data::Keywords;
namespace model { namespace model {
@ -68,7 +69,7 @@ namespace model {
int mID; int mID;
// for poco auto ptr // for poco auto ptr
int mReferenceCount; int mReferenceCount;
}; };
@ -76,6 +77,7 @@ namespace model {
size_t ModelBase::loadFromDB(const std::string& fieldName, const T& fieldValue) size_t ModelBase::loadFromDB(const std::string& fieldName, const T& fieldValue)
{ {
auto cm = ConnectionManager::getInstance(); auto cm = ConnectionManager::getInstance();
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
Poco::Data::Statement select = _loadFromDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER), fieldName); Poco::Data::Statement select = _loadFromDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER), fieldName);
select, Poco::Data::Keywords::useRef(fieldValue); select, Poco::Data::Keywords::useRef(fieldValue);
@ -84,10 +86,8 @@ namespace model {
resultCount = select.execute(); resultCount = select.execute();
} }
catch (Poco::Exception& ex) { catch (Poco::Exception& ex) {
lock();
addError(new ParamError(getTableName(), "mysql error by selecting", ex.displayText().data())); addError(new ParamError(getTableName(), "mysql error by selecting", ex.displayText().data()));
addError(new ParamError(getTableName(), "field name for select: ", fieldName.data())); addError(new ParamError(getTableName(), "field name for select: ", fieldName.data()));
unlock();
} }
return resultCount; return resultCount;
} }
@ -96,6 +96,7 @@ namespace model {
bool ModelBase::isExistInDB(const std::string& fieldName, const T& fieldValue) bool ModelBase::isExistInDB(const std::string& fieldName, const T& fieldValue)
{ {
auto cm = ConnectionManager::getInstance(); auto cm = ConnectionManager::getInstance();
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
Poco::Data::Statement select(session); Poco::Data::Statement select(session);
int id; int id;
@ -122,6 +123,7 @@ namespace model {
{ {
//printf("ModelBase::loadFromDB multi\n"); //printf("ModelBase::loadFromDB multi\n");
std::vector<Tuple> results; std::vector<Tuple> results;
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
//return results; //return results;
if (expectedResults > 0) { if (expectedResults > 0) {
results.reserve(expectedResults); results.reserve(expectedResults);
@ -147,7 +149,7 @@ namespace model {
std::vector<Tuple> ModelBase::loadFromDB(const std::vector<std::string>& fieldNames, const std::vector<WhereFieldType>& fieldValues, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/, int expectedResults/* = 0*/) std::vector<Tuple> ModelBase::loadFromDB(const std::vector<std::string>& fieldNames, const std::vector<WhereFieldType>& fieldValues, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/, int expectedResults/* = 0*/)
{ {
std::vector<Tuple> results; std::vector<Tuple> results;
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
if (fieldNames.size() != fieldValues.size() || fieldNames.size() <= 1) { if (fieldNames.size() != fieldValues.size() || fieldNames.size() <= 1) {
lock(); lock();
addError(new Error(getTableName(), "fieldNames and fieldValues size don't match or smaller as 1")); addError(new Error(getTableName(), "fieldNames and fieldValues size don't match or smaller as 1"));
@ -183,6 +185,7 @@ namespace model {
size_t ModelBase::loadFromDB(const std::vector<std::string>& fieldNames, const T1& field1Value, const T2& field2Value, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/) size_t ModelBase::loadFromDB(const std::vector<std::string>& fieldNames, const T1& field1Value, const T2& field2Value, MysqlConditionType conditionType/* = MYSQL_CONDITION_AND*/)
{ {
auto cm = ConnectionManager::getInstance(); auto cm = ConnectionManager::getInstance();
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
Poco::Data::Statement select = _loadFromDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER), fieldNames, conditionType); Poco::Data::Statement select = _loadFromDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER), fieldNames, conditionType);
select, Poco::Data::Keywords::useRef(field1Value), Poco::Data::Keywords::useRef(field2Value); select, Poco::Data::Keywords::useRef(field1Value), Poco::Data::Keywords::useRef(field2Value);
@ -207,6 +210,7 @@ namespace model {
size_t ModelBase::updateIntoDB(const std::string& fieldName, const T& fieldValue) size_t ModelBase::updateIntoDB(const std::string& fieldName, const T& fieldValue)
{ {
auto cm = ConnectionManager::getInstance(); auto cm = ConnectionManager::getInstance();
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
Poco::Data::Statement update(session); Poco::Data::Statement update(session);