/* * meta_back_select_unique_candidate * * returns the index of the candidate in case it is unique, otherwise * META_TARGET_NONE if none matches, or * META_TARGET_MULTIPLE if more than one matches * Note: ndn MUST be normalized. */ int meta_back_select_unique_candidate( metainfo_t *mi, struct berval *ndn ) { int i, candidate = META_TARGET_NONE; for ( i = 0; i < mi->mi_ntargets; i++ ) { metatarget_t *mt = mi->mi_targets[ i ]; if ( meta_back_is_candidate( mt, ndn, LDAP_SCOPE_BASE ) ) { if ( candidate == META_TARGET_NONE ) { candidate = i; } else { return META_TARGET_MULTIPLE; } } } return candidate; }
/* * meta_back_getconn * * Prepares the connection structure * * FIXME: This function needs to receive some info on the type of operation * it is invoked by, so that only the correct pool of candidate targets * is initialized in case no connection was available yet. * * At present a flag that says whether the candidate target must be unique * is passed; eventually an operation agent will be used. */ struct metaconn * meta_back_getconn( struct metainfo *li, Connection *conn, Operation *op, int op_type, struct berval *ndn, int *candidate ) { struct metaconn *lc, lc_curr; int cached = -1, i = -1, err = LDAP_SUCCESS; int new_conn = 0; /* Searches for a metaconn in the avl tree */ lc_curr.conn = conn; ldap_pvt_thread_mutex_lock( &li->conn_mutex ); lc = (struct metaconn *)avl_find( li->conntree, (caddr_t)&lc_curr, meta_back_conn_cmp ); ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); /* Looks like we didn't get a bind. Open a new session... */ if ( !lc ) { lc = metaconn_alloc( li->ntargets ); lc->conn = conn; new_conn = 1; } /* * looks in cache, if any */ if ( li->cache.ttl != META_DNCACHE_DISABLED ) { cached = i = meta_dncache_get_target( &li->cache, ndn ); } if ( op_type == META_OP_REQUIRE_SINGLE ) { /* * tries to get a unique candidate * (takes care of default target */ if ( i < 0 ) { i = meta_back_select_unique_candidate( li, ndn ); } /* * if any is found, inits the connection */ if ( i < 0 ) { if ( new_conn ) { metaconn_free( lc ); } send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, NULL, "", NULL, NULL ); return NULL; } #ifdef NEW_LOGGING LDAP_LOG( BACK_META, INFO, "meta_back_getconn: got target %d for ndn=\"%s\" from cache\n", i, ndn->bv_val, 0 ); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_CACHE, "==>meta_back_getconn: got target %d for ndn=\"%s\" from cache\n%s", i, ndn->bv_val, "" ); #endif /* !NEW_LOGGING */ /* * Clear all other candidates */ ( void )meta_clear_unused_candidates( li, lc, i, 0 ); /* * The target is activated; if needed, it is * also init'd. In case of error, init_one_conn * sends the appropriate result. */ err = init_one_conn( conn, op, li->targets[ i ], &lc->conns[ i ] ); if ( err != LDAP_SUCCESS ) { /* * FIXME: in case one target cannot * be init'd, should the other ones * be tried? */ ( void )meta_clear_one_candidate( &lc->conns[ i ], 1 ); if ( new_conn ) { metaconn_free( lc ); } return NULL; } if ( candidate ) { *candidate = i; } /* * require all connections ... */ } else if (op_type == META_OP_REQUIRE_ALL) { for ( i = 0; i < li->ntargets; i++ ) { /* * The target is activated; if needed, it is * also init'd */ int lerr = init_one_conn( conn, op, li->targets[ i ], &lc->conns[ i ] ); if ( lerr != LDAP_SUCCESS ) { /* * FIXME: in case one target cannot * be init'd, should the other ones * be tried? */ ( void )meta_clear_one_candidate( &lc->conns[ i ], 1 ); err = lerr; continue; } } /* * if no unique candidate ... */ } else { for ( i = 0; i < li->ntargets; i++ ) { if ( i == cached || meta_back_is_candidate( &li->targets[ i ]->suffix, ndn ) ) { /* * The target is activated; if needed, it is * also init'd */ int lerr = init_one_conn( conn, op, li->targets[ i ], &lc->conns[ i ] ); if ( lerr != LDAP_SUCCESS ) { /* * FIXME: in case one target cannot * be init'd, should the other ones * be tried? */ ( void )meta_clear_one_candidate( &lc->conns[ i ], 1 ); err = lerr; continue; } } } } if ( new_conn ) { /* * Inserts the newly created metaconn in the avl tree */ ldap_pvt_thread_mutex_lock( &li->conn_mutex ); err = avl_insert( &li->conntree, ( caddr_t )lc, meta_back_conn_cmp, meta_back_conn_dup ); #if PRINT_CONNTREE > 0 myprint( li->conntree ); #endif /* PRINT_CONNTREE */ ldap_pvt_thread_mutex_unlock( &li->conn_mutex ); #ifdef NEW_LOGGING LDAP_LOG( BACK_META, INFO, "meta_back_getconn: conn %ld inserted\n", lc->conn->c_connid, 0, 0); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_TRACE, "=>meta_back_getconn: conn %ld inserted\n%s%s", lc->conn->c_connid, "", "" ); #endif /* !NEW_LOGGING */ /* * Err could be -1 in case a duplicate metaconn is inserted */ if ( err != 0 ) { send_ldap_result( conn, op, LDAP_OTHER, NULL, "Internal server error", NULL, NULL ); metaconn_free( lc ); return NULL; } } else { #ifdef NEW_LOGGING LDAP_LOG( BACK_META, INFO, "meta_back_getconn: conn %ld fetched\n", lc->conn->c_connid, 0, 0 ); #else /* !NEW_LOGGING */ Debug( LDAP_DEBUG_TRACE, "=>meta_back_getconn: conn %ld fetched\n%s%s", lc->conn->c_connid, "", "" ); #endif /* !NEW_LOGGING */ } return lc; }