/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 2001-2006 The OpenLDAP Foundation.
+ * Copyright 2001-2008 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#define SLAPD_TOOLS
#include "slap.h"
+#include "config.h"
typedef struct gluenode {
BackendDB *gn_be;
int nctrls;
} glue_state;
+static int
+glue_op_cleanup( Operation *op, SlapReply *rs )
+{
+ /* This is not a final result */
+ if (rs->sr_type == REP_RESULT )
+ rs->sr_type = REP_GLUE_RESULT;
+ return SLAP_CB_CONTINUE;
+}
+
static int
glue_op_response ( Operation *op, SlapReply *rs )
{
if (!j) {
newctrls = ch_malloc((i+1)*sizeof(LDAPControl *));
} else {
+ /* Forget old pagedResults response if we're sending
+ * a new one now
+ */
+ if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
+ int newpage = 0;
+ for ( k=0; k<i; k++ ) {
+ if ( !strcmp(rs->sr_ctrls[k]->ldctl_oid,
+ LDAP_CONTROL_PAGEDRESULTS )) {
+ newpage = 1;
+ break;
+ }
+ }
+ if ( newpage ) {
+ for ( k=0; k<j; k++ ) {
+ if ( !strcmp(gs->ctrls[k]->ldctl_oid,
+ LDAP_CONTROL_PAGEDRESULTS )) {
+ gs->ctrls[k]->ldctl_oid = NULL;
+ ldap_control_free( gs->ctrls[k] );
+ gs->ctrls[k] = gs->ctrls[--j];
+ gs->ctrls[j] = NULL;
+ break;
+ }
+ }
+ }
+ }
newctrls = ch_realloc(gs->ctrls,
(j+i+1)*sizeof(LDAPControl *));
}
case LDAP_REQ_DELETE: which = op_delete; break;
case LDAP_REQ_MODIFY: which = op_modify; break;
case LDAP_REQ_MODRDN: which = op_modrdn; break;
+ case LDAP_REQ_EXTENDED: which = op_extended; break;
default: assert( 0 ); break;
}
if ( func[which] )
rc = func[which]( op, rs );
else
- rc = SLAP_CB_CONTINUE;
+ rc = SLAP_CB_BYPASS;
op->o_bd = b0;
op->o_bd->bd_info = bi0;
return rc;
}
+static int
+glue_response ( Operation *op, SlapReply *rs )
+{
+ BackendDB *be = op->o_bd;
+ be = glue_back_select (op->o_bd, &op->o_req_ndn);
+
+ /* If we're on the master backend, let overlay framework handle it.
+ * Otherwise, bail out.
+ */
+ return ( op->o_bd == be ) ? SLAP_CB_CONTINUE : SLAP_CB_BYPASS;
+}
+
static int
glue_chk_referrals ( Operation *op, SlapReply *rs )
{
return rc;
}
+/* ITS#4615 - overlays configured above the glue overlay should be
+ * invoked for the entire glued tree. Overlays configured below the
+ * glue overlay should only be invoked on the master backend.
+ * So, if we're searching on any subordinates, we need to force the
+ * current overlay chain to stop processing, without stopping the
+ * overall callback flow.
+ */
static int
glue_sub_search( Operation *op, SlapReply *rs, BackendDB *b0,
slap_overinst *on )
int i;
long stoptime = 0, starttime;
glue_state gs = {NULL, NULL, NULL, 0, 0, 0, 0};
- slap_callback cb = { NULL, glue_op_response, NULL, NULL };
+ slap_callback cb = { NULL, glue_op_response, glue_op_cleanup, NULL };
int scope0, tlimit0;
struct berval dn, ndn, *pdn;
continue;
if (get_no_subordinate_glue(op) && btmp != b1)
continue;
+ /* If we remembered which backend we were on before,
+ * skip down to it now
+ */
+ if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED &&
+ op->o_conn->c_pagedresults_state.ps_be &&
+ op->o_conn->c_pagedresults_state.ps_be != btmp )
+ continue;
if (tlimit0 != SLAP_NO_LIMIT) {
op->o_time = slap_get_time();
case LDAP_X_CANNOT_CHAIN:
#endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */
goto end_of_loop;
-
+
+ case LDAP_SUCCESS:
+ if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
+ PagedResultsState *ps = op->o_pagedresults_state;
+
+ /* Assume this backend can be forgotten now */
+ op->o_conn->c_pagedresults_state.ps_be = NULL;
+
+ /* If we have a full page, exit the loop. We may
+ * need to remember this backend so we can continue
+ * from here on a subsequent request.
+ */
+ if ( rs->sr_nentries >= ps->ps_size ) {
+ /* Don't bother to remember the first backend.
+ * Only remember the last one if there's more state left.
+ */
+ if ( op->o_bd != b0 &&
+ ( op->o_conn->c_pagedresults_state.ps_cookie ||
+ op->o_bd != gi->gi_n[0].gn_be ))
+ op->o_conn->c_pagedresults_state.ps_be = op->o_bd;
+ goto end_of_loop;
+ }
+
+ /* This backend has run out of entries, but more responses
+ * can fit in the page. Fake a reset of the state so the
+ * next backend will start up properly. Only back-[bh]db
+ * and back-sql look at this state info.
+ */
+ if ( ps->ps_cookieval.bv_len == sizeof( PagedResultsCookie )) {
+ ps->ps_cookie = 0;
+ memset( ps->ps_cookieval.bv_val, 0,
+ sizeof( PagedResultsCookie ));
+ }
+ }
+
default:
break;
}
glueinfo *gi = on->on_bi.bi_private;
static int glueOpened = 0;
int i, j, same, bsame = 0, rc = 0;
+ ConfigReply cr = {0};
if (glueOpened) return 0;
gi->gi_n[i].gn_be->bd_info );
/* Let backend.c take care of the rest of startup */
if ( !rc )
- rc = backend_startup_one( gi->gi_n[i].gn_be );
+ rc = backend_startup_one( gi->gi_n[i].gn_be, &cr );
if ( rc ) break;
}
if ( !rc && !bsame && on->on_info->oi_orig->bi_open )
return rc;
}
+static int
+glue_entry_get_rw (
+ Operation *op,
+ struct berval *dn,
+ ObjectClass *oc,
+ AttributeDescription *ad,
+ int rw,
+ Entry **e )
+{
+ int rc;
+ BackendDB *b0 = op->o_bd;
+ op->o_bd = glue_back_select( b0, dn );
+
+ if ( op->o_bd->be_fetch ) {
+ rc = op->o_bd->be_fetch( op, dn, oc, ad, rw, e );
+ } else {
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ }
+ op->o_bd =b0;
+ return rc;
+}
+
static int
glue_entry_release_rw (
Operation *op,
int rw
)
{
- BackendDB *b0, b2;
+ BackendDB *b0 = op->o_bd;
int rc = -1;
- b0 = op->o_bd;
- b2 = *op->o_bd;
- b2.bd_info = (BackendInfo *)glue_tool_inst( op->o_bd->bd_info );
- op->o_bd = glue_back_select (&b2, &e->e_nname);
+ op->o_bd = glue_back_select (b0, &e->e_nname);
if ( op->o_bd->be_release ) {
rc = op->o_bd->be_release( op, e, rw );
return rc;
}
+static ID
+glue_tool_dn2id_get (
+ BackendDB *b0,
+ struct berval *dn
+)
+{
+ BackendDB *be, b2;
+ int rc = -1;
+
+ b2 = *b0;
+ b2.bd_info = (BackendInfo *)glue_tool_inst( b0->bd_info );
+ be = glue_back_select (&b2, dn);
+ if ( be == &b2 ) be = &toolDB;
+
+ if (!be->be_dn2id_get)
+ return NOID;
+
+ if (!glueBack) {
+ if ( be->be_entry_open ) {
+ rc = be->be_entry_open (be, glueMode);
+ }
+ if (rc != 0) {
+ return NOID;
+ }
+ } else if (be != glueBack) {
+ /* If this entry belongs in a different branch than the
+ * previous one, close the current database and open the
+ * new one.
+ */
+ if ( glueBack->be_entry_close ) {
+ glueBack->be_entry_close (glueBack);
+ }
+ if ( be->be_entry_open ) {
+ rc = be->be_entry_open (be, glueMode);
+ }
+ if (rc != 0) {
+ return NOID;
+ }
+ }
+ glueBack = be;
+ return be->be_dn2id_get (be, dn);
+}
+
static Entry *
glue_tool_entry_get (
BackendDB *b0,
return be->be_entry_put (be, e, text);
}
+static ID
+glue_tool_entry_modify (
+ BackendDB *b0,
+ Entry *e,
+ struct berval *text
+)
+{
+ if (!glueBack || !glueBack->be_entry_modify)
+ return NOID;
+
+ return glueBack->be_entry_modify (glueBack, e, text);
+}
+
static int
glue_tool_entry_reindex (
BackendDB *b0,
- ID id
+ ID id,
+ AttributeDescription **adv
)
{
if (!glueBack || !glueBack->be_entry_reindex)
return -1;
- return glueBack->be_entry_reindex (glueBack, id);
+ return glueBack->be_entry_reindex (glueBack, id, adv);
}
static int
static int
glue_db_init(
- BackendDB *be
+ BackendDB *be,
+ ConfigReply *cr
)
{
slap_overinst *on = (slap_overinst *)be->bd_info;
BackendInfo *bi = oi->oi_orig;
glueinfo *gi;
+ if ( SLAP_GLUE_SUBORDINATE( be )) {
+ Debug( LDAP_DEBUG_ANY, "glue: backend %s is already subordinate, "
+ "cannot have glue overlay!\n",
+ be->be_suffix[0].bv_val, 0, 0 );
+ return LDAP_OTHER;
+ }
+
gi = ch_calloc( 1, sizeof(glueinfo));
on->on_bi.bi_private = gi;
dnParent( be->be_nsuffix, &gi->gi_pdn );
oi->oi_bi.bi_open = glue_open;
oi->oi_bi.bi_close = glue_close;
- oi->oi_bi.bi_entry_release_rw = glue_entry_release_rw;
-
/* Only advertise these if the root DB supports them */
if ( bi->bi_tool_entry_open )
oi->oi_bi.bi_tool_entry_open = glue_tool_entry_open;
oi->oi_bi.bi_tool_entry_next = glue_tool_entry_next;
if ( bi->bi_tool_entry_get )
oi->oi_bi.bi_tool_entry_get = glue_tool_entry_get;
+ if ( bi->bi_tool_dn2id_get )
+ oi->oi_bi.bi_tool_dn2id_get = glue_tool_dn2id_get;
if ( bi->bi_tool_entry_put )
oi->oi_bi.bi_tool_entry_put = glue_tool_entry_put;
if ( bi->bi_tool_entry_reindex )
oi->oi_bi.bi_tool_entry_reindex = glue_tool_entry_reindex;
+ if ( bi->bi_tool_entry_modify )
+ oi->oi_bi.bi_tool_entry_modify = glue_tool_entry_modify;
if ( bi->bi_tool_sync )
oi->oi_bi.bi_tool_sync = glue_tool_sync;
- /*FIXME : need to add support */
- oi->oi_bi.bi_tool_dn2id_get = 0;
- oi->oi_bi.bi_tool_id2entry_get = 0;
- oi->oi_bi.bi_tool_entry_modify = 0;
-
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_INSTANCE;
return 0;
static int
glue_db_destroy (
- BackendDB *be
+ BackendDB *be,
+ ConfigReply *cr
)
{
slap_overinst *on = (slap_overinst *)be->bd_info;
static int
glue_db_close(
- BackendDB *be
+ BackendDB *be,
+ ConfigReply *cr
)
{
slap_overinst *on = (slap_overinst *)be->bd_info;
/* If it's not already configured, set up the overlay */
if ( !SLAP_GLUE_INSTANCE( be )) {
- rc = overlay_config( be, glue.on_bi.bi_type );
+ rc = overlay_config( be, glue.on_bi.bi_type, -1, NULL, NULL);
if ( rc )
break;
}
glue_Addrec *ga;
int rc = 0;
+ if ( overlay_is_inst( be, "glue" )) {
+ Debug( LDAP_DEBUG_ANY, "glue: backend %s already has glue overlay, "
+ "cannot be a subordinate!\n",
+ be->be_suffix[0].bv_val, 0, 0 );
+ return LDAP_OTHER;
+ }
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_SUBORDINATE;
if ( advert )
SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_GLUE_ADVERTISE;
glue.on_bi.bi_op_modrdn = glue_op_func;
glue.on_bi.bi_op_add = glue_op_func;
glue.on_bi.bi_op_delete = glue_op_func;
+ glue.on_bi.bi_extended = glue_op_func;
glue.on_bi.bi_chk_referrals = glue_chk_referrals;
glue.on_bi.bi_chk_controls = glue_chk_controls;
+ glue.on_bi.bi_entry_get_rw = glue_entry_get_rw;
+ glue.on_bi.bi_entry_release_rw = glue_entry_release_rw;
+
+ glue.on_response = glue_response;
return overlay_register( &glue );
}