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
changed to poco mutex for gradido login server
default mutex from poco is recursive so it is some heavy thing
\author Dario Rekowski
@ -50,8 +51,8 @@ namespace UniLib {
inline const std::string& getLastSucceededLock() { return mLastSucceededLock; }
protected:
mutable Poco::Mutex mWorkMutex;
private:
Poco::Mutex mWorkMutex;
std::string mLastSucceededLock;
};
}

View File

@ -7,25 +7,25 @@ using namespace Poco::Data::Keywords;
namespace model {
namespace table {
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*/)
: mUserId(0), mEmailVerificationCode(code), mType(type)
: mUserId(0), mEmailVerificationCode(code), mType(type), mResendCount(0)
{
}
EmailOptIn::EmailOptIn()
: mUserId(0), mEmailVerificationCode(0)
: mUserId(0), mEmailVerificationCode(0), mResendCount(0)
{
}
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();
insert << "INSERT INTO " << getTableName()
<< " (user_id, verification_code, email_opt_in_type_id) VALUES(?,?,?)"
, use(mUserId), use(mEmailVerificationCode), bind(mType);
<< " (user_id, verification_code, email_opt_in_type_id, resend_count) VALUES(?,?,?,?)"
, use(mUserId), use(mEmailVerificationCode), bind(mType), bind(mResendCount);
unlock();
return insert;
}
@ -53,9 +53,9 @@ namespace model {
{
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 << " = ?"
, into(mID), into(mUserId), into(mEmailVerificationCode), into(mType);
, into(mID), into(mUserId), into(mEmailVerificationCode), into(mType), into(mResendCount);
return select;
@ -76,7 +76,7 @@ namespace model {
{
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 << " = ?";
@ -90,7 +90,7 @@ namespace model {
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] << " = ? ";
if (conditionType == MYSQL_CONDITION_AND) {
for (int i = 1; i < fieldNames.size(); i++) {
@ -106,12 +106,19 @@ namespace model {
addError(new ParamError("EmailOptIn::_loadFromDB", "condition type not implemented", conditionType));
}
//<< " where " << fieldName << " = ?"
select , into(mUserId), into(mEmailVerificationCode), into(mType);
select , into(mUserId), into(mEmailVerificationCode), into(mType), into(mResendCount);
return select;
}
size_t EmailOptIn::addResendCountAndUpdate()
{
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
mResendCount++;
return updateIntoDB("resend_count", mResendCount);
}
std::string EmailOptIn::toString()
{
std::stringstream ss;

View File

@ -17,7 +17,7 @@ namespace model {
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
{
@ -34,10 +34,13 @@ namespace model {
inline Poco::UInt64 getCode() const { return mEmailVerificationCode; }
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 void setCode(Poco::UInt64 code) { mEmailVerificationCode = code; }
inline void setUserId(int user_Id) { mUserId = user_Id; }
size_t addResendCountAndUpdate();
static const char* typeToString(EmailOptInType type);
protected:
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
Poco::UInt64 mEmailVerificationCode;
int mType;
int mResendCount;
};

View File

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

View File

@ -13,6 +13,7 @@
#include "Poco/JSON/Object.h"
#include <shared_mutex>
//using namespace Poco::Data::Keywords;
namespace model {
@ -68,7 +69,7 @@ namespace model {
int mID;
// 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)
{
auto cm = ConnectionManager::getInstance();
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
Poco::Data::Statement select = _loadFromDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER), fieldName);
select, Poco::Data::Keywords::useRef(fieldValue);
@ -84,10 +86,8 @@ namespace model {
resultCount = select.execute();
}
catch (Poco::Exception& ex) {
lock();
addError(new ParamError(getTableName(), "mysql error by selecting", ex.displayText().data()));
addError(new ParamError(getTableName(), "field name for select: ", fieldName.data()));
unlock();
}
return resultCount;
}
@ -96,6 +96,7 @@ namespace model {
bool ModelBase::isExistInDB(const std::string& fieldName, const T& fieldValue)
{
auto cm = ConnectionManager::getInstance();
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
Poco::Data::Statement select(session);
int id;
@ -122,6 +123,7 @@ namespace model {
{
//printf("ModelBase::loadFromDB multi\n");
std::vector<Tuple> results;
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
//return results;
if (expectedResults > 0) {
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> results;
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
if (fieldNames.size() != fieldValues.size() || fieldNames.size() <= 1) {
lock();
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*/)
{
auto cm = ConnectionManager::getInstance();
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
Poco::Data::Statement select = _loadFromDB(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER), fieldNames, conditionType);
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)
{
auto cm = ConnectionManager::getInstance();
Poco::ScopedLock<Poco::Mutex> _lock(mWorkMutex);
auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER);
Poco::Data::Statement update(session);