Esempio n. 1
0
/* VmDirMDBDNToEntry: For a given entry DN, reads an entry from the entry DB.
 *
 * Returns: BE error - BACKEND_ERROR, BACKEND OPERATIONS, BACKEND_ENTRY_NOTFOUND
 *
 */
DWORD
VmDirMDBDNToEntry(
    PVDIR_BACKEND_CTX           pBECtx,
    PVDIR_SCHEMA_CTX            pSchemaCtx,
    VDIR_BERVALUE*              pDn,
    PVDIR_ENTRY                 pEntry,
    VDIR_BACKEND_ENTRY_LOCKTYPE entryLockType)
{
    DWORD       dwError = LDAP_SUCCESS;
    ENTRYID     eId = {0};

    // make sure we look up normalized dn value
    dwError = VmDirNormalizeDN( pDn, pSchemaCtx );
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirMDBDNToEntryId( pBECtx, pDn, &eId );
    BAIL_ON_VMDIR_ERROR( dwError );

    dwError = VmDirMDBEIdToEntry( pBECtx, pSchemaCtx, eId, pEntry, entryLockType );
    BAIL_ON_VMDIR_ERROR( dwError );

cleanup:

    return dwError;

error:

    VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "BEDNToEntry DN (%s) failed, (%u)(%s)",
                     VDIR_SAFE_STRING( pDn->bvnorm_val), dwError, VDIR_SAFE_STRING(pBECtx->pszBEErrorMsg) );

    VMDIR_SET_BACKEND_ERROR(dwError);   // if dwError no in BE space, set to ERROR_BACKEND_ERROR

    goto cleanup;
}
Esempio n. 2
0
/* MdbDeleteEntry: Deletes an entry in the MDB DBs.
 *
 * Returns: BE error codes.
 *
 */
DWORD
VmDirMDBDeleteEntry(
    PVDIR_BACKEND_CTX   pBECtx,
    PVDIR_MODIFICATION  pMods,
    PVDIR_ENTRY         pEntry
    )
{
    DWORD                   dwError = 0;
    VDIR_MODIFICATION *     mod = NULL;
    PVDIR_DB_TXN            pTxn = NULL;

    assert( pBECtx && pBECtx->pBEPrivate && pMods && pEntry );

    pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate;

    // Delete child from the parentId index
    dwError = MDBDeleteParentIdIndex( pBECtx, &(pEntry->pdn), pEntry->eId );
    BAIL_ON_VMDIR_ERROR(dwError);

    for (mod = pMods; mod != NULL; mod = mod->next)
    {
        switch (mod->operation)
        {
            case MOD_OP_DELETE:
                if ((dwError = MdbUpdateIndicesForAttr( pBECtx->pBE, pTxn, &(pEntry->dn), &(mod->attr.type), mod->attr.vals, mod->attr.numVals,
                                                       pEntry->eId, BE_INDEX_OP_TYPE_DELETE )) != 0)
                {
                    dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx,
                                                VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val));
                    BAIL_ON_VMDIR_ERROR( dwError );
                }
                break;
            default:
                assert( FALSE );
        }
    }

    // Delete Entry Blob
    if ((dwError = MDBDeleteEntryBlob(pBECtx, pEntry->eId)) != 0)
    {
        dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, "MDBDeleteEntryBlob");
        BAIL_ON_VMDIR_ERROR( dwError );
    }

cleanup:
     return dwError;

error:
    VMDIR_SET_BACKEND_ERROR(dwError);   // if dwError no in BE space, set to ERROR_BACKEND_ERROR

    VMDIR_LOG_ERROR(LDAP_DEBUG_BACKEND, "VmDirMDBDeleteEntry: failed: error=%d,DN=%s",
                    dwError, VDIR_SAFE_STRING(pEntry->dn.lberbv.bv_val));
     goto cleanup;
}
Esempio n. 3
0
/* MdbCheckRefIntegrity: Checks for the attributes that have referential integrity constraint set, that the DN attribute
 *                    values refer to existing objects.
 *
 * Returns: BE error codes.
 *
 */
