[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: slapd new backend

Malcolm Cowen writes:
> I've got the API documentation, and the setup type documentation from
> the website.  None of that covers the backends much however, so I'm
> currently going through the various call hooks provided by the system
> using debug to see what is going on.

slap.h contains quite a bit of comments about the API.

Here are some more notes in C-like format I've written while trying to
figure the API out.  Note that I haven't checked yet that I've gotten it
straight.  See also ITS#5328.

struct BackendInfo {

     * be->be_<operation> aka bi->bi_op_<operation>:
     * Handle one LDAP operation, except what auxiliary function below handle.
     * Set the SlapReply, in some cases send it too.
     * Return an LDAP result code.
     * ? [What is the relation between sent and returned result code?] ?
     * bind
     *  If returning LDAP_SUCCESS, do not send it first - the frontend will.
     *  Do send non-success responses before returning.
     * unbind, abandon:
     *  These LDAP operations have no response, so don't send one.
     * search, modify, modrdn, add, delete:
     *  Send response.
     * compare:
     *  Send response, but return LDAP_SUCCESS after sending
     * bi_extended (be->be_extended), bi_op_cancel (be->be_cancel):
     *  Do not send response, just set up the SlapReply.
     * Operations that can be abandoned may return SLAPD_ABANDON if
     * op->o_abandon is set.  It is OK to "send" SLAPD_ABANDON with
     * send_ldap_response(); that function will catch it.
    typedef int BI_op_func( Operation *op, SlapReply *rs );
    BI_op_func  *bi_op_bind;
    BI_op_func  *bi_op_unbind;
    BI_op_func  *bi_op_search;
    BI_op_func  *bi_op_compare;
    BI_op_func  *bi_op_modify;
    BI_op_func  *bi_op_modrdn;
    BI_op_func  *bi_op_add;
    BI_op_func  *bi_op_delete;
    BI_op_func  *bi_op_abandon;
    /* Extended Operations Helper */
    BI_op_func  *bi_extended;
    BI_op_func  *bi_op_cancel;

    /* Auxilary Functions */

     * Insert backend-specific operational attributes in
     * rs->sr_operational_attrs.  The frontend handles entryDN and
     * subschemaSubentry, unless REP_NO_ENTRYDN and REP_NO_SUBSCHEMA are
     * set.  Called from backend_operational().
    BI_op_func          *bi_operational;    /* be->be_operational() */

     * Called before LDAP operation handlers.
     * May send and return a referral if the operation should do so.
     * The existence of this function makes LDAP operations non-atomic.
     * It should send and return LDAP_REFERRAL, or return but NOT send
     * another result code.  With LDAP_SUCCESS, slapd will proceed to
     * the operation handler.  With other result codes, slapd will put
     * them in rs->sr_err and send the error.
     * Called from backend_check_referrals().
    BI_op_func          *bi_chk_referrals;  /* be->be_chk_referrals() */

     * bi->bi_chk_controls() aka be->be_chk_controls():
     * May react to controls in op->o_ctrlflag from the LDAP operation,
     * before slapd checks bi->bi_controls and globally handled controls.
     * Called before LDAP operation handlers.
     * Do not send results.
     * Return SLAP_CB_CONTINUE for slapd to check other supported controls.
     * Return LDAP_SUCCESS to proceed to the operation without checking
     * other controls.  Otherwise return an error code which slapd will
     * send to fail the operation.
     * Called from backend_check_restrictions().
     * See overlays/pcache.c for an example.
     * Presumably it returns LDAP_SUCCESS, it must first do the work
     * normally done by backend_check_controls().
    BI_op_func          *bi_chk_controls;   /* be->be_chk_controls() */

     * bi->bi_entry_get_rw() aka be->be_fetch():
     * Fetch an entry for operation 'op' with normalized DN 'ndn', for
     * read operations if 'rw' == 0, for write operations if 'rw' == 1.
     * If 'oc' and/or 'at' are non-NULL but the entry does not contain
     * them, the function may fail with LDAP_NO_SUCH_ATTRIBUTE.
     * Return an LDAP result code.  *e is NULL on entry, and must be
     * non-NULL on exit if and only if LDAP_SUCCESS is returned.  I think.
     * Slapd returns the entry to the backend with bi_entry_release_rw()
     * if that is set, otherwise hopefully frees it with entry_free().
     * ? [See below.]
     * Called from be_entry_get_rw().
     * ? [What can the caller and the backend do with the entry before
     *    it is released?  Can it be modified?  No current callers
     *    use rw!=0, can it be modified in that case? ]
     * ? [Callers of entry_release seem to choose rw based on which
     *    LDAP operation is being used, which maybe means that
     *    be_fetch() callers should do the same - i.e. set rw for
     *    the Add operation even for entries which the caller will
     *    only read.  Need to check.  Except, do any callers use
     *    * rw != 0 anyway? ]
    int (*bi_entry_get_rw)(
        Operation *op, struct berval *ndn,
        ObjectClass *oc, AttributeDescription *at, int rw, Entry **e );

     * bi->bi_entry_release_rw() aka be->be_release():
     * Returns an entry to the backend, possibly fetched with be_fetch.
     * Slapd will also call it with entries that did not originate
     * with the backend, I do not know if that is intentional.
     * ? [After some overlay did entry_dup(), maybe.  Must check.]
     * Called from be_entry_release_rw(), which frees the entry with
     * entry_free() if there is no be_entry_release_rw function.
     * ? [However frontendDB->be_release() also calls this function,
     *    but does not free the entry if no function is found.  Then
     *    it just returns LDAP_NO_SUCH_OBJECT.]
     * Return an LDAP result code, which is hardly ever used.
     * Only SLAP_CB_CONTINUE seems to matter: If there are overlays,
     * this means other bi_entry_release_rw() functions are called,
     * or entry_free() if all else fails.
     * ? [Maybe back-relay has a memory leak and should call entry_free
     *    if there is no backend function.  frontendDB does not, overlay
     *    translucent does, backglue does but has a FIXME comment about
     *    it.  Fix what?]
    int (*bi_entry_release_rw)( Operation *op, Entry *e, int rw );

     * bi->bi_has_subordinates() aka be->be_has_subordinates():
     * Generate the value for compare(entry, "hasSubordinates=TRUE").
     * Returns an LDAP result code.  When it returns LDAP_SUCCESS, it
     * must set *hasSubs to LDAP_COMPARE_TRUE or LDAP_COMPARE_FALSE.
     * This function really should succeed except on internal errors:
     * test_filter() with the presence filter (hasSubordinates=*) does
     * not call this function, it assumes attribute hasSubordinates will
     * exist if this function does.  And for equality match it turns
     * other result codes than LDAP_SUCCESS into LDAP_OTHER.  (Though it
     * can also be used for the Compare operation, in that case a result
     * code of LDAP_NO_SUCH_ATTRIBUTE also makes sense.)
     * back-relay sets this function, which is wrong when relaying to a
     * backend which does not.  OTOH slapi_entry_has_children() exists
     * even though slapi does not set bi_has_subordinates.
     * bi->bi_entry_get_rw must exist if this function does; Compare
     * will call it if !defined(SLAP_COMPARE_IN_FRONTEND).
    int (*bi_has_subordinates)( Operation *op, Entry *e, int *hasSubs );


     * Connection management, called when a connection is opened or closed.
     * Return an LDAP result code.
     * Overlays must normally return SLAP_CB_CONTINUE, so the backend
     * also gets a chance to prepare for and clean up after connections.
     * Slapd discards other result codes, which is just as well since the
     * overlay code turns SLAP_CB_CONTINUE into LDAP_UNWILLING_TO_PERFORM
     * when the backend has no connection handler.
     * Slapi can set up a fake connection and call backend_connection_init,
     * but I see no matching call to backend_connection_destroy.  Maybe
     * the connection is given to slapd which destroys it?
    typedef int BI_conn_func( BackendDB *bd, Connection *c );
    BI_conn_func    *bi_connection_init;    /* be->be_connection_init */
    BI_conn_func    *bi_connection_destroy; /* be->be_connection_destroy */

    /* Hooks for slap tools: bi->bi_tool_<act> aka be->be_<act> */
    int (*bi_tool_entry_open)( BackendDB *be, int mode );
    int (*bi_tool_entry_close)( BackendDB *be );