]> git.sur5r.net Git - openldap/blob - servers/slapd/back-asyncmeta/message_queue.c
b00a91c098b6301be0da91bd0abc1c1b07a1bc8a
[openldap] / servers / slapd / back-asyncmeta / message_queue.c
1 /* message_queue.c - routines to maintain the per-connection lists
2  * of pending operations */
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 2016 The OpenLDAP Foundation.
7  * Portions Copyright 2016 Symas Corporation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18
19 /* ACKNOWLEDGEMENTS:
20  * This work was developed by Symas Corporation
21  * based on back-meta module for inclusion in OpenLDAP Software.
22  * This work was sponsored by Ericsson. */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27
28 #include <ac/socket.h>
29 #include <ac/string.h>
30 #include <ac/time.h>
31
32 #include "lutil.h"
33 #include "slap.h"
34 #include "../back-ldap/back-ldap.h"
35 #include "back-asyncmeta.h"
36 #include "../../../libraries/liblber/lber-int.h"
37 #include "lutil.h"
38
39
40 LDAPControl **asyncmeta_copy_controls(Operation *op)
41 {
42         LDAPControl **new_controls = NULL;
43         LDAPControl **c;
44         LDAPControl  *tmp_ctl = NULL;
45         int i, length = 1;
46
47
48         if (op->o_ctrls == NULL) {
49                 return NULL;
50         }
51         for (c = op->o_ctrls; *c != NULL; c++) {
52                 length++;
53         }
54
55         new_controls = op->o_tmpalloc( sizeof(LDAPControl*)*length, op->o_tmpmemctx );
56         for (i = 0; i < length-1; i ++) {
57                 new_controls[i] = op->o_tmpalloc( sizeof(LDAPControl), op->o_tmpmemctx );
58                 if (op->o_ctrls[i]->ldctl_value.bv_len > 0) {
59                         ber_dupbv_x( &new_controls[i]->ldctl_value, &op->o_ctrls[i]->ldctl_value, op->o_tmpmemctx);
60                 }
61                 if (op->o_ctrls[i]->ldctl_oid) {
62                         new_controls[i]->ldctl_oid = ber_strdup_x(op->o_ctrls[i]->ldctl_oid, op->o_tmpmemctx);
63                 }
64                 new_controls[i]->ldctl_iscritical = op->o_ctrls[i]->ldctl_iscritical;
65         }
66         new_controls[length-1] = NULL;
67         return new_controls;
68 }
69
70 static
71 void asyncmeta_free_op_controls(Operation *op)
72 {
73         LDAPControl **c;
74         for (c = op->o_ctrls; *c != NULL; c++) {
75                 if ((*c)->ldctl_value.bv_len > 0) {
76                         free((*c)->ldctl_value.bv_val);
77                 }
78                 if ((*c)->ldctl_oid) {
79                         free((*c)->ldctl_oid);
80                 }
81                 free(*c);
82         }
83         free(op->o_ctrls);
84 }
85
86
87 static
88 Modifications* asyncmeta_copy_modlist(Operation *op, Modifications *modlist)
89 {
90         Modifications *ml;
91         Modifications *new_mods = NULL;
92         for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
93                 Modifications *mod = op->o_tmpalloc( sizeof( Modifications ), op->o_tmpmemctx );
94                 *mod = *ml;
95                 if ( ml->sml_values ) {
96                                 ber_bvarray_dup_x( &mod->sml_values, ml->sml_values, op->o_tmpmemctx );
97                                 if ( ml->sml_nvalues ) {
98                                         ber_bvarray_dup_x( &mod->sml_nvalues, ml->sml_nvalues, op->o_tmpmemctx );
99                                 }
100                         }
101                 mod->sml_next = NULL;
102                 if (new_mods == NULL) {
103                         new_mods = mod;
104                 } else {
105                         new_mods->sml_next = mod;
106                 }
107         }
108         return new_mods;
109 }
110
111 Operation *asyncmeta_copy_op(Operation *op)
112 {
113         const char      *text;
114         int rc;
115         char txtbuf[SLAP_TEXT_BUFLEN];
116         size_t textlen = sizeof txtbuf;
117         Entry *e;
118         Operation *new_op = op->o_tmpcalloc( 1, sizeof(OperationBuffer), op->o_tmpmemctx );
119         *new_op = *op;
120         new_op->o_hdr = &((OperationBuffer *) new_op)->ob_hdr;
121         *(new_op->o_hdr) = *(op->o_hdr);
122         new_op->o_controls = ((OperationBuffer *) new_op)->ob_controls;
123         new_op->o_callback = op->o_callback;
124         new_op->o_ber = NULL;
125         new_op->o_bd = op->o_bd->bd_self;
126
127         ber_dupbv_x( &new_op->o_req_dn, &op->o_req_dn, op->o_tmpmemctx );
128         ber_dupbv_x( &new_op->o_req_ndn, &op->o_req_ndn, op->o_tmpmemctx );
129         op->o_callback = NULL;
130
131         if (op->o_ndn.bv_len > 0) {
132                 ber_dupbv_x( &new_op->o_ndn, &op->o_ndn, op->o_tmpmemctx );
133         }
134         if (op->o_dn.bv_len > 0) {
135                 ber_dupbv_x( &new_op->o_dn, &op->o_dn, op->o_tmpmemctx );
136         }
137
138         new_op->o_ctrls = asyncmeta_copy_controls(op);
139         switch (op->o_tag) {
140         case LDAP_REQ_SEARCH:
141         {
142                 AttributeName *at_names;
143                 int i;
144                 for (i=0; op->ors_attrs && !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++);
145                 if (i > 0) {
146                         at_names = op->o_tmpcalloc( i+1, sizeof( AttributeName ), op->o_tmpmemctx );
147                         at_names[i].an_name.bv_len = 0;
148                         i--;
149                         for (i; i >= 0; i--) {
150                                 at_names[i] = op->ors_attrs[i];
151                                 ber_dupbv_x( &at_names[i].an_name, &op->ors_attrs[i].an_name, op->o_tmpmemctx );
152                         }
153                 } else {
154                         at_names = NULL;
155                 }
156                 ber_dupbv_x( &new_op->ors_filterstr, &op->ors_filterstr, op->o_tmpmemctx );
157                 new_op->ors_filter = filter_dup( op->ors_filter, op->o_tmpmemctx );
158                 new_op->ors_attrs = at_names;
159         }
160         break;
161         case LDAP_REQ_ADD:
162         {
163                 slap_entry2mods(op->ora_e, &new_op->ora_modlist, &text, txtbuf, textlen);
164                 e = entry_alloc();
165                 new_op->ora_e = e;
166                 ber_dupbv_x( &e->e_name, &op->o_req_dn, op->o_tmpmemctx );
167                 ber_dupbv_x( &e->e_nname, &op->o_req_ndn, op->o_tmpmemctx );
168                 rc = slap_mods2entry( new_op->ora_modlist, &new_op->ora_e, 1, 0, &text, txtbuf, textlen);
169         }
170         break;
171         case LDAP_REQ_MODIFY:
172         {
173                 new_op->orm_modlist = asyncmeta_copy_modlist(op, op->orm_modlist);
174         }
175         break;
176         case LDAP_REQ_COMPARE:
177                 new_op->orc_ava = (AttributeAssertion *)ch_calloc( 1, sizeof( AttributeAssertion ));
178                 *new_op->orc_ava = *op->orc_ava;
179                 if ( !BER_BVISNULL( &op->orc_ava->aa_value ) ) {
180                         ber_dupbv_x( &new_op->orc_ava->aa_value,  &op->orc_ava->aa_value, op->o_tmpmemctx);
181                 }
182                 break;
183         case LDAP_REQ_MODRDN:
184
185                 if (op->orr_newrdn.bv_len > 0) {
186                         ber_dupbv_x( &new_op->orr_newrdn, &op->orr_newrdn, op->o_tmpmemctx );
187                 }
188                 if (op->orr_nnewrdn.bv_len > 0) {
189                         ber_dupbv_x( &new_op->orr_nnewrdn, &op->orr_nnewrdn, op->o_tmpmemctx );
190                 }
191                 if (op->orr_newSup != NULL) {
192                         new_op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
193                         new_op->orr_newSup->bv_len = 0;
194                         if (op->orr_newSup->bv_len > 0) {
195                                 ber_dupbv_x( new_op->orr_newSup, op->orr_newSup, op->o_tmpmemctx );
196                         }
197                 }
198
199                 if (op->orr_nnewSup != NULL) {
200                         new_op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ), op->o_tmpmemctx );
201                         new_op->orr_nnewSup->bv_len = 0;
202                         if (op->orr_nnewSup->bv_len > 0) {
203                                 ber_dupbv_x( new_op->orr_nnewSup, op->orr_nnewSup, op->o_tmpmemctx );
204                         }
205                 }
206                 new_op->orr_modlist = asyncmeta_copy_modlist(op, op->orr_modlist);
207                 break;
208         case LDAP_REQ_DELETE:
209         default:
210                 break;
211         }
212         return new_op;
213 }
214
215
216 typedef struct listptr {
217         void *reserved;
218         struct listptr *next;
219 } listptr;
220
221 typedef struct listhead {
222         struct listptr *list;
223         int cnt;
224 } listhead;
225
226 static void *asyncmeta_memctx_destroy(void *key, void *data)
227 {
228         listhead *lh = data;
229         listptr *lp;
230         while (lp = lh->list) {
231                 lh->list = lp->next;
232                 slap_sl_mem_destroy((void *)1, lp);
233         }
234         ch_free(lh);
235 }
236
237 #ifndef LH_MAX
238 #define LH_MAX  16
239 #endif
240
241 static void *asyncmeta_memctx_get(void *threadctx)
242 {
243         listhead *lh = NULL;
244         listptr *lp = NULL;
245         ldap_pvt_thread_pool_getkey(threadctx, asyncmeta_memctx_get, &lh, NULL);
246         if (!lh) {
247                 lh = ch_malloc(sizeof(listhead));
248                 lh->cnt = 0;
249                 lh->list = NULL;
250                 ldap_pvt_thread_pool_setkey(threadctx, asyncmeta_memctx_get, lh, asyncmeta_memctx_destroy, NULL, NULL);
251         }
252         if (lh->list) {
253                 lp = lh->list;
254                 lh->list = lp->next;
255                 lh->cnt--;
256                 slap_sl_mem_setctx(threadctx, lp);
257         }
258         return slap_sl_mem_create(SLAP_SLAB_SIZE, SLAP_SLAB_STACK, threadctx, 1);
259 }
260
261 static void asyncmeta_memctx_put(void *threadctx, void *memctx)
262 {
263         listhead *lh = NULL;
264         ldap_pvt_thread_pool_getkey(threadctx, asyncmeta_memctx_get, &lh, NULL);
265         if (!lh) {
266                 lh = ch_malloc(sizeof(listhead));
267                 lh->cnt = 0;
268                 lh->list = NULL;
269                 ldap_pvt_thread_pool_setkey(threadctx, asyncmeta_memctx_get, lh, asyncmeta_memctx_destroy, NULL, NULL);
270         }
271         if (lh->cnt < LH_MAX) {
272                 listptr *lp = memctx;
273                 lp->next = lh->list;
274                 lh->list = lp;
275                 lh->cnt++;
276         } else {
277                 slap_sl_mem_destroy((void *)1, memctx);
278         }
279 }
280
281 int asyncmeta_new_bm_context(Operation *op, SlapReply *rs, bm_context_t **new_bc, int ntargets)
282 {
283         void *oldctx = op->o_tmpmemctx;
284
285         /* prevent old memctx from being destroyed */
286         slap_sl_mem_setctx(op->o_threadctx, NULL);
287         /* create new memctx */
288         op->o_tmpmemctx = asyncmeta_memctx_get( op->o_threadctx );
289         *new_bc = op->o_tmpcalloc( 1, sizeof( bm_context_t ), op->o_tmpmemctx );
290
291         (*new_bc)->op = asyncmeta_copy_op(op);
292         (*new_bc)->candidates = op->o_tmpcalloc(ntargets, sizeof(SlapReply),op->o_tmpmemctx);
293         /* restore original memctx */
294         slap_sl_mem_setctx(op->o_threadctx, oldctx);
295         op->o_tmpmemctx = oldctx;
296         return LDAP_SUCCESS;
297 }
298
299 void asyncmeta_free_op(Operation *op)
300 {
301         assert (op != NULL);
302         switch (op->o_tag) {
303         case LDAP_REQ_SEARCH:
304                 if (op->ors_filterstr.bv_len != 0) {
305                         free(op->ors_filterstr.bv_val);
306                 }
307                 if (op->ors_filter) {
308                         filter_free(op->ors_filter);
309                 }
310                 if (op->ors_attrs) {
311                         free(op->ors_attrs);
312                 }
313                 break;
314         case LDAP_REQ_ADD:
315                 if ( op->ora_modlist != NULL ) {
316                         slap_mods_free(op->ora_modlist, 0 );
317                 }
318
319                 if ( op->ora_e != NULL ) {
320                         entry_free( op->ora_e );
321                 }
322
323                 break;
324         case LDAP_REQ_MODIFY:
325                 if ( op->orm_modlist != NULL ) {
326                         slap_mods_free(op->orm_modlist, 1 );
327                 }
328                 break;
329         case LDAP_REQ_MODRDN:
330                 if (op->orr_newrdn.bv_len > 0) {
331                         free(op->orr_newrdn.bv_val);
332                 }
333                 if (op->orr_nnewrdn.bv_len > 0) {
334                         free(op->orr_nnewrdn.bv_val);
335                 }
336
337                 if (op->orr_nnewSup != NULL ) {
338                         if (op->orr_nnewSup->bv_len > 0) {
339                                 free(op->orr_nnewSup->bv_val);
340                         }
341                         free (op->orr_nnewSup);
342                 }
343
344                 if (op->orr_newSup != NULL ) {
345                         if (op->orr_newSup->bv_len > 0) {
346                                 free(op->orr_newSup->bv_val);
347                         }
348                         free (op->orr_newSup);
349                 }
350
351                 if ( op->orr_modlist != NULL ) {
352                         slap_mods_free(op->orr_modlist, 1 );
353                 }
354                 break;
355         case LDAP_REQ_COMPARE:
356                 if ( !BER_BVISNULL( &op->orc_ava->aa_value ) ) {
357                         free(op->orc_ava->aa_value.bv_val);
358                 }
359                 free(op->orc_ava);
360                 break;
361         case LDAP_REQ_DELETE:
362                 break;
363         default:
364                 Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_free_op : other message type",
365                0, 0, 0 );
366         }
367
368         if (op->o_ctrls != NULL) {
369                 asyncmeta_free_op_controls(op);
370         }
371         if (op->o_ndn.bv_len > 0) {
372                 free(op->o_ndn.bv_val);
373         }
374         if (op->o_dn.bv_len > 0) {
375                 free( op->o_dn.bv_val );
376         }
377         if (op->o_req_dn.bv_len > 0) {
378                 free(op->o_req_dn.bv_val);
379         }
380         if (op->o_req_dn.bv_len > 0) {
381                 free(op->o_req_ndn.bv_val);
382         }
383         free(op);
384 }
385
386
387
388
389 void asyncmeta_clear_bm_context(bm_context_t *bc)
390 {
391
392         Operation *op = bc->op;
393 #if 0
394         bm_candidates_t  *cl;
395         a_metainfo_t    *mi;
396         int i = 0;
397         if (bmc == NULL) {
398                 return;
399         } else if (bmc->cl == NULL) {
400                 free(bmc);
401                 return;
402         }
403         cl = bmc->cl;
404         op = cl->op;
405         switch (op->o_tag) {
406         case LDAP_REQ_SEARCH:
407                 break;
408         case LDAP_REQ_ADD:
409                 if ( (bmc->mdn.bv_len != 0) &&
410                      (bmc->mdn.bv_val != op->o_req_dn.bv_val) ) {
411                         free( bmc->mdn.bv_val );
412                 }
413
414                 if (bmc->data.add_d.attrs != NULL )  {
415                         while (bmc->data.add_d.attrs[i] != NULL) {
416                                 free( bmc->data.add_d.attrs[i]->mod_bvalues );
417                                 free( bmc->data.add_d.attrs[i] );
418                                 i++;
419                         }
420                         free( bmc->data.add_d.attrs );
421                         }
422                 break;
423         case LDAP_REQ_MODIFY:
424                 if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
425                         free( bmc->mdn.bv_val );
426                 }
427                 if ( bmc->data.mod_d.modv != NULL ) {
428                         for ( i = 0; bmc->data.mod_d.modv[ i ]; i++ ) {
429                                 free( bmc->data.mod_d.modv[ i ]->mod_bvalues );
430                         }
431                 }
432                 free( bmc->data.mod_d.mods );
433                 free( bmc->data.mod_d.modv );
434
435                 break;
436         case LDAP_REQ_MODRDN:
437                 if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
438                         free( bmc->mdn.bv_val );
439                 }
440
441                 if ( bmc->data.modrdn_d.newSuperior.bv_len != 0 &&
442                      bmc->data.modrdn_d.newSuperior.bv_val != op->orr_newSup->bv_val )
443                 {
444                         free( bmc->data.modrdn_d.newSuperior.bv_val );
445
446                 }
447
448                 if ( bmc->data.modrdn_d.newrdn.bv_len != 0 &&
449                      bmc->data.modrdn_d.newrdn.bv_val != op->orr_newrdn.bv_val )
450                 {
451                         free( bmc->data.modrdn_d.newrdn.bv_val );
452
453                 }
454                 break;
455         case LDAP_REQ_COMPARE:
456                 if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
457                         free( bmc->mdn.bv_val );
458                 }
459                 if ( op->orc_ava->aa_value.bv_val != bmc->data.comp_d.mapped_value.bv_val ) {
460                         free( bmc->data.comp_d.mapped_value.bv_val );
461                         }
462                 break;
463         case LDAP_REQ_DELETE:
464                 if ( bmc->mdn.bv_val != op->o_req_dn.bv_val ) {
465                         free( bmc->mdn.bv_val );
466                 }
467                 break;
468         default:
469                 Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_clear_bm_context: other message type",
470                0, 0, 0 );
471         }
472         if (bmc->dc != NULL) {
473                 free (bmc->dc);
474         }
475         free(bmc);
476
477         if (clear_cl > 0) {
478                 asyncmeta_free_candidate_list(cl, lock);
479                 Debug( LDAP_DEBUG_TRACE, "==> asyncmeta_clear_bm_context: free_cl_list\n",
480                0, 0, 0 );
481         }
482 #else
483         asyncmeta_memctx_put(op->o_threadctx, op->o_tmpmemctx);
484 #endif
485 }
486
487 int asyncmeta_add_message_queue(a_metaconn_t *mc, bm_context_t *bc)
488 {
489         a_metainfo_t *mi = mc->mc_info;
490         int max_pending_ops = (mi->mi_max_pending_ops == 0) ? META_BACK_CFG_MAX_PENDING_OPS : mi->mi_max_pending_ops;
491
492         Debug( LDAP_DEBUG_TRACE, "add_message_queue: mc %p, pending_ops %d, max_pending %d\n",
493                 mc, mc->pending_ops, max_pending_ops );
494
495         if (mc->pending_ops >= max_pending_ops) {
496                 return LDAP_BUSY;
497         }
498
499         LDAP_SLIST_INSERT_HEAD( &mc->mc_om_list, bc, bc_next);
500         mc->pending_ops++;
501         return LDAP_SUCCESS;
502 }
503
504 void
505 asyncmeta_drop_bc(a_metaconn_t *mc, bm_context_t *bc)
506 {
507         bm_context_t *om;
508         LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) {
509                 if (om == bc) {
510                         LDAP_SLIST_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next);
511                         mc->pending_ops--;
512                         break;
513                 }
514         }
515 }
516
517 bm_context_t *
518 asyncmeta_find_message(ber_int_t msgid, a_metaconn_t *mc, int candidate)
519 {
520         bm_context_t *om;
521         LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) {
522                 if (om->candidates[candidate].sr_msgid == msgid) {
523                         break;
524                 }
525         }
526         return om;
527 }
528
529
530
531 bm_context_t *
532 asyncmeta_find_message_by_opmsguid (ber_int_t msgid, a_metaconn_t *mc, int remove)
533 {
534         bm_context_t *om;
535         LDAP_SLIST_FOREACH( om, &mc->mc_om_list, bc_next ) {
536                 if (om->op->o_msgid == msgid) {
537                         break;
538                 }
539         }
540         if (remove && om) {
541                 LDAP_SLIST_REMOVE(&mc->mc_om_list, om, bm_context_t, bc_next);
542                 mc->pending_ops--;
543         }
544         return om;
545 }