DWORD
VmDirMDBCheckRefIntegrity(
    PVDIR_BACKEND_CTX   pBECtx,
    PVDIR_ENTRY         pEntry)
{
    DWORD               dwError = 0;
    VDIR_ATTRIBUTE *    attr = NULL;

    assert( pBECtx && pBECtx->pBEPrivate  && pEntry );

    for (attr = pEntry->attrs; attr; attr = attr->next)
    {
        // SJ-TBD: Instead of checking referential integrity for hard coded attributes, we should have a
        // proprietary flag e.g. X-constraint in the attribute schema definition
        if (VmDirStringCompareA(attr->type.lberbv.bv_val, ATTR_MEMBER, FALSE) == 0)
        {
            unsigned int i = 0;
            ENTRYID   eId = 0;
            for (; i < attr->numVals; i++)
            {
                // Lookup in the DN index.
                if ((dwError = VmDirNormalizeDN( &(attr->vals[i]), pEntry->pSchemaCtx)) != 0)
                {
                    dwError = ERROR_BACKEND_OPERATIONS;
                    BAIL_ON_VMDIR_ERROR( dwError );
                }

                if ((dwError = VmDirMDBDNToEntryId( pBECtx, &(attr->vals[i]), &eId )) != 0)
                {
                    dwError = MDBToBackendError(dwError, ERROR_BACKEND_ENTRY_NOTFOUND,
                                                ERROR_BACKEND_CONSTRAINT, pBECtx,
                                                VDIR_SAFE_STRING(attr->vals[i].lberbv.bv_val));
                    BAIL_ON_VMDIR_ERROR( dwError );
                }
            }
        }
    }

cleanup:

    return dwError;

error:
    // TODO set pBECtx->pszBEErrorMsg
    VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "BE DN (%s) reference check, error (%u)(%s)",
                     pEntry->dn.lberbv_val, dwError, VDIR_SAFE_STRING(pBECtx->pszBEErrorMsg) );

    VMDIR_SET_BACKEND_ERROR(dwError);   // if dwError no in BE space, set to ERROR_BACKEND_ERROR

    goto cleanup;
}
Esempio n. 4
0
/* MdbDeleteEntry: Deletes an entry in the MDB DBs.
 *
 * Returns: BE error codes.
 *
 */
DWORD
VmDirMDBDeleteEntry(
    PVDIR_BACKEND_CTX   pBECtx,
    PVDIR_MODIFICATION  pMods,
    PVDIR_ENTRY         pEntry
    )
{
    DWORD   dwError = 0;

    assert( pBECtx && pBECtx->pBEPrivate && pEntry );

    // Delete child from the parentId index
    dwError = MDBDeleteParentIdIndex( pBECtx, &(pEntry->pdn), pEntry->eId );
    BAIL_ON_VMDIR_ERROR(dwError);

    dwError = VmDirMDBModifyEntry( pBECtx, pMods, pEntry);
    BAIL_ON_VMDIR_ERROR( dwError );

    if ((dwError = MDBCreateParentIdIndex( pBECtx, &(gVmdirServerGlobals.delObjsContainerDN), pEntry->eId )) != 0)
    {
        dwError = MDBToBackendError(dwError, ERROR_BACKEND_ENTRY_NOTFOUND,
                                    ERROR_BACKEND_PARENT_NOTFOUND, pBECtx, "CreateParentIdIndex");
        BAIL_ON_VMDIR_ERROR( dwError );
    }

cleanup:

    return dwError;

error:

    VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "BEDeleteEntry DN (%s) failed, (%u)(%s)",
                              VDIR_SAFE_STRING( pEntry->dn.bvnorm_val),
                              dwError, VDIR_SAFE_STRING(pBECtx->pszBEErrorMsg) );

    VMDIR_SET_BACKEND_ERROR(dwError);   // if dwError no in BE space, set to ERROR_BACKEND_ERROR

    goto cleanup;
}
Esempio n. 5
0
/* MdbModifyEntry: Updates an entry in the MDB DBs.
 *
 * Returns: BE error codes.
 *
 */
