DWORD VmDirMDBIndexIteratorInit( PVDIR_INDEX_CFG pIndexCfg, PSTR pszInitVal, PVDIR_BACKEND_INDEX_ITERATOR* ppIterator ) { DWORD dwError = 0; VDIR_DB mdbDBi = 0; PSTR pszInitKey = NULL; VDIR_DB_DBT key = {0}; VDIR_DB_DBT value = {0}; PSTR pszVal = NULL; ENTRYID eId = 0; PVDIR_DB_TXN pTxn = NULL; PVDIR_DB_DBC pCursor = NULL; PVDIR_BACKEND_INDEX_ITERATOR pIterator = NULL; PVDIR_MDB_INDEX_ITERATOR pMdbIterator = NULL; if (!pIndexCfg || !ppIterator) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } dwError = VmDirAllocateMemory( sizeof(VDIR_BACKEND_INDEX_ITERATOR), (PVOID*)&pIterator); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirAllocateMemory( sizeof(VDIR_MDB_INDEX_ITERATOR), (PVOID*)&pMdbIterator); BAIL_ON_VMDIR_ERROR(dwError); pIterator->pIterator = (PVOID)pMdbIterator; dwError = VmDirMDBIndexGetDBi(pIndexCfg, &mdbDBi); BAIL_ON_VMDIR_ERROR(dwError); dwError = mdb_txn_begin(gVdirMdbGlobals.mdbEnv, NULL, MDB_RDONLY, &pTxn); BAIL_ON_VMDIR_ERROR(dwError); pMdbIterator->pTxn = pTxn; dwError = mdb_cursor_open(pTxn, mdbDBi, &pCursor); BAIL_ON_VMDIR_ERROR(dwError); pMdbIterator->pCursor = pCursor; if (IsNullOrEmptyString(pszInitVal)) { dwError = mdb_cursor_get(pCursor, &key, &value, MDB_FIRST); } else { dwError = VmDirAllocateStringPrintf( &pszInitKey, "%c%s", BE_INDEX_KEY_TYPE_FWD, pszInitVal); BAIL_ON_VMDIR_ERROR(dwError); key.mv_data = pszInitKey; key.mv_size = VmDirStringLenA(pszInitKey); dwError = mdb_cursor_get(pCursor, &key, &value, MDB_SET_RANGE); } if (dwError == 0 && *(char *)(key.mv_data) == BE_INDEX_KEY_TYPE_FWD) { dwError = VmDirAllocateMemory(key.mv_size, (PVOID*)&pszVal); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirCopyMemory( pszVal, key.mv_size, (char*)key.mv_data + 1, key.mv_size - 1); BAIL_ON_VMDIR_ERROR(dwError); MDBDBTToEntryId(&value, &eId); pIterator->bHasNext = TRUE; } else { pIterator->bHasNext = FALSE; dwError = dwError == MDB_NOTFOUND ? 0 : dwError; pMdbIterator->bAbort = dwError ? TRUE : FALSE; } BAIL_ON_VMDIR_ERROR(dwError); pMdbIterator->pszVal = pszVal; pMdbIterator->eId = eId; *ppIterator = pIterator; cleanup: VMDIR_SAFE_FREE_MEMORY(pszInitKey); return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError ); VmDirMDBIndexIteratorFree(pIterator); VMDIR_SAFE_FREE_MEMORY(pszVal); goto cleanup; }
// To get the current max ENTRYID // Entry database is separated from log databases. DWORD VmDirMDBMaxEntryId( PVDIR_BACKEND_INTERFACE pBE, ENTRYID* pEId ) { DWORD dwError = 0; VDIR_DB mdbDBi = 0; PVDIR_DB_DBC pCursor = NULL; MDB_val key = {0}; MDB_val value = {0}; ENTRYID eId = {0}; unsigned char EIDBytes[sizeof(ENTRYID)] = {0}; VDIR_BACKEND_CTX mdbBECtx = {0}; BOOLEAN bHasTxn = FALSE; PVDIR_MDB_DB pDB = VmDirSafeDBFromBE(pBE); assert(pEId && pDB); mdbBECtx.pBE = pBE; dwError = VmDirMDBTxnBegin(&mdbBECtx, VDIR_BACKEND_TXN_READ, &bHasTxn); BAIL_ON_VMDIR_ERROR(dwError); mdbDBi = pDB->mdbEntryDB.pMdbDataFiles[0].mdbDBi; dwError = mdb_cursor_open((PVDIR_DB_TXN)mdbBECtx.pBEPrivate, mdbDBi, &pCursor); BAIL_ON_VMDIR_ERROR(dwError); key.mv_data = &EIDBytes[0]; if (pBE == VmDirBackendSelect(ALIAS_MAIN)) { //Set cursor position equal or above LOG_ENTRY_EID_PREFIX // it would find the first entry id of raft log entry on legacy data // i.e. database creaded before we implemented a split log. eId = LOG_ENTRY_EID_PREFIX; MDBEntryIdToDBT(eId, &key); dwError = mdb_cursor_get(pCursor, &key, &value, MDB_SET_RANGE); if (dwError == MDB_NOTFOUND) { //mainDb was created after we implemented split log (no log entries in mainDb) // - simply find the last id which will be the last entry-id in normal entries. eId = 0; MDBEntryIdToDBT(eId, &key); dwError = mdb_cursor_get(pCursor, &key, &value, MDB_LAST); BAIL_ON_VMDIR_ERROR(dwError); MDBDBTToEntryId(&key, &eId); } else { BAIL_ON_VMDIR_ERROR(dwError); //Found an entry that is LOG_ENTRY_EID_PREFIX or above // - search backward, and the first one is the last normal entry do { dwError = mdb_cursor_get(pCursor, &key, &value, MDB_PREV); BAIL_ON_VMDIR_ERROR(dwError); MDBDBTToEntryId(&key, &eId); } while (eId >= LOG_ENTRY_EID_PREFIX); } } else { //For logDb, the last one is the log entry. eId = 0; MDBEntryIdToDBT(eId, &key); dwError = mdb_cursor_get(pCursor, &key, &value, MDB_LAST); BAIL_ON_VMDIR_ERROR(dwError); MDBDBTToEntryId(&key, &eId); } mdb_cursor_close(pCursor); pCursor = NULL; if (bHasTxn) { dwError = VmDirMDBTxnCommit(&mdbBECtx); bHasTxn = FALSE; BAIL_ON_VMDIR_ERROR(dwError); } *pEId = eId; cleanup: return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "VmDirMDBMaxEntryId: failed with error (%d),(%s)", dwError, mdb_strerror(dwError) ); mdb_cursor_close(pCursor); if (bHasTxn) { VmDirMDBTxnAbort(&mdbBECtx); } VMDIR_SET_BACKEND_ERROR(dwError); goto cleanup; }
DWORD VmDirMDBIndexIterate( PVDIR_BACKEND_INDEX_ITERATOR pIterator, PSTR* ppszVal, ENTRYID* pEId ) { DWORD dwError = 0; PVDIR_MDB_INDEX_ITERATOR pMdbIterator = NULL; PVDIR_DB_DBC pCursor = NULL; VDIR_DB_DBT key = {0}; VDIR_DB_DBT value = {0}; PSTR pszVal = NULL; ENTRYID eId = 0; if (!pIterator || !ppszVal || !pEId) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_VMDIR_ERROR(dwError); } pMdbIterator = (PVDIR_MDB_INDEX_ITERATOR)pIterator->pIterator; pCursor = pMdbIterator->pCursor; if (pIterator->bHasNext) { *ppszVal = pMdbIterator->pszVal; *pEId = pMdbIterator->eId; dwError = mdb_cursor_get(pCursor, &key, &value, MDB_NEXT); if (dwError == 0 && *(char *)(key.mv_data) == BE_INDEX_KEY_TYPE_FWD) { dwError = VmDirAllocateMemory(key.mv_size, (PVOID*)&pszVal); BAIL_ON_VMDIR_ERROR(dwError); dwError = VmDirCopyMemory( pszVal, key.mv_size, (char*)key.mv_data + 1, key.mv_size - 1); BAIL_ON_VMDIR_ERROR(dwError); MDBDBTToEntryId(&value, &eId); pIterator->bHasNext = TRUE; } else { pIterator->bHasNext = FALSE; dwError = dwError == MDB_NOTFOUND ? 0 : dwError; pMdbIterator->bAbort = dwError ? TRUE : FALSE; } BAIL_ON_VMDIR_ERROR(dwError); pMdbIterator->pszVal = pszVal; pMdbIterator->eId = eId; } cleanup: return dwError; error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "%s failed, error (%d)", __FUNCTION__, dwError ); VMDIR_SAFE_FREE_MEMORY(pszVal); goto cleanup; }