1 /* seqmod.c - sequenced modifies */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2004-2007 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
16 * This work was initially developed by Howard Chu for inclusion in
22 #ifdef SLAPD_OVER_SEQMOD
26 /* This overlay serializes concurrent attempts to modify a single entry */
28 typedef struct modtarget {
29 struct modtarget *mt_next;
30 struct modtarget *mt_tail;
34 typedef struct seqmod_info {
35 Avlnode *sm_mods; /* entries being modified */
36 ldap_pvt_thread_mutex_t sm_mutex;
40 sm_avl_cmp( const void *c1, const void *c2 )
42 const modtarget *m1, *m2;
46 rc = m1->mt_op->o_req_ndn.bv_len - m2->mt_op->o_req_ndn.bv_len;
49 return ber_bvcmp( &m1->mt_op->o_req_ndn, &m2->mt_op->o_req_ndn );
53 seqmod_op_cleanup( Operation *op, SlapReply *rs )
55 slap_callback *sc = op->o_callback;
56 seqmod_info *sm = sc->sc_private;
57 modtarget *mt, mtdummy;
61 /* This op is done, remove it */
62 ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
63 av = avl_find2( sm->sm_mods, &mtdummy, sm_avl_cmp );
68 /* If there are more, promote the next one */
70 av->avl_data = mt->mt_next;
71 mt->mt_next->mt_tail = mt->mt_tail;
73 avl_delete( &sm->sm_mods, mt, sm_avl_cmp );
75 ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
76 op->o_callback = sc->sc_next;
77 op->o_tmpfree( sc, op->o_tmpmemctx );
83 seqmod_op_mod( Operation *op, SlapReply *rs )
85 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
86 seqmod_info *sm = on->on_bi.bi_private;
91 cb = op->o_tmpcalloc( 1, sizeof(slap_callback) + sizeof(modtarget),
93 mt = (modtarget *)(cb+1);
98 /* See if we're already modifying this entry - don't allow
99 * near-simultaneous mods of the same entry
101 ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
102 av = avl_find2( sm->sm_mods, mt, sm_avl_cmp );
104 modtarget *mtp = av->avl_data;
105 mtp->mt_tail->mt_next = mt;
107 /* Wait for this op to get to head of list */
108 while ( mtp != mt ) {
109 ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
110 ldap_pvt_thread_yield();
111 /* Let it finish - should use a condition
112 * variable here... */
113 ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
117 /* Record that we're modifying this now */
118 avl_insert( &sm->sm_mods, mt, sm_avl_cmp, avl_dup_error );
120 ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
122 cb->sc_cleanup = seqmod_op_cleanup;
124 cb->sc_next = op->o_callback;
127 return SLAP_CB_CONTINUE;
136 if ( exop_is_write( op )) return seqmod_op_mod( op, rs );
137 else return SLAP_CB_CONTINUE;
145 slap_overinst *on = (slap_overinst *)be->bd_info;
148 sm = ch_calloc(1, sizeof(seqmod_info));
149 on->on_bi.bi_private = sm;
151 ldap_pvt_thread_mutex_init( &sm->sm_mutex );
161 slap_overinst *on = (slap_overinst *)be->bd_info;
162 seqmod_info *sm = (seqmod_info *)on->on_bi.bi_private;
165 ldap_pvt_thread_mutex_destroy( &sm->sm_mutex );
173 /* This overlay is set up for dynamic loading via moduleload. For static
174 * configuration, you'll need to arrange for the slap_overinst to be
175 * initialized and registered by some other function inside slapd.
178 static slap_overinst seqmod;
183 seqmod.on_bi.bi_type = "seqmod";
184 seqmod.on_bi.bi_db_open = seqmod_db_open;
185 seqmod.on_bi.bi_db_close = seqmod_db_close;
187 seqmod.on_bi.bi_op_modify = seqmod_op_mod;
188 seqmod.on_bi.bi_op_modrdn = seqmod_op_mod;
189 seqmod.on_bi.bi_extended = seqmod_op_extended;
191 return overlay_register( &seqmod );
194 #if SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC
196 init_module( int argc, char *argv[] )
198 return seqmod_initialize();
200 #endif /* SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC */
202 #endif /* defined(SLAPD_OVER_SEQMOD) */