DWORD
VmDirMDBModifyEntry(
    PVDIR_BACKEND_CTX   pBECtx,
    VDIR_MODIFICATION*  pMods,
    PVDIR_ENTRY         pEntry
    )
{
    DWORD                   dwError = 0;
    VDIR_BERVALUE           newEncodedEntry = VDIR_BERVALUE_INIT;
    VDIR_MODIFICATION *     mod = NULL;
    PVDIR_DB_TXN            pTxn = NULL;

    assert( pBECtx && pBECtx->pBEPrivate && pMods && pEntry );

    pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate;

    dwError = VmDirEncodeEntry( pEntry, &newEncodedEntry );
    BAIL_ON_VMDIR_ERROR(dwError);

    VMDIR_SAFE_FREE_MEMORY( pEntry->encodedEntry );
    // entry takes over the responsibility to free newEncodedEntry.lberbv.bv_val
    pEntry->encodedEntry = (unsigned char *)newEncodedEntry.lberbv.bv_val;

    // Create/Delete appropriate indices for indexed attributes.
    for (mod = pMods; mod != NULL; mod = mod->next)
    {
        if (mod->ignore)
        {
            continue;
        }
        switch (mod->operation)
        {
            case MOD_OP_ADD:
                if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(mod->attr.type), mod->attr.vals, mod->attr.numVals,
                                                       pEntry->eId, BE_INDEX_OP_TYPE_CREATE)) != 0)
                {
                    dwError = MDBToBackendError( dwError, MDB_KEYEXIST, ERROR_BACKEND_CONSTRAINT, pBECtx,
                                                 VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val));
                    BAIL_ON_VMDIR_ERROR( dwError );
                }
                break;

            case MOD_OP_DELETE:
                if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(mod->attr.type), mod->attr.vals, mod->attr.numVals,
                                                       pEntry->eId, BE_INDEX_OP_TYPE_DELETE )) != 0)
                {
                    dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx,
                                                VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val));
                    BAIL_ON_VMDIR_ERROR( dwError );
                }
                break;

            case MOD_OP_REPLACE:
            default:
                assert( FALSE );
        }
        if ((dwError = MdbUpdateAttrMetaData( pTxn, &(mod->attr), pEntry->eId, BE_INDEX_OP_TYPE_UPDATE )) != 0)
        {
            dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx,
                                        VDIR_SAFE_STRING(mod->attr.type.lberbv.bv_val));
            BAIL_ON_VMDIR_ERROR( dwError );
        }
    }

    // Update Entry DB.
    if ((dwError = MdbCreateEIDIndex(pTxn, pEntry->eId, &newEncodedEntry, FALSE /* update current eId key */)) != 0)
    {
        dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, "CreateEIDIndex");
        BAIL_ON_VMDIR_ERROR( dwError );
    }

cleanup:

     return dwError;

error:

    VMDIR_SET_BACKEND_ERROR(dwError);   // if dwError no in BE space, set to ERROR_BACKEND_ERROR

    VMDIR_LOG_ERROR(LDAP_DEBUG_BACKEND,
             "ModifyEntry failed: error=%d,DN=%s", dwError, VDIR_SAFE_STRING(pEntry->dn.lberbv.bv_val));

     goto cleanup;
}
Esempio n. 6
0
/* MdbEIdToEntry: For a given entry ID, reads an entry from the entry DB.
 *
 * Returns: BE error - BACKEND_ERROR, BACKEND OPERATIONS, BACKEND_ENTRY_NOTFOUND
 *
 */
