]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/cache-merge.c
Finish proxy cache cleanup and API porting (on behalf of Apurva Kumar)
[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                 for ( i = 0; i < count; i++ ) {
250                         ber_dupbv(mod->sml_bvalues+i, a_new->a_vals+i); 
251                 }
252
253                 mod->sml_bvalues[count].bv_val = 0; 
254                 mod->sml_bvalues[count].bv_len = 0; 
255
256                 mod->sml_desc = NULL;
257                 slap_bv2ad(&mod->sml_type, &mod->sml_desc, &text); 
258                 mod->sml_next =NULL;
259                 *modtail = mod;
260                 modtail = &mod->sml_next;
261                 a_new = a_new->a_next; 
262         } 
263
264         /* add query UUID to queryid attribute */
265         mod = (Modifications *) ch_malloc( sizeof(Modifications) );
266         mod->sml_op = LDAP_MOD_ADD;
267         mod->sml_desc = slap_schema.si_ad_queryid; 
268         ber_dupbv(&mod->sml_type, &mod->sml_desc->ad_cname); 
269         mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
270         ber_dupbv( mod->sml_bvalues, uuid );
271         mod->sml_bvalues[1].bv_val = NULL;
272         mod->sml_bvalues[1].bv_len = 0;
273         *modtail = mod;
274         mod->sml_next = NULL; 
275
276         /* Apply changes */
277         op_tmp.o_req_dn = entry->e_name;
278         op_tmp.o_req_ndn = entry->e_nname;
279         op_tmp.orm_modlist = modhead;
280
281         op_tmp.o_callback->sc_response = null_response; 
282         /* FIXME: &op_tmp ??? */
283         if (be->be_modify(op, &sreply ) != 0 ) {
284                 /* FIXME: cleanup ? */
285                 info->err = MERGE_ERR;
286                 goto cleanup; 
287         }
288
289         /* compute the size of the entry */
290         op_tmp.o_callback->sc_response = get_size_func; 
291
292         op_tmp.ors_scope = LDAP_SCOPE_BASE;
293         op_tmp.ors_deref = LDAP_DEREF_NEVER;
294         op_tmp.ors_slimit = 1;
295         op_tmp.ors_tlimit = 0;
296         op_tmp.ors_filter = filter;
297         op_tmp.ors_filterstr = bv_queryid_any;
298         op_tmp.ors_attrs = NULL;
299         op_tmp.ors_attrsonly = 0;
300    
301         sreply1.sr_entry = NULL; 
302         sreply1.sr_nentries = 0; 
303
304         if (be->be_search( &op_tmp, &sreply1 ) != 0) {
305                 info->err = GET_SIZE_ERR;
306         }
307
308 cleanup:;
309         if ( modhead != NULL) {
310                 slap_mods_free( modhead );
311         }
312
313         return 0; 
314 }
315
316 static void
317 add_func (
318         Operation       *op,
319         SlapReply       *rs
320 )
321 {
322         struct entry_info       *info = op->o_callback->sc_private; 
323         Entry                   *entry = info->entry; 
324         struct berval           *uuid = info->uuid; 
325         Backend                 *be; 
326         BerVarray               value_array; 
327         Entry                   *e; 
328         Attribute               *a, *attr; 
329         int                     i,j;
330         SlapReply               sreply = {REP_RESULT}; 
331
332         struct timeval          time;   /* time */ 
333         long                    timediff; /* time */ 
334
335         Operation               op_tmp = *op;
336
337         /* 
338          * new entry, construct an entry with 
339          * the projected attributes 
340          */
341         if (rs->sr_nentries) {
342                 return;
343         }
344         
345         op_tmp.o_callback->sc_response = null_response; 
346         be = select_backend(&entry->e_nname, 0, 0); 
347         e = (Entry*)malloc(sizeof(Entry)); 
348
349         ber_dupbv(&e->e_name,&entry->e_name); 
350         ber_dupbv(&e->e_nname,&entry->e_nname); 
351
352         e->e_private = 0;
353         e->e_attrs = 0; 
354         e->e_bv.bv_val = 0; 
355
356         /* add queryid attribute */     
357         value_array = (struct berval *)malloc(2 * sizeof( struct berval) );
358         ber_dupbv(value_array, uuid);
359         value_array[1].bv_val = NULL;
360         value_array[1].bv_len = 0;
361
362         a = add_attribute(slap_schema.si_ad_queryid, 
363                         e, value_array); 
364
365         /* append the attribute list from the fetched entry */
366         a->a_next = entry->e_attrs;
367         entry->e_attrs = NULL;
368
369         for ( attr = e->e_attrs; attr; attr = attr->a_next ) {
370                 if ( normalize_values( attr ) ) {
371                         info->err = MERGE_ERR; 
372                         return;
373                 }
374         }
375
376         info->size_final = get_entry_size( e, 0, NULL ); 
377
378         op_tmp.o_bd = be;
379         op_tmp.ora_e = e;
380         
381         if ( be->be_add( &op_tmp, &sreply ) == 0 ) {
382                 info->added = 1; 
383                 be_entry_release_w( &op_tmp, e );
384         } else {
385                 info->err = MERGE_ERR; 
386         }
387 }
388  
389
390 static Attribute* 
391 add_attribute(AttributeDescription *ad,
392         Entry* e, 
393         BerVarray value_array) 
394 {
395         Attribute* new_attr, *last_attr; 
396         const char* text; 
397
398         if (e->e_attrs == NULL) 
399                 last_attr = NULL; 
400         else 
401                 for (last_attr = e->e_attrs; last_attr->a_next;
402                                 last_attr = last_attr->a_next)
403                         ; 
404
405         new_attr = (Attribute*)malloc(sizeof(Attribute));               
406         if (last_attr) 
407                 last_attr->a_next = new_attr;
408         else 
409                 e->e_attrs = new_attr; 
410
411         new_attr->a_next = NULL; 
412         new_attr->a_desc = NULL;
413         new_attr->a_vals = value_array; 
414         new_attr->a_desc = ad;
415
416         return new_attr; 
417 }
418
419 static int
420 get_size_func (
421         Operation       *op,
422         SlapReply       *rs
423 )
424 {
425         struct entry_info       *info = op->o_callback->sc_private; 
426         struct exception        result; 
427
428         if ( rs->sr_type == REP_SEARCH ) {
429                 result.type = info->err;  
430                 info->size_final = get_entry_size(rs->sr_entry,
431                                 info->size_init, &result); 
432         }
433
434         return 0; 
435 }
436
437
438 static int
439 null_response (
440         Operation       *op,
441         SlapReply       *rs )
442 {
443         return 0;
444 }
445
446 static int 
447 normalize_values( Attribute* attr ) 
448 {
449         int nvals, rc, i; 
450  
451         if (attr->a_vals == NULL) {
452                 attr->a_nvals = NULL; 
453                 return 0; 
454         } 
455
456         for ( nvals = 0; attr->a_vals[nvals].bv_val; nvals++ ) 
457                 ; 
458
459         attr->a_nvals = (struct berval*)ch_malloc((nvals+1)*sizeof(struct berval));
460
461         if ( attr->a_desc->ad_type->sat_equality &&
462                                 attr->a_desc->ad_type->sat_equality->smr_normalize )
463         {
464                 for ( i = 0; i < nvals; i++ ) {
465                         rc = attr->a_desc->ad_type->sat_equality->smr_normalize(
466                                 0,
467                                 attr->a_desc->ad_type->sat_syntax,
468                                 attr->a_desc->ad_type->sat_equality,
469                                 &attr->a_vals[i], &attr->a_nvals[i], NULL );
470                         if ( rc ) {
471 #ifdef NEW_LOGGING
472                                 LDAP_LOG( OPERATION, DETAIL1,
473                                         "Error in normalizing attribute %s value %d (%d)\n",
474                                         attr->a_desc->ad_cname.bv_val, i, rc );
475 #else
476                                 Debug( LDAP_DEBUG_ANY,
477                                         "Error in normalizing attribute %s value %d (%d)\n",
478                                         attr->a_desc->ad_cname.bv_val, i, rc );
479 #endif
480                                 return rc;
481                         }
482                 }
483         } else {
484                 for ( i = 0; i < nvals; i++ ) {
485                         ber_dupbv( &attr->a_nvals[i], &attr->a_vals[i] ); 
486                 }
487         }
488                         
489         attr->a_nvals[i].bv_val = NULL;
490         attr->a_nvals[i].bv_len = 0;
491
492         return LDAP_SUCCESS;
493 }
494
495 #endif /* LDAP_CACHING */