/* InternalSearch: Interface that can be used "internally" by the server code. One of the main differences between * this function and MLSearch is that this function does not send back an LDAP result to the client. * * Return: VmDir level error code. Also, pOperation->ldapResult content is set. */ int VmDirInternalSearch( PVDIR_OPERATION pOperation ) { int retVal = LDAP_SUCCESS; DWORD dwEntryCount = 0; BOOLEAN bHasTxn = FALSE; PSTR pszLocalErrMsg = NULL; ENTRYID eId = 0; ENTRYID* pValidatedEntries = NULL; PVDIR_LDAP_RESULT pResult = &(pOperation->ldapResult); PVDIR_OPERATION_ML_METRIC pMLMetrics = NULL; assert(pOperation && pOperation->pBEIF); pMLMetrics = &pOperation->MLMetrics; VMDIR_COLLECT_TIME(pMLMetrics->iMLStartTime); // compute required access for this search ComputeRequiredAccess(&pOperation->request.searchReq); // Normalize (base) DN retVal = VmDirNormalizeDN( &(pOperation->reqDn), pOperation->pSchemaCtx ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "DN normalization failed - (%u)(%s)", retVal, VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pOperation->pSchemaCtx)) ); if (VmDirHandleSpecialSearch( pOperation, pResult )) // TODO, add &pszLocalErrMsg { retVal = pResult->errCode ? pResult->errCode : pResult->vmdirErrCode; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, pszLocalErrMsg, "Special search failed - (%u)", retVal); goto cleanup; // done special search } if (pOperation->dbCopyCtrl) { retVal = VmDirExecDbCopyCtrl(pOperation); BAIL_ON_VMDIR_ERROR(retVal); } if (pOperation->syncReqCtrl != NULL) // Replication { pOperation->opType = VDIR_OPERATION_TYPE_REPL; } if (pOperation->pReplAgrDisableCtrl) { retVal = VmDirExecReplAgrEnableDisableCtrl(BERVAL_NORM_VAL(pOperation->reqDn), FALSE); BAIL_ON_VMDIR_ERROR(retVal); } else if (pOperation->pReplAgrEnableCtrl) { retVal = VmDirExecReplAgrEnableDisableCtrl(BERVAL_NORM_VAL(pOperation->reqDn), TRUE); BAIL_ON_VMDIR_ERROR(retVal); } // If base is not ROOT, read lock the base object (DnToEntryId index entry) to make sure it exists, and it does // not get deleted during this search processing. if (pOperation->reqDn.lberbv.bv_len != 0) { VMDIR_COLLECT_TIME(pMLMetrics->iBETxnBeginStartTime); retVal = pOperation->pBEIF->pfnBETxnBegin( pOperation->pBECtx, VDIR_BACKEND_TXN_READ ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn begin (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); bHasTxn = TRUE; VMDIR_COLLECT_TIME(pMLMetrics->iBETxnBeginEndTime); // Lookup in the DN index. retVal = pOperation->pBEIF->pfnBEDNToEntryId( pOperation->pBECtx, &(pOperation->reqDn), &eId ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "DNToEID (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); } // start txn if not has one already. if (! pOperation->pBECtx->pBEPrivate) { retVal = pOperation->pBEIF->pfnBETxnBegin( pOperation->pBECtx, VDIR_BACKEND_TXN_READ ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn begin (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); bHasTxn = TRUE; } retVal = AppendDNFilter( pOperation ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Appending DN filter failed."); /* * TODO cleanup During background thread implementation of page search */ if (gVmdirGlobals.bPagedSearchReadAhead) { if (pOperation->showPagedResultsCtrl != NULL && !IsNullOrEmptyString(pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie)) { retVal = VmDirPagedSearchCacheRead( pOperation->showPagedResultsCtrl->value.pagedResultCtrlVal.cookie, &pValidatedEntries, &dwEntryCount); BAIL_ON_VMDIR_ERROR(retVal); } } if (pOperation->showPagedResultsCtrl == NULL) { retVal = _VmDirInternalNormalSearch(pOperation); BAIL_ON_VMDIR_ERROR(retVal); } else { retVal = _VmDirInternalPagedSearch(pOperation); BAIL_ON_VMDIR_ERROR(retVal); } /* * TODO cleanup During background thread implementation of page search */ if (pValidatedEntries != NULL) { retVal = ProcessPreValidatedEntries( pOperation, dwEntryCount, pValidatedEntries); BAIL_ON_VMDIR_ERROR(retVal); } VMDIR_COLLECT_TIME(pMLMetrics->iBETxnCommitStartTime); retVal = pOperation->pBEIF->pfnBETxnCommit( pOperation->pBECtx); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn commit (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); bHasTxn = FALSE; VMDIR_COLLECT_TIME(pMLMetrics->iBETxnCommitEndTime); cleanup: // collect metrics VMDIR_COLLECT_TIME(pMLMetrics->iMLEndTime); VmDirInternalMetricsUpdate(pOperation); VmDirInternalMetricsLogInefficientOp(pOperation); VMDIR_SAFE_FREE_MEMORY(pValidatedEntries); VMDIR_SAFE_FREE_MEMORY(pszLocalErrMsg); return retVal; error: if (bHasTxn) { pOperation->pBEIF->pfnBETxnAbort(pOperation->pBECtx); } VMDIR_SET_LDAP_RESULT_ERROR(&pOperation->ldapResult, retVal, pszLocalErrMsg); goto cleanup; }
int VmDirInternalSearch( PVDIR_OPERATION pOperation ) { int retVal = LDAP_SUCCESS; ENTRYID eId = 0; int deadLockRetries = 0; BOOLEAN bHasTxn = FALSE; PSTR pszLocalErrMsg = NULL; PVDIR_LDAP_RESULT pResult = &(pOperation->ldapResult); assert(pOperation && pOperation->pBEIF); // Normalize (base) DN retVal = VmDirNormalizeDN( &(pOperation->reqDn), pOperation->pSchemaCtx ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "DN normalization failed - (%u)(%s)", retVal, VDIR_SAFE_STRING(VmDirSchemaCtxGetErrorMsg(pOperation->pSchemaCtx)) ); if (VmDirHandleSpecialSearch( pOperation, pResult )) // TODO, add &pszLocalErrMsg { retVal = pResult->errCode; BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, pszLocalErrMsg, "Special search failed - (%u)", retVal); goto cleanup; // done special search } if (pOperation->syncReqCtrl != NULL) // Replication { pOperation->lowestPendingUncommittedUsn = pOperation->pBEIF->pfnBEGetLeastOutstandingUSN( pOperation->pBECtx, FALSE ); VmDirLog( LDAP_DEBUG_REPL, "Replication request USN (%u)", pOperation->lowestPendingUncommittedUsn ); } // If base is not ROOT, read lock the base object (DnToEntryId index entry) to make sure it exists, and it does // not get deleted during this search processing. if (pOperation->reqDn.lberbv.bv_len != 0) { // ************************************************************************************ // transaction retry loop begin. make sure all function within are retry agnostic. // ************************************************************************************ txnretry: if (bHasTxn) { pOperation->pBEIF->pfnBETxnAbort( pOperation->pBECtx ); bHasTxn = FALSE; } deadLockRetries++; if (deadLockRetries > MAX_DEADLOCK_RETRIES) { retVal = VMDIR_ERROR_LOCK_DEADLOCK; BAIL_ON_VMDIR_ERROR( retVal ); } else { retVal = pOperation->pBEIF->pfnBETxnBegin( pOperation->pBECtx, VDIR_BACKEND_TXN_READ ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn begin (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); bHasTxn = TRUE; // Lookup in the DN index. retVal = pOperation->pBEIF->pfnBEDNToEntryId( pOperation->pBECtx, &(pOperation->reqDn), &eId ); if (retVal != 0) { switch (retVal) { case VMDIR_ERROR_BACKEND_DEADLOCK: goto txnretry; // Possible retry. default: BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "DNToEID (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); } } } // ************************************************************************************ // transaction retry loop end. // ************************************************************************************ } // start txn if not has one already. if (! pOperation->pBECtx->pBEPrivate) { retVal = pOperation->pBEIF->pfnBETxnBegin( pOperation->pBECtx, VDIR_BACKEND_TXN_READ ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn begin (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); bHasTxn = TRUE; } retVal = AppendDNFilter( pOperation ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Appending DN filter failed."); retVal = BuildCandidateList( pOperation, pOperation->request.searchReq.filter); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "BuildCandidateList failed."); if (pOperation->request.searchReq.filter->computeResult == FILTER_RES_TRUE) { retVal = VMDIR_ERROR_UNWILLING_TO_PERFORM; BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "Full scan of Entry DB is required. Refine your search."); } retVal = ProcessCandidateList( pOperation ); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "ProcessCandidateList failed. (%u)(%s)", retVal, VDIR_SAFE_STRING( pOperation->ldapResult.pszErrMsg) ); retVal = pOperation->pBEIF->pfnBETxnCommit( pOperation->pBECtx); BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, pszLocalErrMsg, "txn commit (%u)(%s)", retVal, VDIR_SAFE_STRING(pOperation->pBEErrorMsg)); bHasTxn = FALSE; cleanup: VMDIR_SAFE_FREE_MEMORY( pszLocalErrMsg ); return retVal; error: if (bHasTxn) { pOperation->pBEIF->pfnBETxnAbort( pOperation->pBECtx ); } VMDIR_SET_LDAP_RESULT_ERROR( &(pOperation->ldapResult), retVal, pszLocalErrMsg); goto cleanup; }