DWORD
VmDirMDBEIdToEntry(
    PVDIR_BACKEND_CTX           pBECtx,
    PVDIR_SCHEMA_CTX            pSchemaCtx,
    ENTRYID                     eId,
    PVDIR_ENTRY                 pEntry,
    VDIR_BACKEND_ENTRY_LOCKTYPE entryLockType)
{
    DWORD           dwError = 0;
    VDIR_DB         mdbDBi = 0;
    PVDIR_DB_TXN    pTxn = NULL;
    VDIR_DB_DBT     key = {0};
    VDIR_DB_DBT     value = {0};
    unsigned char   eIdBytes[sizeof( ENTRYID )] = {0};
    unsigned char*  pszBlob = NULL;

    assert(pBECtx && pBECtx->pBEPrivate && pSchemaCtx && pEntry);

    pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate;

    mdbDBi = gVdirMdbGlobals.mdbEntryDB.pMdbDataFiles[0].mdbDBi;

    // Set key
    key.mv_data = &eIdBytes[0];
    MDBEntryIdToDBT(eId, &key);

    if ((dwError = mdb_get(pTxn, mdbDBi, &key, &value) ) != 0)
    {
        dwError = MDBToBackendError(dwError, MDB_NOTFOUND, ERROR_BACKEND_ENTRY_NOTFOUND, pBECtx, "EIDToEntry");
        BAIL_ON_VMDIR_ERROR( dwError );
    }

    if ((dwError = VmDirAllocateMemory( value.mv_size, (PVOID *)&pszBlob)) != 0)
    {
        dwError = ERROR_BACKEND_OPERATIONS;
        BAIL_ON_VMDIR_ERROR( dwError );
    }

    if ((dwError = VmDirCopyMemory(pszBlob, value.mv_size, value.mv_data, value.mv_size)) != 0)
    {
        dwError = ERROR_BACKEND_OPERATIONS;
        BAIL_ON_VMDIR_ERROR( dwError );
    }

    // encodedEntry takes over pszBlob
    pEntry->encodedEntry = pszBlob;
    pszBlob = NULL;

    pEntry->eId = eId;
    dwError = VmDirDecodeEntry(pSchemaCtx, pEntry );
    BAIL_ON_VMDIR_ERROR(dwError);

cleanup:

    return dwError;

error:

    VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "VmDirMDBEIdToEntry, eid(%u) failed (%u)", eId, dwError);

    VMDIR_SAFE_FREE_MEMORY(pszBlob);
    VmDirFreeEntryContent( pEntry );

    VMDIR_SET_BACKEND_ERROR(dwError);   // if dwError no in BE space, set to ERROR_BACKEND_ERROR

    goto cleanup;
}
Esempio n. 7
0
/* MdbAddEntry: Creates an entry in the MDB DBs.
 *
 * Returns: BE error codes.
 *
 */
