]> git.sur5r.net Git - openldap/commitdiff
Overlay for serializing modifications of a specific entry without
authorHoward Chu <hyc@openldap.org>
Fri, 19 Nov 2004 23:22:49 +0000 (23:22 +0000)
committerHoward Chu <hyc@openldap.org>
Fri, 19 Nov 2004 23:22:49 +0000 (23:22 +0000)
using backend-specific locks

servers/slapd/overlays/seqmod.c [new file with mode: 0644]

diff --git a/servers/slapd/overlays/seqmod.c b/servers/slapd/overlays/seqmod.c
new file mode 100644 (file)
index 0000000..fca2496
--- /dev/null
@@ -0,0 +1,202 @@
+/* seqmod.c - sequenced modifies */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2004 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Howard Chu for inclusion in
+ * OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#define        SLAPD_OVER_SEQMOD       SLAPD_MOD_STATIC
+
+#ifdef SLAPD_OVER_SEQMOD
+
+#include "slap.h"
+
+/* This overlay serializes concurrent attempts to modify a single entry */
+
+typedef struct modtarget {
+       struct modtarget *mt_next;
+       struct modtarget *mt_tail;
+       Operation *mt_op;
+} modtarget;
+
+typedef struct seqmod_info {
+       Avlnode         *sm_mods;       /* entries being modified */
+       ldap_pvt_thread_mutex_t sm_mutex;
+} seqmod_info;
+
+static int
+sm_avl_cmp( const void *c1, const void *c2 )
+{
+       const modtarget *m1, *m2;
+       int rc;
+
+       m1 = c1; m2 = c2;
+       rc = m1->mt_op->o_req_ndn.bv_len - m2->mt_op->o_req_ndn.bv_len;
+
+       if ( rc ) return rc;
+       return ber_bvcmp( &m1->mt_op->o_req_ndn, &m2->mt_op->o_req_ndn );
+}
+
+static int
+seqmod_op_cleanup( Operation *op, SlapReply *rs )
+{
+       seqmod_info *sm = op->o_callback->sc_private;
+       modtarget *mt;
+       Avlnode  *av;
+
+       /* This op is done, remove it */
+       ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
+       av = avl_find( sm->sm_mods, mt, sm_avl_cmp );
+       assert(av);
+
+       mt = av->avl_data;
+
+       /* If there are more, promote the next one */
+       if ( mt->mt_next ) {
+               av->avl_data = mt->mt_next;
+               mt->mt_next->mt_tail = mt->mt_tail;
+       } else {
+               avl_delete( &sm->sm_mods, mt, sm_avl_cmp );
+       }
+       ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
+       op->o_callback = op->o_callback->sc_next;
+       op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
+
+       return 0;
+}
+
+static int
+seqmod_op_mod( Operation *op, SlapReply *rs )
+{
+       slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
+       seqmod_info             *sm = on->on_bi.bi_private;
+       modtarget       *mt;
+       Avlnode *av;
+       slap_callback *cb;
+
+       cb = op->o_tmpcalloc( 1, sizeof(slap_callback) + sizeof(modtarget),
+               op->o_tmpmemctx );
+       mt = (modtarget *)(cb+1);
+       mt->mt_next = NULL;
+       mt->mt_tail = mt;
+       mt->mt_op = op;
+
+       /* See if we're already modifying this entry - don't allow
+        * near-simultaneous mods of the same entry
+        */
+       ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
+       av = avl_find( sm->sm_mods, mt, sm_avl_cmp );
+       if ( av ) {
+               modtarget *mtp = av->avl_data;
+               mtp->mt_tail->mt_next = mt;
+               mtp->mt_tail = mt;
+               /* Wait for this op to get to head of list */
+               while ( mtp != mt ) {
+                       ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
+                       ldap_pvt_thread_yield();
+                       /* Let it finish - should use a condition
+                        * variable here... */
+                       ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
+                       mtp = av->avl_data;
+               }
+       } else {
+               /* Record that we're modifying this now */
+               avl_insert( &sm->sm_mods, mt, sm_avl_cmp, avl_dup_error );
+       }
+       ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
+
+       cb->sc_cleanup = seqmod_op_cleanup;
+       cb->sc_private = sm;
+       cb->sc_next = op->o_callback;
+       op->o_callback = cb;
+
+       return SLAP_CB_CONTINUE;
+}
+
+static int
+seqmod_op_extended(
+       Operation *op,
+       SlapReply *rs
+)
+{
+       if ( exop_is_write( op )) return seqmod_op_mod( op, rs );
+       else return SLAP_CB_CONTINUE;
+}
+
+static int
+seqmod_db_open(
+       BackendDB *be
+)
+{
+       slap_overinst   *on = (slap_overinst *)be->bd_info;
+       seqmod_info     *sm;
+
+       sm = ch_calloc(1, sizeof(seqmod_info));
+       on->on_bi.bi_private = sm;
+
+       ldap_pvt_thread_mutex_init( &sm->sm_mutex );
+
+       return 0;
+}
+
+static int
+seqmod_db_close(
+       BackendDB *be
+)
+{
+       slap_overinst   *on = (slap_overinst *)be->bd_info;
+       seqmod_info     *sm = (seqmod_info *)on->on_bi.bi_private;
+
+       if ( sm ) {
+               ldap_pvt_thread_mutex_destroy( &sm->sm_mutex );
+
+               ch_free( sm );
+       }
+
+       return 0;
+}
+
+/* This overlay is set up for dynamic loading via moduleload. For static
+ * configuration, you'll need to arrange for the slap_overinst to be
+ * initialized and registered by some other function inside slapd.
+ */
+
+static slap_overinst           seqmod;
+
+int
+seqmod_init()
+{
+       seqmod.on_bi.bi_type = "seqmod";
+       seqmod.on_bi.bi_db_open = seqmod_db_open;
+       seqmod.on_bi.bi_db_close = seqmod_db_close;
+
+       seqmod.on_bi.bi_op_modify = seqmod_op_mod;
+       seqmod.on_bi.bi_op_modrdn = seqmod_op_mod;
+       seqmod.on_bi.bi_extended = seqmod_op_extended;
+
+       return overlay_register( &seqmod );
+}
+
+#if SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC
+int
+init_module( int argc, char *argv[] )
+{
+       return seqmod_init();
+}
+#endif /* SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC */
+
+#endif /* defined(SLAPD_OVER_SEQMOD) */