LMDBCursor* LMDB::NewCursor() { MDB_txn* mdb_txn; MDB_cursor* mdb_cursor; MDB_CHECK(mdb_txn_begin(mdb_env_, NULL, MDB_RDONLY, &mdb_txn)); MDB_CHECK(mdb_dbi_open(mdb_txn, NULL, 0, &mdb_dbi_)); MDB_CHECK(mdb_cursor_open(mdb_txn, mdb_dbi_, &mdb_cursor)); return new LMDBCursor(mdb_txn, mdb_cursor); }
void LMDB::Open(const string& source, Mode mode) { MDB_CHECK(mdb_env_create(&mdb_env_)); MDB_CHECK(mdb_env_set_mapsize(mdb_env_, LMDB_MAP_SIZE)); if (mode == NEW) { CHECK_EQ(mkdir(source.c_str(), 0744), 0) << "mkdir " << source << "failed"; } int flags = 0; if (mode == READ) { flags = MDB_RDONLY | MDB_NOTLS; } MDB_CHECK(mdb_env_open(mdb_env_, source.c_str(), flags, 0664)); LOG(INFO) << "Opened lmdb " << source; }
/** * This function works in stages. First we clean up the given key to prevent * any trickery by users. Then we retrieve the existing value, increment it, * and store it back in the db. */ uint64_t counter_inc(counter_t *lc, const char *key) { char clean_key[KEYSZ] = { 0 }; key_clean(clean_key, key); clean_key[15] = '\0'; MDB_val mkey, data, update; MDB_txn *txn = NULL; mkey.mv_size = (KEYSZ) * sizeof(char); mkey.mv_data = (void *)clean_key; mdb_txn_begin(lc->env, NULL, 0, &txn); uint64_t stored_counter = 0; // We only care about success here, since if mdb_get fails it is because // the key doesn't exist and we need to make it. if(mdb_get(txn, *lc->dbi, &mkey, &data) == MDB_SUCCESS) { stored_counter = *(uint64_t *)data.mv_data; } stored_counter++; update.mv_size = sizeof(uint64_t); update.mv_data = (void *)&stored_counter; if(mdb_put(txn, *lc->dbi, &mkey, &update, 0) != MDB_SUCCESS) { perror("mdb_put"); mdb_txn_abort(txn); return 0; } MDB_CHECK(mdb_txn_commit(txn), MDB_SUCCESS, 0); return stored_counter; }
void LMDBTransaction::Put(const string& key, const string& value) { MDB_val mdb_key, mdb_value; mdb_key.mv_data = const_cast<char*>(key.data()); mdb_key.mv_size = key.size(); mdb_value.mv_data = const_cast<char*>(value.data()); mdb_value.mv_size = value.size(); MDB_CHECK(mdb_put(mdb_txn_, *mdb_dbi_, &mdb_key, &mdb_value, 0)); }
void Seek(MDB_cursor_op op) { int mdb_status = mdb_cursor_get(mdb_cursor_, &mdb_key_, &mdb_value_, op); if (mdb_status == MDB_NOTFOUND) { valid_ = false; } else { MDB_CHECK(mdb_status); valid_ = true; } }
void LMDB::Open(const string& source, Mode mode) { MDB_CHECK(mdb_env_create(&mdb_env_)); MDB_CHECK(mdb_env_set_mapsize(mdb_env_, LMDB_MAP_SIZE)); if (mode == NEW) { CHECK_EQ(mkdir(source.c_str(), 0744), 0) << "mkdir " << source << " failed"; } int flags = 0; if (mode == READ) { flags = MDB_RDONLY | MDB_NOTLS; } int rc = mdb_env_open(mdb_env_, source.c_str(), flags, 0664); #ifndef ALLOW_LMDB_NOLOCK MDB_CHECK(rc); #else if (rc == EACCES) { LOG(WARNING) << "Permission denied. Trying with MDB_NOLOCK ..."; // Close and re-open environment handle mdb_env_close(mdb_env_); MDB_CHECK(mdb_env_create(&mdb_env_)); // Try again with MDB_NOLOCK flags |= MDB_NOLOCK; MDB_CHECK(mdb_env_open(mdb_env_, source.c_str(), flags, 0664)); } else { MDB_CHECK(rc); } #endif LOG(INFO) << "Opened lmdb " << source; }
counter_t *counter_init(const char *path, uint64_t readers) { counter_t *lc = NULL; if((lc = calloc(1, sizeof(counter_t))) == NULL) { perror("calloc"); return NULL; } // Setup and open the lmdb enviornment MDB_CHECK(mdb_env_create(&lc->env), MDB_SUCCESS, NULL); MDB_CHECK(mdb_env_set_maxreaders(lc->env, readers), MDB_SUCCESS, NULL); MDB_CHECK(mdb_env_set_mapsize(lc->env, MDB_MAPSIZE), MDB_SUCCESS, NULL); MDB_CHECK(mdb_env_open(lc->env, path, MDB_WRITEMAP | MDB_MAPASYNC | MDB_NOSUBDIR, 0664), MDB_SUCCESS, NULL); MDB_txn *txn = NULL; MDB_CHECK(mdb_txn_begin(lc->env, NULL, 0, &txn), MDB_SUCCESS, NULL); if((lc->dbi = calloc(1, sizeof(MDB_dbi))) == NULL) { perror("calloc"); return NULL; } MDB_CHECK(mdb_dbi_open(txn, NULL, 0, lc->dbi), MDB_SUCCESS, NULL); mdb_txn_commit(txn); return lc; }
void LMDBCursor::Seek(MDB_cursor_op op) { #ifdef _MSC_VER if (op != MDB_FIRST) VirtualUnlock(mdb_value_.mv_data, mdb_value_.mv_size); #endif int mdb_status = mdb_cursor_get(mdb_cursor_, &mdb_key_, &mdb_value_, op); if (mdb_status == MDB_NOTFOUND) { valid_ = false; } else { MDB_CHECK(mdb_status); valid_ = true; } }
STDMETHODIMP_(BOOL) CDbxMdb::DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting) { if (!szModule || !szSetting) return 1; int settingNameLen = (int)strlen(szSetting); int moduleNameLen = (int)strlen(szModule); MCONTACT saveContact = contactID; { mir_cslock lck(m_csDbAccess); char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen); if (szCachedSettingName[-1] == 0) { // it's not a resident variable DBSettingKey keySearch; keySearch.dwContactID = contactID; keySearch.dwOfsModule = GetModuleNameOfs(szModule); strncpy_s(keySearch.szSettingName, szSetting, _TRUNCATE); MDB_val key = { 2 * sizeof(DWORD) + settingNameLen, &keySearch }, data; for (;; Remap()) { txn_ptr trnlck(m_pMdbEnv); MDB_CHECK(mdb_del(trnlck, m_dbSettings, &key, &data), 1); if (trnlck.commit()) break; } } m_cache->GetCachedValuePtr(saveContact, szCachedSettingName, -1); } // notify DBCONTACTWRITESETTING dbcws = { 0 }; dbcws.szModule = szModule; dbcws.szSetting = szSetting; dbcws.value.type = DBVT_DELETED; NotifyEventHooks(hSettingChangeEvent, saveContact, (LPARAM)&dbcws); return 0; }
LMDBTransaction* LMDB::NewTransaction() { MDB_txn* mdb_txn; MDB_CHECK(mdb_txn_begin(mdb_env_, NULL, 0, &mdb_txn)); MDB_CHECK(mdb_dbi_open(mdb_txn, NULL, 0, &mdb_dbi_)); return new LMDBTransaction(&mdb_dbi_, mdb_txn); }
virtual void Commit() { MDB_CHECK(mdb_txn_commit(mdb_txn_)); }
STDMETHODIMP_(BOOL) CDbxMdb::WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws) { if (dbcws == NULL || dbcws->szSetting == NULL || dbcws->szModule == NULL || m_bReadOnly) return 1; // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name int settingNameLen = (int)strlen(dbcws->szSetting); int moduleNameLen = (int)strlen(dbcws->szModule); if (settingNameLen > 0xFE) { #ifdef _DEBUG OutputDebugStringA("WriteContactSetting() got a > 255 setting name length. \n"); #endif return 1; } if (moduleNameLen > 0xFE) { #ifdef _DEBUG OutputDebugStringA("WriteContactSetting() got a > 255 module name length. \n"); #endif return 1; } // used for notifications DBCONTACTWRITESETTING dbcwNotif = *dbcws; if (dbcwNotif.value.type == DBVT_WCHAR) { if (dbcwNotif.value.pszVal != NULL) { char* val = mir_utf8encodeW(dbcwNotif.value.pwszVal); if (val == NULL) return 1; dbcwNotif.value.pszVal = (char*)alloca(strlen(val) + 1); strcpy(dbcwNotif.value.pszVal, val); mir_free(val); dbcwNotif.value.type = DBVT_UTF8; } else return 1; } if (dbcwNotif.szModule == NULL || dbcwNotif.szSetting == NULL) return 1; DBCONTACTWRITESETTING dbcwWork = dbcwNotif; mir_ptr<BYTE> pEncoded(NULL); bool bIsEncrypted = false; switch (dbcwWork.value.type) { case DBVT_BYTE: case DBVT_WORD: case DBVT_DWORD: break; case DBVT_ASCIIZ: case DBVT_UTF8: bIsEncrypted = m_bEncrypted || IsSettingEncrypted(dbcws->szModule, dbcws->szSetting); LBL_WriteString: if (dbcwWork.value.pszVal == NULL) return 1; dbcwWork.value.cchVal = (WORD)strlen(dbcwWork.value.pszVal); if (bIsEncrypted) { size_t len; BYTE *pResult = m_crypto->encodeString(dbcwWork.value.pszVal, &len); if (pResult != NULL) { pEncoded = dbcwWork.value.pbVal = pResult; dbcwWork.value.cpbVal = (WORD)len; dbcwWork.value.type = DBVT_ENCRYPTED; } } break; case DBVT_UNENCRYPTED: dbcwNotif.value.type = dbcwWork.value.type = DBVT_UTF8; goto LBL_WriteString; case DBVT_BLOB: case DBVT_ENCRYPTED: if (dbcwWork.value.pbVal == NULL) return 1; break; default: return 1; } mir_cslockfull lck(m_csDbAccess); char *szCachedSettingName = m_cache->GetCachedSetting(dbcwWork.szModule, dbcwWork.szSetting, moduleNameLen, settingNameLen); // we don't cache blobs and passwords if (dbcwWork.value.type != DBVT_BLOB && dbcwWork.value.type != DBVT_ENCRYPTED && !bIsEncrypted) { DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); if (pCachedValue != NULL) { bool bIsIdentical = false; if (pCachedValue->type == dbcwWork.value.type) { switch (dbcwWork.value.type) { case DBVT_BYTE: bIsIdentical = pCachedValue->bVal == dbcwWork.value.bVal; break; case DBVT_WORD: bIsIdentical = pCachedValue->wVal == dbcwWork.value.wVal; break; case DBVT_DWORD: bIsIdentical = pCachedValue->dVal == dbcwWork.value.dVal; break; case DBVT_UTF8: case DBVT_ASCIIZ: bIsIdentical = strcmp(pCachedValue->pszVal, dbcwWork.value.pszVal) == 0; break; } if (bIsIdentical) return 0; } m_cache->SetCachedVariant(&dbcwWork.value, pCachedValue); } if (szCachedSettingName[-1] != 0) { lck.unlock(); NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwWork); return 0; } } else m_cache->GetCachedValuePtr(contactID, szCachedSettingName, -1); DBSettingKey keySearch; keySearch.dwContactID = contactID; keySearch.dwOfsModule = GetModuleNameOfs(dbcws->szModule); strncpy_s(keySearch.szSettingName, dbcws->szSetting, _TRUNCATE); MDB_val key = { 2 * sizeof(DWORD) + settingNameLen, &keySearch }, data; switch (dbcwWork.value.type) { case DBVT_BYTE: data.mv_size = 2; break; case DBVT_WORD: data.mv_size = 3; break; case DBVT_DWORD: data.mv_size = 5; break; case DBVT_ASCIIZ: case DBVT_UTF8: data.mv_size = 3 + dbcwWork.value.cchVal; break; case DBVT_BLOB: case DBVT_ENCRYPTED: data.mv_size = 3 + dbcwWork.value.cpbVal; break; } for (;; Remap()) { txn_ptr trnlck(m_pMdbEnv); MDB_CHECK(mdb_put(trnlck, m_dbSettings, &key, &data, MDB_RESERVE), 1); BYTE *pBlob = (BYTE*)data.mv_data; *pBlob++ = dbcwWork.value.type; switch (dbcwWork.value.type) { case DBVT_BYTE: *pBlob = dbcwWork.value.bVal; break; case DBVT_WORD: *(WORD*)pBlob = dbcwWork.value.wVal; break; case DBVT_DWORD: *(DWORD*)pBlob = dbcwWork.value.dVal; break; case DBVT_ASCIIZ: case DBVT_UTF8: data.mv_size = *(WORD*)pBlob = dbcwWork.value.cchVal; pBlob += 2; memcpy(pBlob, dbcwWork.value.pszVal, dbcwWork.value.cchVal); break; case DBVT_BLOB: case DBVT_ENCRYPTED: data.mv_size = *(WORD*)pBlob = dbcwWork.value.cpbVal; pBlob += 2; memcpy(pBlob, dbcwWork.value.pbVal, dbcwWork.value.cpbVal); } if (trnlck.commit()) break; } lck.unlock(); // notify NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwNotif); return 0; }
virtual void flush() { MDB_CHECK(mdb_txn_commit(mdb_txn_)); }