DWORD
VmDirMDBAddEntry(
    PVDIR_BACKEND_CTX   pBECtx,
    PVDIR_ENTRY         pEntry)
{
    DWORD             dwError = 0;
    ENTRYID           entryId = 0;
    VDIR_DB_TXN*      pTxn = NULL;
    VDIR_BERVALUE     encodedEntry = VDIR_BERVALUE_INIT;
    VDIR_ATTRIBUTE *  nextAttr = NULL;

    assert( pEntry && pBECtx && pBECtx->pBEPrivate );

    pTxn = (PVDIR_DB_TXN)pBECtx->pBEPrivate;

    dwError = VmDirEncodeEntry( pEntry, &encodedEntry );
    BAIL_ON_VMDIR_ERROR(dwError);

    if (pEntry->eId != 0)    // Reserved entries have eId already
    {
        entryId = pEntry->eId;
    }
    else
    {
        VDIR_DB_DBT     EIDkey = {0};
        VDIR_DB_DBT     EIDvalue  = {0};
        unsigned char   EIDKeyBytes[sizeof( ENTRYID )] = {0};
        unsigned char   EIDValueBytes[sizeof( ENTRYID )] = {0};

        EIDkey.mv_data = &EIDKeyBytes[0];
        MDBEntryIdToDBT(BE_MDB_ENTRYID_SEQ_KEY, &EIDkey);

        dwError =  mdb_get(pTxn, gVdirMdbGlobals.mdbSeqDBi, &EIDkey, &EIDvalue);
        BAIL_ON_VMDIR_ERROR(dwError);

        assert( EIDvalue.mv_size == sizeof(ENTRYID) );
        entryId = *((ENTRYID*)EIDvalue.mv_data);

        *((ENTRYID*)&EIDValueBytes[0]) = entryId + 1;
        EIDvalue.mv_data = &EIDValueBytes[0];
        EIDvalue.mv_size = sizeof(ENTRYID);

        dwError =  mdb_put(pTxn, gVdirMdbGlobals.mdbSeqDBi, &EIDkey, &EIDvalue, BE_DB_FLAGS_ZERO);
        BAIL_ON_VMDIR_ERROR(dwError);
    }

    assert( entryId > 0 );

    if ((dwError = MDBCreateParentIdIndex(pBECtx, &(pEntry->pdn), entryId)) != 0)
    {
        dwError = MDBToBackendError(dwError, ERROR_BACKEND_ENTRY_NOTFOUND,
                                    ERROR_BACKEND_PARENT_NOTFOUND, pBECtx, "CreateParentIdIndex");
        BAIL_ON_VMDIR_ERROR( dwError );
    }

    // Update DN index first. this make sure we always return ERROR_BACKEND_ENTRY_EXISTS in such case.
    for (nextAttr = pEntry->attrs; nextAttr != NULL; nextAttr = nextAttr->next)
    {
        if (VmDirStringCompareA(nextAttr->type.lberbv.bv_val, ATTR_DN, FALSE) == 0)
        {
            // make sure we store normalized DN value.
            dwError = VmDirNormalizeDN( &(nextAttr->vals[0]), pEntry->pSchemaCtx );
            BAIL_ON_VMDIR_ERROR(dwError);

            if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(nextAttr->type), nextAttr->vals, nextAttr->numVals,
                                                    entryId, BE_INDEX_OP_TYPE_CREATE)) != 0)
            {
                dwError = MDBToBackendError( dwError,
                                             MDB_KEYEXIST,
                                             ERROR_BACKEND_ENTRY_EXISTS,
                                             pBECtx,
                                             VDIR_SAFE_STRING(nextAttr->vals[0].bvnorm_val));
                BAIL_ON_VMDIR_ERROR( dwError );
            }
            if ((dwError = MdbUpdateAttrMetaData( pTxn, nextAttr, entryId, BE_INDEX_OP_TYPE_CREATE )) != 0)
            {
                dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx, "UpdateDNAttrMetaData");
                BAIL_ON_VMDIR_ERROR( dwError );
            }
        }
    }

    // Update remaining indices
    for (nextAttr = pEntry->attrs; nextAttr != NULL; nextAttr = nextAttr->next)
    {
        if (VmDirStringCompareA(nextAttr->type.lberbv.bv_val, ATTR_DN, FALSE) != 0)
        {
            if ((dwError = MdbUpdateIndicesForAttr( pTxn, &(nextAttr->type), nextAttr->vals, nextAttr->numVals,
                                                    entryId, BE_INDEX_OP_TYPE_CREATE)) != 0)
            {
                dwError = MDBToBackendError( dwError,
                                             MDB_KEYEXIST,
                                             ERROR_BACKEND_CONSTRAINT,
                                             pBECtx,
                                             VDIR_SAFE_STRING(nextAttr->type.lberbv.bv_val));
                BAIL_ON_VMDIR_ERROR( dwError );
            }
            if ((dwError = MdbUpdateAttrMetaData( pTxn, nextAttr, entryId, BE_INDEX_OP_TYPE_CREATE )) != 0)
            {
                dwError = MDBToBackendError(dwError, 0, ERROR_BACKEND_ERROR, pBECtx,
                                            VDIR_SAFE_STRING(nextAttr->type.lberbv.bv_val));
                BAIL_ON_VMDIR_ERROR( dwError );
            }
        }
    }

    // Update entry/blob database
    if ((dwError = MdbCreateEIDIndex(pTxn, entryId, &encodedEntry, TRUE /* 1st time new entry creation */)) != 0)
    {
        dwError = MDBToBackendError(dwError, MDB_KEYEXIST, ERROR_BACKEND_CONSTRAINT, pBECtx, "CreateEIDIndex");
        BAIL_ON_VMDIR_ERROR( dwError );
    }

cleanup:

    VMDIR_SAFE_FREE_MEMORY( encodedEntry.lberbv.bv_val );

    return dwError;

error:
    // TODO set pBECtx->pszBEErrorMsg?
    VMDIR_LOG_ERROR( LDAP_DEBUG_BACKEND, "BEAddEntry DN (%s),  (%u)(%s)", VDIR_SAFE_STRING(pEntry->dn.lberbv.bv_val),
                              dwError, VDIR_SAFE_STRING(pBECtx->pszBEErrorMsg));

    VMDIR_SET_BACKEND_ERROR(dwError);   // if dwError no in BE space, set to ERROR_BACKEND_ERROR

    goto cleanup;
}
Esempio n. 8
0
// 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;
}