Back to index

openldap  2.4.31
seqmod.c
Go to the documentation of this file.
00001 /* seqmod.c - sequenced modifies */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 2004-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* ACKNOWLEDGEMENTS:
00016  * This work was initially developed by Howard Chu for inclusion in
00017  * OpenLDAP Software.
00018  */
00019 
00020 #include "portable.h"
00021 
00022 #ifdef SLAPD_OVER_SEQMOD
00023 
00024 #include "slap.h"
00025 #include "config.h"
00026 
00027 /* This overlay serializes concurrent attempts to modify a single entry */
00028 
00029 typedef struct modtarget {
00030        struct modtarget *mt_next;
00031        struct modtarget *mt_tail;
00032        Operation *mt_op;
00033 } modtarget;
00034 
00035 typedef struct seqmod_info {
00036        Avlnode              *sm_mods;     /* entries being modified */
00037        ldap_pvt_thread_mutex_t     sm_mutex;
00038 } seqmod_info;
00039 
00040 static int
00041 sm_avl_cmp( const void *c1, const void *c2 )
00042 {
00043        const modtarget *m1, *m2;
00044        int rc;
00045 
00046        m1 = c1; m2 = c2;
00047        rc = m1->mt_op->o_req_ndn.bv_len - m2->mt_op->o_req_ndn.bv_len;
00048 
00049        if ( rc ) return rc;
00050        return ber_bvcmp( &m1->mt_op->o_req_ndn, &m2->mt_op->o_req_ndn );
00051 }
00052 
00053 static int
00054 seqmod_op_cleanup( Operation *op, SlapReply *rs )
00055 {
00056        slap_callback *sc = op->o_callback;
00057        seqmod_info *sm = sc->sc_private;
00058        modtarget *mt, mtdummy;
00059        Avlnode        *av;
00060 
00061        mtdummy.mt_op = op;
00062        /* This op is done, remove it */
00063        ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
00064        av = avl_find2( sm->sm_mods, &mtdummy, sm_avl_cmp );
00065        assert(av != NULL);
00066 
00067        mt = av->avl_data;
00068 
00069        /* If there are more, promote the next one */
00070        if ( mt->mt_next ) {
00071               av->avl_data = mt->mt_next;
00072               mt->mt_next->mt_tail = mt->mt_tail;
00073        } else {
00074               avl_delete( &sm->sm_mods, mt, sm_avl_cmp );
00075        }
00076        ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
00077        op->o_callback = sc->sc_next;
00078        op->o_tmpfree( sc, op->o_tmpmemctx );
00079 
00080        return 0;
00081 }
00082 
00083 static int
00084 seqmod_op_mod( Operation *op, SlapReply *rs )
00085 {
00086        slap_overinst        *on = (slap_overinst *)op->o_bd->bd_info;
00087        seqmod_info          *sm = on->on_bi.bi_private;
00088        modtarget     *mt;
00089        Avlnode       *av;
00090        slap_callback *cb;
00091 
00092        cb = op->o_tmpcalloc( 1, sizeof(slap_callback) + sizeof(modtarget),
00093               op->o_tmpmemctx );
00094        mt = (modtarget *)(cb+1);
00095        mt->mt_next = NULL;
00096        mt->mt_tail = mt;
00097        mt->mt_op = op;
00098 
00099        /* See if we're already modifying this entry - don't allow
00100         * near-simultaneous mods of the same entry
00101         */
00102        ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
00103        av = avl_find2( sm->sm_mods, mt, sm_avl_cmp );
00104        if ( av ) {
00105               modtarget *mtp = av->avl_data;
00106               mtp->mt_tail->mt_next = mt;
00107               mtp->mt_tail = mt;
00108               /* Wait for this op to get to head of list */
00109               while ( mtp != mt ) {
00110                      ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
00111                      ldap_pvt_thread_yield();
00112                      /* Let it finish - should use a condition
00113                       * variable here... */
00114                      ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
00115                      mtp = av->avl_data;
00116               }
00117        } else {
00118               /* Record that we're modifying this now */
00119               avl_insert( &sm->sm_mods, mt, sm_avl_cmp, avl_dup_error );
00120        }
00121        ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
00122 
00123        cb->sc_cleanup = seqmod_op_cleanup;
00124        cb->sc_private = sm;
00125        cb->sc_next = op->o_callback;
00126        op->o_callback = cb;
00127 
00128        return SLAP_CB_CONTINUE;
00129 }
00130 
00131 static int
00132 seqmod_op_extended(
00133        Operation *op,
00134        SlapReply *rs
00135 )
00136 {
00137        if ( exop_is_write( op )) return seqmod_op_mod( op, rs );
00138        else return SLAP_CB_CONTINUE;
00139 }
00140 
00141 static int
00142 seqmod_db_open(
00143        BackendDB *be,
00144        ConfigReply *cr
00145 )
00146 {
00147        slap_overinst *on = (slap_overinst *)be->bd_info;
00148        seqmod_info   *sm;
00149 
00150        sm = ch_calloc(1, sizeof(seqmod_info));
00151        on->on_bi.bi_private = sm;
00152 
00153        ldap_pvt_thread_mutex_init( &sm->sm_mutex );
00154 
00155        return 0;
00156 }
00157 
00158 static int
00159 seqmod_db_close(
00160        BackendDB *be,
00161        ConfigReply *cr
00162 )
00163 {
00164        slap_overinst *on = (slap_overinst *)be->bd_info;
00165        seqmod_info   *sm = (seqmod_info *)on->on_bi.bi_private;
00166 
00167        if ( sm ) {
00168               ldap_pvt_thread_mutex_destroy( &sm->sm_mutex );
00169 
00170               ch_free( sm );
00171        }
00172 
00173        return 0;
00174 }
00175 
00176 /* This overlay is set up for dynamic loading via moduleload. For static
00177  * configuration, you'll need to arrange for the slap_overinst to be
00178  * initialized and registered by some other function inside slapd.
00179  */
00180 
00181 static slap_overinst               seqmod;
00182 
00183 int
00184 seqmod_initialize()
00185 {
00186        seqmod.on_bi.bi_type = "seqmod";
00187        seqmod.on_bi.bi_db_open = seqmod_db_open;
00188        seqmod.on_bi.bi_db_close = seqmod_db_close;
00189 
00190        seqmod.on_bi.bi_op_modify = seqmod_op_mod;
00191        seqmod.on_bi.bi_op_modrdn = seqmod_op_mod;
00192        seqmod.on_bi.bi_extended = seqmod_op_extended;
00193 
00194        return overlay_register( &seqmod );
00195 }
00196 
00197 #if SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC
00198 int
00199 init_module( int argc, char *argv[] )
00200 {
00201        return seqmod_initialize();
00202 }
00203 #endif /* SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC */
00204 
00205 #endif /* defined(SLAPD_OVER_SEQMOD) */