Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / openldap / dist / servers / slapd / overlays / seqmod.c
blob0d22525e79e792ac2bc1cbff2666b3bbd237efd2
1 /* seqmod.c - sequenced modifies */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2004-2008 The OpenLDAP Foundation.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
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>.
15 /* ACKNOWLEDGEMENTS:
16 * This work was initially developed by Howard Chu for inclusion in
17 * OpenLDAP Software.
20 #include "portable.h"
22 #ifdef SLAPD_OVER_SEQMOD
24 #include "slap.h"
25 #include "config.h"
27 /* This overlay serializes concurrent attempts to modify a single entry */
29 typedef struct modtarget {
30 struct modtarget *mt_next;
31 struct modtarget *mt_tail;
32 Operation *mt_op;
33 } modtarget;
35 typedef struct seqmod_info {
36 Avlnode *sm_mods; /* entries being modified */
37 ldap_pvt_thread_mutex_t sm_mutex;
38 } seqmod_info;
40 static int
41 sm_avl_cmp( const void *c1, const void *c2 )
43 const modtarget *m1, *m2;
44 int rc;
46 m1 = c1; m2 = c2;
47 rc = m1->mt_op->o_req_ndn.bv_len - m2->mt_op->o_req_ndn.bv_len;
49 if ( rc ) return rc;
50 return ber_bvcmp( &m1->mt_op->o_req_ndn, &m2->mt_op->o_req_ndn );
53 static int
54 seqmod_op_cleanup( Operation *op, SlapReply *rs )
56 slap_callback *sc = op->o_callback;
57 seqmod_info *sm = sc->sc_private;
58 modtarget *mt, mtdummy;
59 Avlnode *av;
61 mtdummy.mt_op = op;
62 /* This op is done, remove it */
63 ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
64 av = avl_find2( sm->sm_mods, &mtdummy, sm_avl_cmp );
65 assert(av != NULL);
67 mt = av->avl_data;
69 /* If there are more, promote the next one */
70 if ( mt->mt_next ) {
71 av->avl_data = mt->mt_next;
72 mt->mt_next->mt_tail = mt->mt_tail;
73 } else {
74 avl_delete( &sm->sm_mods, mt, sm_avl_cmp );
76 ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
77 op->o_callback = sc->sc_next;
78 op->o_tmpfree( sc, op->o_tmpmemctx );
80 return 0;
83 static int
84 seqmod_op_mod( Operation *op, SlapReply *rs )
86 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
87 seqmod_info *sm = on->on_bi.bi_private;
88 modtarget *mt;
89 Avlnode *av;
90 slap_callback *cb;
92 cb = op->o_tmpcalloc( 1, sizeof(slap_callback) + sizeof(modtarget),
93 op->o_tmpmemctx );
94 mt = (modtarget *)(cb+1);
95 mt->mt_next = NULL;
96 mt->mt_tail = mt;
97 mt->mt_op = op;
99 /* See if we're already modifying this entry - don't allow
100 * near-simultaneous mods of the same entry
102 ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
103 av = avl_find2( sm->sm_mods, mt, sm_avl_cmp );
104 if ( av ) {
105 modtarget *mtp = av->avl_data;
106 mtp->mt_tail->mt_next = mt;
107 mtp->mt_tail = mt;
108 /* Wait for this op to get to head of list */
109 while ( mtp != mt ) {
110 ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
111 ldap_pvt_thread_yield();
112 /* Let it finish - should use a condition
113 * variable here... */
114 ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
115 mtp = av->avl_data;
117 } else {
118 /* Record that we're modifying this now */
119 avl_insert( &sm->sm_mods, mt, sm_avl_cmp, avl_dup_error );
121 ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
123 cb->sc_cleanup = seqmod_op_cleanup;
124 cb->sc_private = sm;
125 cb->sc_next = op->o_callback;
126 op->o_callback = cb;
128 return SLAP_CB_CONTINUE;
131 static int
132 seqmod_op_extended(
133 Operation *op,
134 SlapReply *rs
137 if ( exop_is_write( op )) return seqmod_op_mod( op, rs );
138 else return SLAP_CB_CONTINUE;
141 static int
142 seqmod_db_open(
143 BackendDB *be,
144 ConfigReply *cr
147 slap_overinst *on = (slap_overinst *)be->bd_info;
148 seqmod_info *sm;
150 sm = ch_calloc(1, sizeof(seqmod_info));
151 on->on_bi.bi_private = sm;
153 ldap_pvt_thread_mutex_init( &sm->sm_mutex );
155 return 0;
158 static int
159 seqmod_db_close(
160 BackendDB *be,
161 ConfigReply *cr
164 slap_overinst *on = (slap_overinst *)be->bd_info;
165 seqmod_info *sm = (seqmod_info *)on->on_bi.bi_private;
167 if ( sm ) {
168 ldap_pvt_thread_mutex_destroy( &sm->sm_mutex );
170 ch_free( sm );
173 return 0;
176 /* This overlay is set up for dynamic loading via moduleload. For static
177 * configuration, you'll need to arrange for the slap_overinst to be
178 * initialized and registered by some other function inside slapd.
181 static slap_overinst seqmod;
184 seqmod_initialize()
186 seqmod.on_bi.bi_type = "seqmod";
187 seqmod.on_bi.bi_db_open = seqmod_db_open;
188 seqmod.on_bi.bi_db_close = seqmod_db_close;
190 seqmod.on_bi.bi_op_modify = seqmod_op_mod;
191 seqmod.on_bi.bi_op_modrdn = seqmod_op_mod;
192 seqmod.on_bi.bi_extended = seqmod_op_extended;
194 return overlay_register( &seqmod );
197 #if SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC
199 init_module( int argc, char *argv[] )
201 return seqmod_initialize();
203 #endif /* SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC */
205 #endif /* defined(SLAPD_OVER_SEQMOD) */