From 0a8a140351a533e2fb895228589efd2846b9c697 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Fri, 30 Mar 2018 16:47:09 +0300 Subject: fix for asynchronous database flush to fix unsaved data --- plugins/Dbx_mdbx/src/dbcontacts.cpp | 6 ++ plugins/Dbx_mdbx/src/dbcrypt.cpp | 3 + plugins/Dbx_mdbx/src/dbevents.cpp | 4 + plugins/Dbx_mdbx/src/dbintf.cpp | 24 ++++++ plugins/Dbx_mdbx/src/dbintf.h | 130 ++++++++++++++++----------------- plugins/Dbx_mdbx/src/dbmodulechain.cpp | 1 + plugins/Dbx_mdbx/src/dbsettings.cpp | 4 + 7 files changed, 106 insertions(+), 66 deletions(-) (limited to 'plugins/Dbx_mdbx/src') diff --git a/plugins/Dbx_mdbx/src/dbcontacts.cpp b/plugins/Dbx_mdbx/src/dbcontacts.cpp index 24faa109fc..aa3a27f8f2 100644 --- a/plugins/Dbx_mdbx/src/dbcontacts.cpp +++ b/plugins/Dbx_mdbx/src/dbcontacts.cpp @@ -77,6 +77,7 @@ STDMETHODIMP_(LONG) CDbxMDBX::DeleteContact(MCONTACT contactID) // free cache item m_cache->FreeCachedContact(contactID); + DBFlush(); InterlockedDecrement(&m_contactCount); return 0; @@ -98,6 +99,7 @@ STDMETHODIMP_(MCONTACT) CDbxMDBX::AddContact() return 0; } + DBFlush(); InterlockedIncrement(&m_contactCount); NotifyEventHooks(hContactAddedEvent, dwContactId, 0); return dwContactId; @@ -155,6 +157,8 @@ BOOL CDbxMDBX::MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) return 1; if (trnlck.commit() != MDBX_SUCCESS) return 1; + + DBFlush(); return 0; } @@ -185,6 +189,8 @@ BOOL CDbxMDBX::MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) return 1; if (trnlck.commit() != MDBX_SUCCESS) return 1; + + DBFlush(); return 0; } diff --git a/plugins/Dbx_mdbx/src/dbcrypt.cpp b/plugins/Dbx_mdbx/src/dbcrypt.cpp index 0a6585e565..e22b3a293d 100644 --- a/plugins/Dbx_mdbx/src/dbcrypt.cpp +++ b/plugins/Dbx_mdbx/src/dbcrypt.cpp @@ -62,6 +62,7 @@ CRYPTO_PROVIDER* CDbxMDBX::SelectProvider() return nullptr; } + DBFlush(); return pProv; } @@ -137,6 +138,7 @@ void CDbxMDBX::StoreKey() } SecureZeroMemory(pKey, iKeyLength); + DBFlush(); } void CDbxMDBX::SetPassword(const wchar_t *ptszPassword) @@ -228,6 +230,7 @@ int CDbxMDBX::EnableEncryption(bool bEncrypted) if (trnlck.commit() != MDBX_SUCCESS) return 1; + DBFlush(); m_bEncrypted = bEncrypted; return 0; } diff --git a/plugins/Dbx_mdbx/src/dbevents.cpp b/plugins/Dbx_mdbx/src/dbevents.cpp index 4ad32afe54..ad8d478b73 100644 --- a/plugins/Dbx_mdbx/src/dbevents.cpp +++ b/plugins/Dbx_mdbx/src/dbevents.cpp @@ -134,6 +134,8 @@ STDMETHODIMP_(MEVENT) CDbxMDBX::AddEvent(MCONTACT contactID, DBEVENTINFO *dbei) return 0; } + DBFlush(); + // Notify only in safe mode or on really new events if (m_safetyMode) NotifyEventHooks(hEventAddedEvent, contactNotifyID, dwEventId); @@ -214,6 +216,7 @@ STDMETHODIMP_(BOOL) CDbxMDBX::DeleteEvent(MCONTACT contactID, MEVENT hDbEvent) return 1; } + DBFlush(); NotifyEventHooks(hEventDeletedEvent, contactID, hDbEvent); return 0; } @@ -340,6 +343,7 @@ STDMETHODIMP_(BOOL) CDbxMDBX::MarkEventRead(MCONTACT contactID, MEVENT hDbEvent) return -1; } + DBFlush(); NotifyEventHooks(hEventMarkedRead, contactID, (LPARAM)hDbEvent); return wRetVal; } diff --git a/plugins/Dbx_mdbx/src/dbintf.cpp b/plugins/Dbx_mdbx/src/dbintf.cpp index 79f5f0a4f1..b94edd4845 100644 --- a/plugins/Dbx_mdbx/src/dbintf.cpp +++ b/plugins/Dbx_mdbx/src/dbintf.cpp @@ -95,6 +95,7 @@ int CDbxMDBX::Load(bool bSkipInit) m_header.dwVersion = DBHEADER_VERSION; data.iov_base = &m_header; data.iov_len = sizeof(m_header); mdbx_put(trnlck, m_dbGlobal, &key, &data, 0); + DBFlush(); } keyVal = 2; @@ -183,6 +184,7 @@ int CDbxMDBX::PrepareCheck() STDMETHODIMP_(void) CDbxMDBX::SetCacheSafetyMode(BOOL bIsSet) { m_safetyMode = bIsSet != 0; + DBFlush(true); } int CDbxMDBX::Map() @@ -203,3 +205,25 @@ int CDbxMDBX::Map() int exclusive = (m_bShared) ? 1 : 2; return mdbx_env_open_ex(m_env, _T2A(m_tszProfileName), mode, 0664, &exclusive); } + +///////////////////////////////////////////////////////////////////////////////////////// + +static VOID CALLBACK DoBufferFlushTimerProc(HWND, UINT, UINT_PTR idEvent, DWORD) +{ + KillTimer(nullptr, idEvent); + + for (auto &it : g_Dbs) + if (it->m_timerId == idEvent) + it->DBFlush(true); +} + +void CDbxMDBX::DBFlush(bool bForce) +{ + if (bForce) { + mdbx_env_sync(m_env, true); + } + else if (m_safetyMode) { + ::KillTimer(nullptr, m_timerId); + ::SetTimer(nullptr, m_timerId, 50, DoBufferFlushTimerProc); + } +} diff --git a/plugins/Dbx_mdbx/src/dbintf.h b/plugins/Dbx_mdbx/src/dbintf.h index d858deeb3e..a1e4c992c7 100644 --- a/plugins/Dbx_mdbx/src/dbintf.h +++ b/plugins/Dbx_mdbx/src/dbintf.h @@ -129,17 +129,10 @@ struct EventItem MEVENT eventId; }; -struct CDbxMDBX : public MDatabaseCommon, public MZeroedObject +class CDbxMDBX : public MDatabaseCommon, public MZeroedObject { friend class MDBXEventCursor; - CDbxMDBX(const TCHAR *tszFileName, int mode); - virtual ~CDbxMDBX(); - - int Load(bool bSkipInit); - int Create(void); - int Check(void); - __forceinline MDBX_txn* StartTran() const { MDBX_txn *res = 0; @@ -150,66 +143,17 @@ struct CDbxMDBX : public MDatabaseCommon, public MZeroedObject return res; } - void StoreKey(void); - void SetPassword(const wchar_t *ptszPassword); - void UpdateMenuItem(void); - + void FillContacts(void); + int Map(); int PrepareCheck(); + void UpdateMenuItem(void); - __forceinline LPSTR GetMenuTitle() const { return m_bUsesPassword ? (char*)LPGEN("Change/remove password") : (char*)LPGEN("Set password"); } - - __forceinline bool isEncrypted() const { return m_bEncrypted; } - __forceinline bool usesPassword() const { return m_bUsesPassword; } - int EnableEncryption(bool bEnable); -public: - STDMETHODIMP_(BOOL) IsRelational(void) { return TRUE; } - STDMETHODIMP_(void) SetCacheSafetyMode(BOOL); - - STDMETHODIMP_(LONG) GetContactCount(void); - STDMETHODIMP_(LONG) DeleteContact(MCONTACT contactID); - STDMETHODIMP_(MCONTACT) AddContact(void); - STDMETHODIMP_(BOOL) IsDbContact(MCONTACT contactID); - STDMETHODIMP_(LONG) GetContactSize(void); - - STDMETHODIMP_(LONG) GetEventCount(MCONTACT contactID); - STDMETHODIMP_(MEVENT) AddEvent(MCONTACT contactID, DBEVENTINFO *dbe); - STDMETHODIMP_(BOOL) DeleteEvent(MCONTACT contactID, MEVENT hDbEvent); - STDMETHODIMP_(LONG) GetBlobSize(MEVENT hDbEvent); - STDMETHODIMP_(BOOL) GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbe); - STDMETHODIMP_(BOOL) MarkEventRead(MCONTACT contactID, MEVENT hDbEvent); - STDMETHODIMP_(MCONTACT) GetEventContact(MEVENT hDbEvent); - STDMETHODIMP_(MEVENT) FindFirstEvent(MCONTACT contactID); - STDMETHODIMP_(MEVENT) FindFirstUnreadEvent(MCONTACT contactID); - STDMETHODIMP_(MEVENT) FindLastEvent(MCONTACT contactID); - STDMETHODIMP_(MEVENT) FindNextEvent(MCONTACT contactID, MEVENT hDbEvent); - STDMETHODIMP_(MEVENT) FindPrevEvent(MCONTACT contactID, MEVENT hDbEvent); - - STDMETHODIMP_(BOOL) EnumModuleNames(DBMODULEENUMPROC pFunc, void *pParam); - - STDMETHODIMP_(BOOL) GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic); - STDMETHODIMP_(BOOL) WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws); - STDMETHODIMP_(BOOL) DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting); - STDMETHODIMP_(BOOL) EnumContactSettings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param); - - STDMETHODIMP_(BOOL) MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub); - STDMETHODIMP_(BOOL) MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub); - -protected: - - void FillContacts(void); - - int Map(); + //////////////////////////////////////////////////////////////////////////// + // database stuff -protected: TCHAR* m_tszProfileName; bool m_safetyMode, m_bReadOnly, m_bShared, m_bEncrypted, m_bUsesPassword; - //////////////////////////////////////////////////////////////////////////// - // database stuff -public: - MICryptoEngine *m_crypto; - -protected: MDBX_env *m_env; CMDBX_txn_ro m_txn_ro; @@ -241,7 +185,7 @@ protected: //////////////////////////////////////////////////////////////////////////// // events - MDBX_dbi m_dbEvents, m_dbEventsSort; + MDBX_dbi m_dbEvents, m_dbEventsSort; MDBX_cursor *m_curEvents, *m_curEventsSort; MEVENT m_dwMaxEventId; @@ -254,11 +198,11 @@ protected: MDBX_dbi m_dbModules; MDBX_cursor *m_curModules; - + std::map m_Modules; int InitModules(); - + uint32_t GetModuleID(const char *szName); char* GetModuleName(uint32_t dwId); @@ -271,4 +215,58 @@ protected: CRYPTO_PROVIDER* SelectProvider(); void InitDialogs(); -}; \ No newline at end of file + +public: + CDbxMDBX(const TCHAR *tszFileName, int mode); + virtual ~CDbxMDBX(); + + int Check(void); + int Create(void); + void DBFlush(bool bForce = false); + int EnableEncryption(bool bEnable); + int Load(bool bSkipInit); + void StoreKey(void); + void SetPassword(const wchar_t *ptszPassword); + + __forceinline LPSTR GetMenuTitle() const { return m_bUsesPassword ? (char*)LPGEN("Change/remove password") : (char*)LPGEN("Set password"); } + + __forceinline bool isEncrypted() const { return m_bEncrypted; } + __forceinline bool usesPassword() const { return m_bUsesPassword; } + +public: + STDMETHODIMP_(BOOL) IsRelational(void) { return TRUE; } + STDMETHODIMP_(void) SetCacheSafetyMode(BOOL); + + STDMETHODIMP_(LONG) GetContactCount(void); + STDMETHODIMP_(LONG) DeleteContact(MCONTACT contactID); + STDMETHODIMP_(MCONTACT) AddContact(void); + STDMETHODIMP_(BOOL) IsDbContact(MCONTACT contactID); + STDMETHODIMP_(LONG) GetContactSize(void); + + STDMETHODIMP_(LONG) GetEventCount(MCONTACT contactID); + STDMETHODIMP_(MEVENT) AddEvent(MCONTACT contactID, DBEVENTINFO *dbe); + STDMETHODIMP_(BOOL) DeleteEvent(MCONTACT contactID, MEVENT hDbEvent); + STDMETHODIMP_(LONG) GetBlobSize(MEVENT hDbEvent); + STDMETHODIMP_(BOOL) GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbe); + STDMETHODIMP_(BOOL) MarkEventRead(MCONTACT contactID, MEVENT hDbEvent); + STDMETHODIMP_(MCONTACT) GetEventContact(MEVENT hDbEvent); + STDMETHODIMP_(MEVENT) FindFirstEvent(MCONTACT contactID); + STDMETHODIMP_(MEVENT) FindFirstUnreadEvent(MCONTACT contactID); + STDMETHODIMP_(MEVENT) FindLastEvent(MCONTACT contactID); + STDMETHODIMP_(MEVENT) FindNextEvent(MCONTACT contactID, MEVENT hDbEvent); + STDMETHODIMP_(MEVENT) FindPrevEvent(MCONTACT contactID, MEVENT hDbEvent); + + STDMETHODIMP_(BOOL) EnumModuleNames(DBMODULEENUMPROC pFunc, void *pParam); + + STDMETHODIMP_(BOOL) GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic); + STDMETHODIMP_(BOOL) WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws); + STDMETHODIMP_(BOOL) DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting); + STDMETHODIMP_(BOOL) EnumContactSettings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param); + + STDMETHODIMP_(BOOL) MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub); + STDMETHODIMP_(BOOL) MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub); + +public: + MICryptoEngine *m_crypto; + UINT_PTR m_timerId; // timer to flush unsaved data +}; diff --git a/plugins/Dbx_mdbx/src/dbmodulechain.cpp b/plugins/Dbx_mdbx/src/dbmodulechain.cpp index daaaf494ff..0ab6b3eb58 100644 --- a/plugins/Dbx_mdbx/src/dbmodulechain.cpp +++ b/plugins/Dbx_mdbx/src/dbmodulechain.cpp @@ -52,6 +52,7 @@ uint32_t CDbxMDBX::GetModuleID(const char *szName) } m_Modules[iHash] = szName; + DBFlush(); } return iHash; diff --git a/plugins/Dbx_mdbx/src/dbsettings.cpp b/plugins/Dbx_mdbx/src/dbsettings.cpp index e8294b4b72..83211cd36f 100644 --- a/plugins/Dbx_mdbx/src/dbsettings.cpp +++ b/plugins/Dbx_mdbx/src/dbsettings.cpp @@ -348,6 +348,8 @@ LBL_WriteString: // notify lck.unlock(); + + DBFlush(); NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwNotif); return 0; } @@ -381,6 +383,8 @@ STDMETHODIMP_(BOOL) CDbxMDBX::DeleteContactSetting(MCONTACT contactID, LPCSTR sz m_cache->GetCachedValuePtr(contactID, szCachedSettingName, -1); } + DBFlush(); + // notify DBCONTACTWRITESETTING dbcws = { 0 }; dbcws.szModule = szModule; -- cgit v1.2.3