]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/cache-merge.c
28fd72f4b40802601e577a25274b72a957597a36
[openldap] / servers / slapd / back-meta / cache-merge.c
1 /* Copyright (c) 2003 by International Business Machines, Inc.
2  *
3  * International Business Machines, Inc. (hereinafter called IBM) grants
4  * permission under its copyrights to use, copy, modify, and distribute this
5  * Software with or without fee, provided that the above copyright notice and
6  * all paragraphs of this notice appear in all copies, and that the name of IBM
7  * not be used in connection with the marketing of any product incorporating
8  * the Software or modifications thereof, without specific, written prior
9  * permission.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
12  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
13  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
14  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
15  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
16  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
17  */
18
19 #include "portable.h"
20
21 #include <stdio.h>
22
23 #include <ac/socket.h>
24 #include <ac/string.h>
25 #include <ac/time.h>
26
27 #include "slap.h"
28 #include "ldif.h"
29 #include "../back-ldap/back-ldap.h"
30 #include "back-meta.h"
31 #include "ldap_pvt.h"
32 #undef ldap_debug       /* silence a warning in ldap-int.h */
33 #include "ldap_log.h"
34 #include "../../../libraries/libldap/ldap-int.h"
35 #include <sys/time.h>
36
37 #ifdef LDAP_CACHING
38
39 static struct berval bv_queryid_any = BER_BVC( "(queryid=*)" );
40
41 static int
42 merge_func (
43         Operation       *op,
44         SlapReply       *rs
45 ); 
46
47 static void
48 add_func (
49         Operation       *op,
50         SlapReply       *rs
51 ); 
52
53 static Attribute* 
54 add_attribute(AttributeDescription *ad,
55         Entry* e,
56         BerVarray value_array
57 ); 
58
59 static int
60 get_size_func (
61         Operation       *op,
62         SlapReply       *rs
63 ); 
64
65 static int
66 null_response (
67         Operation       *op,
68         SlapReply       *rs
69 ); 
70
71 static int 
72 normalize_values( Attribute* attr );    
73
74 struct entry_info {
75         int                     size_init; 
76         int                     size_final; 
77         int                     added; 
78         Entry*                  entry; 
79         struct berval*          uuid; 
80         struct timeval          tv;     /* time */ 
81         enum type_of_result     err; 
82         Backend*                glue_be; 
83 }; 
84
85
86 int 
87 get_entry_size(
88         Entry* e, 
89         int size_init, 
90         struct exception* result )
91 {
92         Attribute       *a;
93         struct berval   bv;
94         int             i; 
95         int             tmplen;
96         int             size=0;
97
98         if ( result )
99                 result->type = SUCCESS; 
100
101         if ( e->e_dn != NULL ) {
102                 tmplen = strlen( e->e_dn );
103                 size = LDIF_SIZE_NEEDED( 2, tmplen );
104         }
105
106         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
107                 for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) {
108                         bv = a->a_vals[i];
109                         tmplen = a->a_desc->ad_cname.bv_len;
110                         size += LDIF_SIZE_NEEDED( tmplen, bv.bv_len);
111                 }
112         }
113         if ((size < size_init) && result) {
114                 result->type = SIZE_ERR; 
115         }
116         return size;
117 }
118
119 /* quick hack: call the right callback */
120 static int
121 add_merge_func( Operation *op, SlapReply *rs )
122 {
123         switch ( rs->sr_type ) {
124         case REP_SEARCH:
125                 merge_func( op, rs );
126                 break;
127
128         case REP_RESULT:
129                 add_func( op, rs );
130                 break;
131
132         default:
133                 assert( 0 );
134         }
135         return 0;
136 }
137
138 int
139 merge_entry(
140         Operation               *op,
141         SlapReply               *rs,
142         struct berval*          query_uuid, 
143         struct exception*       result )
144 {
145         struct entry_info info;
146         struct berval normdn;
147         struct berval prettydn;
148
149         SlapReply sreply = {REP_RESULT};
150
151         Operation op_tmp = *op;
152         slap_callback cb = { add_merge_func, NULL };
153
154         Filter* filter = str2filter( bv_queryid_any.bv_val );
155         sreply.sr_entry = NULL; 
156         sreply.sr_nentries = 0; 
157
158         dnPrettyNormal(0, &rs->sr_entry->e_name, &prettydn, &normdn,
159                         op->o_tmpmemctx);
160
161         free(rs->sr_entry->e_name.bv_val);
162         rs->sr_entry->e_name = prettydn;
163         if (rs->sr_entry->e_nname.bv_val) free(rs->sr_entry->e_nname.bv_val);
164         rs->sr_entry->e_nname = normdn;
165
166         info.entry = rs->sr_entry;
167         info.uuid = query_uuid;
168         info.size_init = 0;
169         info.size_final = 0;
170         info.added = 0;
171         info.glue_be = op->o_bd;
172         info.err = SUCCESS;
173         cb.sc_private = &info;
174
175         op_tmp.o_tag = LDAP_REQ_SEARCH;
176         op_tmp.o_protocol = LDAP_VERSION3;
177         op_tmp.o_callback = &cb;
178         op_tmp.o_caching_on = 1;
179         op_tmp.o_time = slap_get_time();
180         op_tmp.o_do_not_cache = 1;
181
182         op_tmp.o_req_dn = rs->sr_entry->e_name;
183         op_tmp.o_req_ndn = rs->sr_entry->e_nname;
184         op_tmp.ors_scope = LDAP_SCOPE_BASE;
185         op_tmp.ors_deref = LDAP_DEREF_NEVER;
186         op_tmp.ors_slimit = 1;
187         op_tmp.ors_tlimit = 0;
188         op_tmp.ors_filter = filter;
189         op_tmp.ors_filterstr = bv_queryid_any;
190         op_tmp.ors_attrs = NULL;
191         op_tmp.ors_attrsonly = 0;
192
193         op->o_bd->be_search( &op_tmp, &sreply );
194         result->type = info.err; 
195         if ( result->type == SUCCESS )
196                 result->rc = info.added; 
197         else 
198                 result->rc = 0; 
199         return ( info.size_final - info.size_init );
200 }
201
202 static int
203 merge_func (
204         Operation       *op,
205         SlapReply       *rs
206 )
207 {
208         Backend                 *be;
209         char                    *new_attr_name;
210         Attribute               *a_new, *a;
211         int                     i = 0;
212         int                     rc = 0;
213     
214         int                     count;
215         struct timeval          time;   /* time */
216         long                    timediff; /* time */
217         struct entry_info       *info = op->o_callback->sc_private;
218         Filter                  *filter = str2filter( bv_queryid_any.bv_val );
219         Entry                   *entry = info->entry;
220         struct berval           *uuid = info->uuid;
221         Modifications           *modhead = NULL;
222         Modifications           *mod;
223         Modifications           **modtail = &modhead;
224         AttributeDescription    *a_new_desc;
225         const char              *text = NULL;
226         Operation               op_tmp = *op;
227         SlapReply               sreply = {REP_RESULT}; 
228         SlapReply               sreply1 = {REP_RESULT}; 
229
230         info->err = SUCCESS; 
231
232         be = select_backend(&entry->e_nname, 0, 0); 
233      
234         info->size_init = get_entry_size(rs->sr_entry, 0, 0);  
235         a_new = entry->e_attrs;
236
237         while (a_new != NULL) {
238                 a_new_desc = a_new->a_desc; 
239                 mod = (Modifications *) malloc( sizeof(Modifications) );
240                 mod->sml_op = LDAP_MOD_REPLACE;
241                 ber_dupbv(&mod->sml_type, &a_new_desc->ad_cname); 
242
243                 for ( count = 0; a_new->a_vals[count].bv_val; count++ ) 
244                         ;
245
246                 mod->sml_bvalues = (struct berval*) malloc(
247                                 (count+1) * sizeof( struct berval) );
248
249                 mod->sml_nvalues = (struct berval*) malloc(
250                                 (count+1) * sizeof( struct berval) );
251
252                 for ( i = 0; i < count; i++ ) {
253                         ber_dupbv(mod->sml_bvalues+i, a_new->a_vals+i); 
254                         if ( a_new->a_desc->ad_type->sat_equality &&
255                                 a_new->a_desc->ad_type->sat_equality->smr_normalize ) {
256                                 rc = a_new->a_desc->ad_type->sat_equality->smr_normalize(
257                                         0,
258                                         a_new->a_desc->ad_type->sat_syntax,
259                                         a_new->a_desc->ad_type->sat_equality,
260                                         a_new->a_vals+i, mod->sml_nvalues+i, NULL );
261                                 if (rc) {
262                                         info->err = MERGE_ERR; 
263                                         return 0; 
264                                 } 
265                         }
266                         else {  
267                                 ber_dupbv( mod->sml_nvalues+i, a_new->a_vals+i ); 
268                         } 
269                 }
270
271                 mod->sml_bvalues[count].bv_val = 0; 
272                 mod->sml_bvalues[count].bv_len = 0; 
273
274                 mod->sml_nvalues[count].bv_val = 0; 
275                 mod->sml_nvalues[count].bv_len = 0; 
276
277                 mod->sml_desc = NULL;
278                 slap_bv2ad(&mod->sml_type, &mod->sml_desc, &text); 
279                 mod->sml_next =NULL;
280                 *modtail = mod;
281                 modtail = &mod->sml_next;
282                 a_new = a_new->a_next; 
283         } 
284
285         /* add query UUID to queryid attribute */
286         mod = (Modifications *) ch_malloc( sizeof(Modifications) );
287         mod->sml_op = LDAP_MOD_ADD;
288         mod->sml_desc = slap_schema.si_ad_queryid; 
289         ber_dupbv(&mod->sml_type, &mod->sml_desc->ad_cname); 
290
291         mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
292         ber_dupbv( mod->sml_bvalues, uuid );
293         mod->sml_bvalues[1].bv_val = NULL;
294         mod->sml_bvalues[1].bv_len = 0;
295
296         mod->sml_nvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
297         ber_dupbv( mod->sml_nvalues, uuid );
298         mod->sml_nvalues[1].bv_val = NULL;
299         mod->sml_nvalues[1].bv_len = 0;
300
301         *modtail = mod;
302         mod->sml_next = NULL; 
303
304         /* Apply changes */
305         op_tmp.o_req_dn = entry->e_name;
306         op_tmp.o_req_ndn = entry->e_nname;
307         op_tmp.orm_modlist = modhead;
308
309         op_tmp.o_callback->sc_response = null_response; 
310         /* FIXME: &op_tmp ??? */
311         if (be->be_modify(&op_tmp, &sreply ) != 0 ) {
312                 /* FIXME: cleanup ? */
313                 info->err = MERGE_ERR;
314                 goto cleanup; 
315         }
316
317         /* compute the size of the entry */
318         op_tmp.o_callback->sc_response = get_size_func; 
319
320         op_tmp.ors_scope = LDAP_SCOPE_BASE;
321         op_tmp.ors_deref = LDAP_DEREF_NEVER;
322         op_tmp.ors_slimit = 1;
323         op_tmp.ors_tlimit = 0;
324         op_tmp.ors_filter = filter;
325         op_tmp.ors_filterstr = bv_queryid_any;
326         op_tmp.ors_attrs = NULL;
327         op_tmp.ors_attrsonly = 0;
328    
329         sreply1.sr_entry = NULL; 
330         sreply1.sr_nentries = 0; 
331
332         if (be->be_search( &op_tmp, &sreply1 ) != 0) {
333                 info->err = GET_SIZE_ERR;
334         }
335
336 cleanup:;
337         if ( modhead != NULL) {
338                 slap_mods_free( modhead );
339         }
340
341         return 0; 
342 }
343
344 static void
345 add_func (
346         Operation       *op,
347         SlapReply       *rs
348 )
349 {
350         struct entry_info       *info = op->o_callback->sc_private; 
351         Entry                   *entry = info->entry; 
352         struct berval           *uuid = info->uuid; 
353         Backend                 *be; 
354         BerVarray               value_array; 
355         Entry                   *e; 
356         Attribute               *a, *attr; 
357         int                     i,j;
358         SlapReply               sreply = {REP_RESULT}; 
359
360         struct timeval          time;   /* time */ 
361         long                    timediff; /* time */ 
362
363         Operation               op_tmp = *op;
364
365         /* 
366          * new entry, construct an entry with 
367          * the projected attributes 
368          */
369         if (rs->sr_nentries) {
370                 return;
371         }
372         
373         op_tmp.o_callback->sc_response = null_response; 
374         be = select_backend(&entry->e_nname, 0, 0); 
375         e = (Entry*)malloc(sizeof(Entry)); 
376
377         ber_dupbv(&e->e_name,&entry->e_name); 
378         ber_dupbv(&e->e_nname,&entry->e_nname); 
379
380         e->e_private = 0;
381         e->e_attrs = 0; 
382         e->e_bv.bv_val = 0; 
383
384         /* add queryid attribute */     
385         value_array = (struct berval *)malloc(2 * sizeof( struct berval) );
386         ber_dupbv(value_array, uuid);
387         value_array[1].bv_val = NULL;
388         value_array[1].bv_len = 0;
389
390         a = add_attribute(slap_schema.si_ad_queryid, 
391                         e, value_array); 
392
393         /* append the attribute list from the fetched entry */
394         a->a_next = entry->e_attrs;
395         entry->e_attrs = NULL;
396
397         for ( attr = e->e_attrs; attr; attr = attr->a_next ) {
398                 if ( normalize_values( attr ) ) {
399                         info->err = MERGE_ERR; 
400                         return;
401                 }
402         }
403
404         info->size_final = get_entry_size( e, 0, NULL ); 
405
406         op_tmp.o_bd = be;
407         op_tmp.ora_e = e;
408         
409         if ( be->be_add( &op_tmp, &sreply ) == 0 ) {
410                 info->added = 1; 
411                 be_entry_release_w( &op_tmp, e );
412         } else {
413                 info->err = MERGE_ERR; 
414         }
415 }
416  
417
418 static Attribute* 
419 add_attribute(AttributeDescription *ad,
420         Entry* e, 
421         BerVarray value_array) 
422 {
423         Attribute* new_attr, *last_attr; 
424         const char* text; 
425
426         if (e->e_attrs == NULL) 
427                 last_attr = NULL; 
428         else 
429                 for (last_attr = e->e_attrs; last_attr->a_next;
430                                 last_attr = last_attr->a_next)
431                         ; 
432
433         new_attr = (Attribute*)malloc(sizeof(Attribute));               
434         if (last_attr) 
435                 last_attr->a_next = new_attr;
436         else 
437                 e->e_attrs = new_attr; 
438
439         new_attr->a_next = NULL; 
440         new_attr->a_desc = NULL;
441         new_attr->a_vals = value_array; 
442         new_attr->a_desc = ad;
443
444         return new_attr; 
445 }
446
447 static int
448 get_size_func (
449         Operation       *op,
450         SlapReply       *rs
451 )
452 {
453         struct entry_info       *info = op->o_callback->sc_private; 
454         struct exception        result; 
455
456         if ( rs->sr_type == REP_SEARCH ) {
457                 result.type = info->err;  
458                 info->size_final = get_entry_size(rs->sr_entry,
459                                 info->size_init, &result); 
460         }
461
462         return 0; 
463 }
464
465
466 static int
467 null_response (
468         Operation       *op,
469         SlapReply       *rs )
470 {
471         return 0;
472 }
473
474 static int 
475 normalize_values( Attribute* attr ) 
476 {
477         int nvals, rc, i; 
478  
479         if (attr->a_vals == NULL) {
480                 attr->a_nvals = NULL; 
481                 return 0; 
482         } 
483
484         for ( nvals = 0; attr->a_vals[nvals].bv_val; nvals++ ) 
485                 ; 
486
487         attr->a_nvals = (struct berval*)ch_malloc((nvals+1)*sizeof(struct berval));
488
489         if ( attr->a_desc->ad_type->sat_equality &&
490                                 attr->a_desc->ad_type->sat_equality->smr_normalize )
491         {
492                 for ( i = 0; i < nvals; i++ ) {
493                         rc = attr->a_desc->ad_type->sat_equality->smr_normalize(
494                                 0,
495                                 attr->a_desc->ad_type->sat_syntax,
496                                 attr->a_desc->ad_type->sat_equality,
497                                 &attr->a_vals[i], &attr->a_nvals[i], NULL );
498                         if ( rc ) {
499 #ifdef NEW_LOGGING
500                                 LDAP_LOG( OPERATION, DETAIL1,
501                                         "Error in normalizing attribute %s value %d (%d)\n",
502                                         attr->a_desc->ad_cname.bv_val, i, rc );
503 #else
504                                 Debug( LDAP_DEBUG_ANY,
505                                         "Error in normalizing attribute %s value %d (%d)\n",
506                                         attr->a_desc->ad_cname.bv_val, i, rc );
507 #endif
508                                 return rc;
509                         }
510                 }
511         } else {
512                 for ( i = 0; i < nvals; i++ ) {
513                         ber_dupbv( &attr->a_nvals[i], &attr->a_vals[i] ); 
514                 }
515         }
516                         
517         attr->a_nvals[i].bv_val = NULL;
518         attr->a_nvals[i].bv_len = 0;
519
520         return LDAP_SUCCESS;
521 }
522
523 #endif /* LDAP_CACHING */