]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/cache-search.c
Commit of the Proxy Cache contribution (ITS#2062)
[openldap] / servers / slapd / back-meta / cache-search.c
1 /*
2  * Copyright (c) 2003 by International Business Machines, Inc.
3  *
4  * International Business Machines, Inc. (hereinafter called IBM) grants
5  * permission under its copyrights to use, copy, modify, and distribute this
6  * Software with or without fee, provided that the above copyright notice and
7  * all paragraphs of this notice appear in all copies, and that the name of IBM
8  * not be used in connection with the marketing of any product incorporating
9  * the Software or modifications thereof, without specific, written prior
10  * permission.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
13  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
15  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
17  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
18  *
19  * 
20  * This software is based on the backends back-ldap and back-meta, implemented
21  * by Howard Chu <hyc@highlandsun.com>, Mark Valence
22  * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
23  * contributors. 
24  *
25  * The original copyright statements follow. 
26  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
27  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
28  *
29  * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
30  *
31  * This work has been developed to fulfill the requirements
32  * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
33  * to the OpenLDAP Foundation in the hope that it may be useful
34  * to the Open Source community, but WITHOUT ANY WARRANTY.
35  *
36  * Permission is granted to anyone to use this software for any purpose
37  * on any computer system, and to alter it and redistribute it, subject
38  * to the following restrictions:
39  *
40  * 1. The author and SysNet s.n.c. are not responsible for the consequences
41  *    of use of this software, no matter how awful, even if they arise from 
42  *    flaws in it.
43  *
44  * 2. The origin of this software must not be misrepresented, either by
45  *    explicit claim or by omission.  Since few users ever read sources,
46  *    credits should appear in the documentation.
47  *
48  * 3. Altered versions must be plainly marked as such, and must not be
49  *    misrepresented as being the original software.  Since few users
50  *    ever read sources, credits should appear in the documentation.
51  *    SysNet s.n.c. cannot be responsible for the consequences of the
52  *    alterations.
53  *
54  * 4. This notice may not be removed or altered.
55  *
56  *
57  * This software is based on the backend back-ldap, implemented
58  * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
59  * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
60  * contributors. The contribution of the original software to the present
61  * implementation is acknowledged in this copyright statement.
62  *
63  * A special acknowledgement goes to Howard for the overall architecture
64  * (and for borrowing large pieces of code), and to Mark, who implemented
65  * from scratch the attribute/objectclass mapping.
66  *
67  * The original copyright statement follows.
68  *
69  * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
70  *
71  * Permission is granted to anyone to use this software for any purpose
72  * on any computer system, and to alter it and redistribute it, subject
73  * to the following restrictions:
74  *
75  * 1. The author is not responsible for the consequences of use of this
76  *    software, no matter how awful, even if they arise from flaws in it.
77  *
78  * 2. The origin of this software must not be misrepresented, either by
79  *    explicit claim or by omission.  Since few users ever read sources,
80  *    credits should appear in the documentation.
81  *
82  * 3. Altered versions must be plainly marked as such, and must not be
83  *    misrepresented as being the original software.  Since few users
84  *    ever read sources, credits should appear in the
85  *    documentation.
86  *
87  * 4. This notice may not be removed or altered.
88  *                
89  */
90 #include "portable.h"
91
92 #include <stdio.h>
93
94 #include <ac/socket.h>
95 #include <ac/string.h>
96 #include <ac/time.h>
97
98 #include "lutil.h"
99 #include "slap.h"
100 #include "../back-ldap/back-ldap.h"
101 #include "back-meta.h"
102 #include "ldap_pvt.h"
103 #undef ldap_debug       /* silence a warning in ldap-int.h */
104 #include "ldap_log.h"
105 #include "../../../libraries/libldap/ldap-int.h"
106 #include <sys/time.h>
107
108 #ifdef LDAP_CACHING 
109 static Entry* 
110 meta_create_entry(
111         Backend         *be,
112         struct metaconn *lc,
113         int             target,
114         LDAPMessage     *e,
115         struct exception* result
116 ); 
117
118 static int
119 is_one_level_rdn(
120         const char      *rdn,
121         int             from
122 );
123
124 static struct metaconn*  
125 metaConnect(
126         struct metainfo* li, 
127         Connection* conn, 
128         Operation* op, 
129         int op_type, 
130         struct berval* nbase, 
131         struct exception* result 
132 );
133
134 static void
135 add_filter_attrs(
136         AttributeName** newattrs, 
137         AttributeName* attrs, 
138         AttributeName* filter_attrs
139 );
140
141 static int 
142 handleLdapResult(
143         struct metaconn* lc, 
144         Operation* op, 
145         int* msgid, Backend* be, 
146         AttributeName* attrs, 
147         int attrsonly, 
148         int candidates, 
149         int cacheable, 
150         Entry*** entry_array, 
151         int curr_limit, 
152         int slimit,
153         struct exception* result
154 );
155
156 static Entry* 
157 get_result_entry(
158         Backend* be,
159         struct metaconn* lc, 
160         struct metasingleconn* lsc, 
161         int* msgid,
162         int i, 
163         struct timeval* tv, 
164         struct exception* result
165 ); 
166
167 static void
168 rewriteSession(
169         struct rewrite_info* info, 
170         const char* rewriteContext, 
171         const char* string, 
172         const void* cookie,  
173         char** base, 
174         struct exception* result
175 );
176
177 static int 
178 get_attr_set(
179         AttributeName* attrs, 
180         query_manager* qm, 
181         int num
182 );
183
184 static int 
185 attrscmp(
186         AttributeName* attrs_in, 
187         AttributeName* attrs
188 );
189
190 static char* 
191 cache_entries(
192         Entry** entry_array, 
193         cache_manager* cm, 
194         Backend* be, 
195         Connection* conn, 
196         struct exception* result
197 ); 
198
199 static int 
200 is_temp_answerable(
201         int attr_set, 
202         struct berval* tempstr, 
203         query_manager* qm, 
204         int template_id
205 );
206
207 static void
208 consistency_check(
209         Backend* be,
210         Backend* glue_be, 
211         Connection* conn
212 ); 
213
214 static int
215 cache_back_sentry(
216         Backend* be, 
217         Connection* conn,
218         Operation* op, 
219         Entry* e, 
220         AttributeName* attrs, 
221         int attrsonly, 
222         LDAPControl** ctrls
223 );
224
225 int
226 meta_back_cache_search(
227         Backend         *be,
228         Connection      *conn,
229         Operation       *op,
230         struct berval   *base,
231         struct berval   *nbase,
232         int             scope,
233         int             deref,
234         int             slimit,
235         int             tlimit,
236         Filter          *filt,
237         struct berval   *filterstr,
238         AttributeName   *attributes,
239         int             attrsonly
240 )
241 {
242         struct metainfo         *li = ( struct metainfo * )be->be_private;
243         struct metaconn         *lc;
244         struct metasingleconn   *lsc;
245         cache_manager*          cm = li->cm; 
246         query_manager*          qm = cm->qm; 
247
248         time_t                  curr_time; 
249
250         int count, rc = 0, *msgid = NULL; 
251         char *mbase = NULL;
252         char *cbase = NULL; 
253         char *uuid; 
254             
255         int i = -1, last = 0, candidates = 0, op_type;
256
257         struct berval   mfilter;
258         struct berval   *cachebase = NULL;  
259         struct berval   *ncachebase = NULL;  
260         struct berval   cache_suffix; 
261         struct berval   tempstr = {0, 0}; 
262
263         AttributeName   *filter_attrs = NULL; 
264         AttributeName   *new_attrs = NULL; 
265         AttributeName   *attrs = NULL; 
266
267         Entry           *e;
268         Entry           **entry_array = NULL;
269
270         Query           query; 
271
272         int             attr_set = -1; 
273         int             template_id = -1; 
274         int             answerable = 0; 
275         int             cacheable = 0; 
276         int             num_entries = 0;
277         int             curr_limit;
278         int             fattr_cnt=0; 
279
280    
281         struct exception result[1]; 
282
283         Filter* filter = str2filter(filterstr->bv_val); 
284         slap_callback cb = {NULL, NULL, cache_back_sentry, NULL}; 
285
286         cb.sc_private = be; 
287
288         if (attributes) {
289                 for ( count=0; attributes[ count ].an_name.bv_val; count++ )
290                         ;
291                 attrs = (AttributeName*)malloc( ( count + 1 ) *
292                                                 sizeof(AttributeName));
293                 for ( count=0; attributes[ count ].an_name.bv_val; count++ ) {
294                         ber_dupbv(&attrs[ count ].an_name,
295                                                 &attributes[ count ].an_name);
296                         attrs[count].an_desc = attributes[count].an_desc; 
297                 }
298                 attrs[ count ].an_name.bv_val = NULL;
299                 attrs[ count ].an_name.bv_len = 0;
300         }
301
302         result->type = SUCCESS; 
303         result->rc = 0; 
304         ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
305         cm->threads++; 
306 #ifdef NEW_LOGGING
307         LDAP_LOG( BACK_META, DETAIL1, "Threads++ = %d\n", cm->threads, 0, 0 );
308 #else /* !NEW_LOGGING */
309         Debug( LDAP_DEBUG_ANY, "Threads++ = %d\n", cm->threads, 0, 0 );
310 #endif /* !NEW_LOGGING */
311         ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
312     
313         filter2template(filter, &tempstr, &filter_attrs, &fattr_cnt, result);  
314         if (result->type != SUCCESS) 
315                 goto Catch; 
316
317 #ifdef NEW_LOGGING
318         LDAP_LOG( BACK_META, DETAIL1, "query template of incoming query = %s\n",
319                                         tempstr.bv_val, 0, 0 );
320 #else /* !NEW_LOGGING */
321         Debug( LDAP_DEBUG_ANY, "query template of incoming query = %s\n",
322                                         tempstr.bv_val, 0, 0 );
323 #endif /* !NEW_LOGGING */
324         curr_limit = cm->num_entries_limit ;
325
326         /* find attr set */     
327         attr_set = get_attr_set(attrs, qm, cm->numattrsets); 
328     
329         query.filter = filter; 
330         query.attrs = attrs; 
331         query.base = *base; 
332         query.scope = scope; 
333
334         /* check for query containment */
335         if (attr_set > -1) {
336                 for (i=0; i<cm->numtemplates; i++) {
337                         /* find if template i can potentially answer tempstr */
338                         if (!is_temp_answerable(attr_set, &tempstr, qm, i)) 
339                                 continue; 
340                         if (attr_set == qm->templates[i].attr_set_index) {
341                                 cacheable = 1; 
342                                 template_id = i; 
343                         }
344 #ifdef NEW_LOGGING
345                         LDAP_LOG( BACK_META, DETAIL2,
346                                         "Entering QC, querystr = %s\n",
347                                         filterstr->bv_val, 0, 0 );
348 #else /* !NEW_LOGGING */
349                         Debug( LDAP_DEBUG_NONE, "Entering QC, querystr = %s\n",
350                                                 filterstr->bv_val, 0, 0 );
351 #endif /* !NEW_LOGGING */
352                         answerable = (*(qm->qcfunc))(qm, &query, i);
353
354                         if (answerable)
355                                 break;
356                 }
357         }
358
359         if (answerable) {
360 #ifdef NEW_LOGGING
361                 LDAP_LOG( BACK_META, DETAIL1, "QUERY ANSWERABLE\n", 0, 0, 0 );
362 #else /* !NEW_LOGGING */
363                 Debug( LDAP_DEBUG_ANY, "QUERY ANSWERABLE\n", 0, 0, 0 );
364 #endif /* !NEW_LOGGING */
365                 rewriteSession(li->rwinfo, "cacheBase", nbase->bv_val,
366                                         conn, &cbase, result); 
367                 if (result->type != SUCCESS) { 
368                         ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock); 
369                         goto Catch; 
370                 }
371                 cachebase = ber_str2bv(cbase, strlen(cbase), 0, NULL);  
372                 dnNormalize(NULL, cachebase, &ncachebase); 
373         
374                 op->o_caching_on = 1;   
375                 op->o_callback = &cb; 
376                 li->glue_be->be_search(li->glue_be, conn, op, cachebase,
377                                 ncachebase, scope, deref, slimit, tlimit,
378                                 filter, filterstr, attrs, attrsonly);
379
380                 ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock); 
381         } else {
382 #ifdef NEW_LOGGING
383                 LDAP_LOG( BACK_META, DETAIL1, "QUERY NOT ANSWERABLE\n",
384                                         0, 0, 0 );
385 #else /* !NEW_LOGGING */
386                 Debug( LDAP_DEBUG_ANY, "QUERY NOT ANSWERABLE\n", 0, 0, 0 );
387 #endif /* !NEW_LOGGING */
388
389                 if ( scope == LDAP_SCOPE_BASE ) {
390                         op_type = META_OP_REQUIRE_SINGLE;
391                 } else {
392                         op_type = META_OP_ALLOW_MULTIPLE;
393                 }
394
395                 lc = metaConnect(li, conn, op, op_type, nbase, result);
396
397                 if (result->type != SUCCESS) 
398                         goto Catch; 
399
400                 ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
401                 if (cm->num_cached_queries >= cm->max_queries) {
402                         cacheable = 0; 
403                 }
404                 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
405                 
406                 if (cacheable) {
407 #ifdef NEW_LOGGING
408                         LDAP_LOG( BACK_META, DETAIL1,
409                                         "QUERY TEMPLATE CACHEABLE\n",
410                                         0, 0, 0);
411 #else /* !NEW_LOGGING */
412                         Debug( LDAP_DEBUG_ANY, "QUERY TEMPLATE CACHEABLE\n",
413                                         0, 0, 0);
414 #endif /* !NEW_LOGGING */
415                         add_filter_attrs(&new_attrs, attrs, filter_attrs);
416                 } else {
417                         new_attrs = attrs; 
418                 }
419
420                 free(filter_attrs); 
421         
422                 /*
423                  * Array of message id of each target
424                  */
425                 msgid = ch_calloc( sizeof( int ), li->ntargets );
426                 if ( msgid == NULL ) {
427                         result->type = CONN_ERR; 
428                         goto Catch; 
429                 }
430
431                 /*
432                 if (slimit > 0 &&  (slimit <= cm->num_entries_limit))  
433                         slimit = cm->num_entries_limit; 
434                 */
435
436                 /*
437                  * Inits searches
438                  */
439
440                 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
441                         char    *realbase = ( char * )base->bv_val;
442                         int     realscope = scope;
443                         ber_len_t suffixlen;
444                         char    *mapped_filter, **mapped_attrs;
445
446                         /* FIXME: Check for more than one targets */
447                         if ( meta_back_is_candidate(
448                                         &li->targets[i]->suffix, nbase ))
449                                 lsc->candidate = META_CANDIDATE; 
450
451                         if ( lsc->candidate != META_CANDIDATE ) 
452                                 continue;
453
454                         if ( deref != -1 ) {
455                                 ldap_set_option( lsc->ld, LDAP_OPT_DEREF,
456                                                 ( void * )&deref);
457                         }
458                         if ( tlimit != -1 ) {
459                                 ldap_set_option( lsc->ld, LDAP_OPT_TIMELIMIT,
460                                                 ( void * )&tlimit);
461                         }
462                         if ( slimit != -1 ) {
463                                 ldap_set_option( lsc->ld, LDAP_OPT_SIZELIMIT,
464                                                 ( void * )&slimit);
465                         }
466
467                         /*
468                          * modifies the base according to the scope, if required
469                          */
470                         suffixlen = li->targets[ i ]->suffix.bv_len;
471                         if ( suffixlen > nbase->bv_len ) {
472                                 switch ( scope ) {
473                                 case LDAP_SCOPE_SUBTREE:
474                                         /*
475                                          * make the target suffix the new base
476                                          * FIXME: this is very forgiving,
477                                          * because illegal bases may be turned
478                                          * into the suffix of the target.
479                                          */
480                                         if ( dnIsSuffix(
481                                                 &li->targets[ i ]->suffix,
482                                                 nbase ) ) {
483                                                 realbase =
484                                                 li->targets[i]->suffix.bv_val;
485                                         } else {
486                                                 /*
487                                                  * this target is no longer
488                                                  * candidate
489                                                  */
490                                                 lsc->candidate =
491                                                         META_NOT_CANDIDATE;
492                                                 continue;
493                                         }
494                                         break;
495
496                                 case LDAP_SCOPE_ONELEVEL:
497                                         if ( is_one_level_rdn(
498                                                 li->targets[ i ]->suffix.bv_val,
499                                                 suffixlen - nbase->bv_len - 1 )
500                                                 && dnIsSuffix(
501                                                 &li->targets[ i ]->suffix,
502                                                 nbase ) ) {
503                                                 /*
504                                                  * if there is exactly one
505                                                  * level, make the target suffix
506                                                  * the new base, and make scope
507                                                  * "base"
508                                                  */
509                                                 realbase =
510                                                 li->targets[i]->suffix.bv_val;
511                                                 realscope = LDAP_SCOPE_BASE;
512                                                 break;
513                                         } /* else continue with the next case */
514                                 case LDAP_SCOPE_BASE:
515                                         /*
516                                          * this target is no longer candidate
517                                          */
518                                         lsc->candidate = META_NOT_CANDIDATE;
519                                         continue;
520                                 }
521                         }
522
523                         /*
524                          * Rewrite the search base, if required
525                          */
526
527                         rewriteSession(li->targets[i]->rwinfo, "searchBase",
528                                         realbase, conn, &mbase, result); 
529
530                         if (result->type != SUCCESS)
531                                 goto Catch; 
532
533                         if ( mbase == NULL ) {
534                                 mbase = realbase;
535                         }
536
537                         /*
538                          * Rewrite the search filter, if required
539                          */
540                         rewriteSession( li->targets[i]->rwinfo, "searchFilter",
541                                         filterstr->bv_val, conn,
542                                         &mfilter.bv_val, result);
543                         if (result->type != SUCCESS) 
544                                 goto Catch; 
545
546                         if ( mfilter.bv_val != NULL && mfilter.bv_val[ 0 ]
547                                                                 != '\0') {
548                                 mfilter.bv_len = strlen( mfilter.bv_val );
549                         } else {
550                                 if ( mfilter.bv_val != NULL ) {
551                                         free( mfilter.bv_val );
552                                 }
553                                 mfilter = *filterstr;
554                         }
555
556                         /*
557                          * Maps attributes in filter
558                          */
559                         mapped_filter = ldap_back_map_filter(
560                                         &li->targets[i]->at_map,
561                                         &li->targets[i]->oc_map, &mfilter, 0 );
562                         if ( mapped_filter == NULL ) {
563                                 mapped_filter = ( char * )mfilter.bv_val;
564                         } else {
565                                 if ( mfilter.bv_val != filterstr->bv_val ) {
566                                         free( mfilter.bv_val );
567                                 }
568                         }
569                         mfilter.bv_val = NULL;
570                         mfilter.bv_len = 0;
571
572                         /*
573                          * Maps required attributes
574                          */
575                         mapped_attrs = ldap_back_map_attrs(
576                                         &li->targets[ i ]->at_map,
577                                         new_attrs, 0 );
578                         if ( mapped_attrs == NULL && new_attrs) {
579                                 for ( count=0;
580                                       new_attrs[ count ].an_name.bv_val;
581                                       count++)
582                                         ;
583                                 mapped_attrs = ch_malloc( ( count + 1 ) *
584                                                         sizeof(char *));
585                                 for ( count=0;
586                                       new_attrs[ count ].an_name.bv_val;
587                                       count++ ) {
588                                         mapped_attrs[ count ] =
589                                                 new_attrs[count].an_name.bv_val;
590                                 }
591                                 mapped_attrs[ count ] = NULL;
592                         }
593
594                         /*
595                          * Starts the search
596                          */
597                         msgid[ i ] = ldap_search( lsc->ld, mbase, realscope,
598                                                 mapped_filter, mapped_attrs,
599                                                 attrsonly ); 
600                         if ( msgid[ i ] == -1 ) {
601                                 lsc->candidate = META_NOT_CANDIDATE;
602                                 continue;
603                         }
604
605                         if ( mapped_attrs ) {
606                                 free( mapped_attrs );
607                                 mapped_attrs = NULL;
608                         }
609
610                         if ( mapped_filter != filterstr->bv_val ) {
611                                 free( mapped_filter );
612                                 mapped_filter = NULL;
613                         }
614
615                         if ( mbase != realbase ) {
616                                 free( mbase );
617                                 mbase = NULL;
618                         }
619
620                         ++candidates;
621                 }
622
623                 num_entries = handleLdapResult(lc, op, msgid, be, attrs,
624                                 attrsonly, candidates, cacheable, &entry_array,
625                                 curr_limit, slimit, result); 
626
627                 if (result->type != SUCCESS) 
628                         goto Catch; 
629                 if (cacheable && (num_entries <= curr_limit)) {
630 #ifdef NEW_LOGGING
631                         LDAP_LOG( BACK_META, DETAIL1,
632                                         "QUERY CACHEABLE\n", 0, 0, 0 );
633 #else /* !NEW_LOGGING */
634                         Debug( LDAP_DEBUG_ANY, "QUERY CACHEABLE\n", 0, 0, 0 );
635 #endif /* !NEW_LOGGING */
636                         uuid = cache_entries(entry_array, cm, li->glue_be,
637                                                         conn, result); 
638 #ifdef NEW_LOGGING
639                         LDAP_LOG( BACK_META, DETAIL1,
640                                         "Added query %s UUID %s ENTRIES %d\n",
641                                         filterstr->bv_val, uuid, num_entries );
642 #else /* !NEW_LOGGING */
643                         Debug( LDAP_DEBUG_ANY,
644                                         "Added query %s UUID %s ENTRIES %d\n",
645                                         filterstr->bv_val, uuid, num_entries );
646 #endif /* !NEW_LOGGING */
647             
648                         if (result->type != SUCCESS) 
649                                 goto Catch; 
650                         (*(qm->addfunc))(qm, &query, template_id, uuid, result); 
651                         if (result->type != SUCCESS) 
652                                 goto Catch; 
653                         filter = 0; 
654                         attrs = 0; 
655                 }
656         }
657
658 Catch: 
659         switch (result->type) {
660                 case SUCCESS: 
661                         rc=0; 
662                         break; 
663                 case FILTER_ERR: 
664 #ifdef NEW_LOGGING
665                         LDAP_LOG( BACK_META, DETAIL1,
666                                         "Invalid template error\n", 0, 0, 0 );
667 #else /* !NEW_LOGGING */
668                         Debug( LDAP_DEBUG_ANY, "Invalid template error\n",
669                                         0, 0, 0 );
670 #endif /* !NEW_LOGGING */
671                         break; 
672                 case CONN_ERR: 
673                         rc = -1; 
674 #ifdef NEW_LOGGING
675                         LDAP_LOG( BACK_META, DETAIL1,
676                                 "Could not connect to a remote server\n",
677                                 0, 0, 0 );
678 #else /* !NEW_LOGGING */
679                         Debug( LDAP_DEBUG_ANY,
680                                 "Could not connect to a remote server\n",
681                                 0, 0, 0 );
682 #endif /* !NEW_LOGGING */
683                         send_ldap_result(conn, op, LDAP_OTHER,  
684                                         NULL, "Connection error",
685                                         NULL, NULL );
686                         break; 
687                 case RESULT_ERR: 
688                         rc = -1; 
689 #ifdef NEW_LOGGING
690                         LDAP_LOG( BACK_META, DETAIL1,
691                                 "Error in handling ldap_result\n", 0, 0, 0 );
692 #else /* !NEW_LOGGING */
693                         Debug( LDAP_DEBUG_ANY,
694                                 "Error in handling ldap_result\n", 0, 0, 0 );
695 #endif /* !NEW_LOGGING */
696                         break; 
697                 case REWRITING_ERR: 
698                         rc = -1; 
699                         if (result->rc == REWRITE_REGEXEC_UNWILLING) {
700                                 send_ldap_result( conn, op,
701                                                 LDAP_UNWILLING_TO_PERFORM,
702                                                 NULL, "Unwilling to perform",
703                                                 NULL, NULL );
704                         } else {
705                                 send_ldap_result( conn, op, LDAP_OTHER,
706                                                 NULL, "Rewrite error",
707                                                 NULL, NULL );
708                         }
709                         break; 
710                 case MERGE_ERR: 
711                         rc = -1; 
712 #ifdef NEW_LOGGING
713                         LDAP_LOG( BACK_META, DETAIL1,
714                                 "Error in merging entry \n", 0, 0, 0 );
715 #else /* !NEW_LOGGING */
716                         Debug( LDAP_DEBUG_ANY,
717                                 "Error in merging entry \n", 0, 0, 0 );
718 #endif /* !NEW_LOGGING */
719                         break; 
720                 case REMOVE_ERR: 
721                         rc = -1; 
722 #ifdef NEW_LOGGING
723                         LDAP_LOG( BACK_META, DETAIL1,
724                                         "Error in removing query \n",
725                                         0, 0, 0 );
726 #else /* !NEW_LOGGING */
727                         Debug( LDAP_DEBUG_ANY, "Error in removing query \n",
728                                         0, 0, 0 );
729 #endif /* !NEW_LOGGING */
730                         break; 
731                 default:
732                         /* assert(0); */
733         }
734
735         ldap_pvt_thread_mutex_lock(&cm->consistency_mutex); 
736         curr_time = slap_get_time(); 
737         if (curr_time - cm->consistency_time > cm->consistency_cycle_time) {
738                 cm->consistency_time = curr_time; 
739                 consistency_check(be, li->glue_be, conn); 
740         }       
741         ldap_pvt_thread_mutex_unlock(&cm->consistency_mutex); 
742
743         if ( msgid ) {
744                 ch_free( msgid );
745         }
746         if (entry_array)  {
747                 for (i=0; (e = entry_array[i]); i++) {
748                         entry_free(e); 
749                 }
750                 free(entry_array);
751         }
752         if (filter) 
753                 filter_free(filter);
754
755         if (new_attrs) {
756                 if (new_attrs != attrs) 
757                         free(new_attrs); 
758         }
759
760         if (attrs)
761                 free(attrs); 
762
763         if (tempstr.bv_val ) {
764                 free(tempstr.bv_val);
765         }
766         ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
767         cm->threads--; 
768 #ifdef NEW_LOGGING
769         LDAP_LOG( BACK_META, DETAIL1, "Threads-- = %d\n", cm->threads, 0, 0 ); 
770 #else /* !NEW_LOGGING */
771         Debug( LDAP_DEBUG_ANY, "Threads-- = %d\n", cm->threads, 0, 0 ); 
772 #endif /* !NEW_LOGGING */
773         ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
774         return rc;
775 }
776
777
778 static Entry* 
779 meta_create_entry (
780         Backend                 *be,
781         struct metaconn         *lc,
782         int                     target,
783         LDAPMessage             *e,
784         struct exception*       result
785 )
786 {
787         struct metainfo         *li = ( struct metainfo * )be->be_private;
788         struct berval           a, mapped;
789         Entry*                  ent;
790         BerElement              ber = *e->lm_ber;
791         Attribute               *attr, **attrp;
792         struct berval           dummy = { 0, NULL };
793         struct berval           *bv, bdn;
794         const char              *text;
795         char*                   ename = NULL; 
796         if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) {
797                 result->type = CREATE_ENTRY_ERR;        
798                 return NULL; 
799         }
800         ent = (Entry*)malloc(sizeof(Entry)); 
801
802         /*
803          * Rewrite the dn of the result, if needed
804          */
805         rewriteSession( li->targets[ target ]->rwinfo, "searchResult",
806                         bdn.bv_val, lc->conn, &ent->e_name.bv_val, result );  
807
808         if (result->type != SUCCESS) {
809                 return NULL; 
810         }
811         if ( ent->e_name.bv_val == NULL ) {
812                 ber_dupbv(&(ent->e_name), &bdn);
813         } else {
814 #ifdef NEW_LOGGING
815                 LDAP_LOG( BACK_META, DETAIL1,
816                         "[rw] searchResult[%d]: \"%s\" -> \"%s\"\n",
817                         target, bdn.bv_val, ent->e_name.bv_val );
818 #else /* !NEW_LOGGING */
819                 Debug( LDAP_DEBUG_ARGS, "rw> searchResult[%d]: \"%s\""
820                         " -> \"%s\"\n",
821                         target, bdn.bv_val, ent->e_name.bv_val );
822 #endif /* !NEW_LOGGING */
823                 ent->e_name.bv_len = strlen( ent->e_name.bv_val );
824         }
825                 
826         /*
827          * Note: this may fail if the target host(s) schema differs
828          * from the one known to the meta, and a DN with unknown
829          * attributes is returned.
830          * 
831          * FIXME: should we log anything, or delegate to dnNormalize2?
832          */
833         dnNormalize2( NULL, &ent->e_name, &ent->e_nname ); 
834
835         /*
836         if ( dnNormalize2( NULL, &ent->e_name, &ent->e_nname ) != LDAP_SUCCESS ) {
837                 return LDAP_INVALID_DN_SYNTAX;
838         }
839         */
840
841         /*
842          * cache dn
843          */
844         if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
845                 meta_dncache_update_entry( &li->cache, &ent->e_nname, target );
846         }
847
848         ent->e_id = 0;
849         ent->e_attrs = 0;
850         ent->e_private = 0;
851         ent->e_bv.bv_val = 0; 
852
853         attrp = &ent->e_attrs;
854
855         while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
856                 ldap_back_map( &li->targets[ target ]->at_map, &a, &mapped, 1 );
857                 if ( mapped.bv_val == NULL ) {
858                         continue;
859                 }
860                 attr = ( Attribute * )ch_malloc( sizeof( Attribute ) );
861                 if ( attr == NULL ) {
862                         continue;
863                 }
864                 attr->a_flags = 0;
865                 attr->a_next = 0;
866                 attr->a_desc = NULL;
867                 if ( slap_bv2ad( &mapped, &attr->a_desc, &text ) != LDAP_SUCCESS) {
868                         if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text ) 
869                                         != LDAP_SUCCESS) {
870 #ifdef NEW_LOGGING
871                                 LDAP_LOG( BACK_META, DETAIL1,
872                                         "slap_bv2undef_ad(%s): %s\n",
873                                         mapped.bv_val, text, 0 );
874 #else /* !NEW_LOGGING */
875                                 Debug( LDAP_DEBUG_ANY,
876                                         "slap_bv2undef_ad(%s): "
877                                         "%s\n%s", mapped.bv_val, text, "" );
878 #endif /* !NEW_LOGGING */
879                                 ch_free( attr );
880                                 continue;
881                         }
882                 }
883
884                 /* no subschemaSubentry */
885                 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) {
886                         ch_free(attr);
887                         continue;
888                 }
889
890                 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR 
891                                 || attr->a_vals == NULL ) {
892                         attr->a_vals = &dummy;
893                 } else if ( attr->a_desc == slap_schema.si_ad_objectClass ||
894                                 attr->a_desc ==
895                                 slap_schema.si_ad_structuralObjectClass) {
896                         int i, last;
897                         for ( last = 0; attr->a_vals[ last ].bv_val; ++last )
898                                 ;
899                         for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++,i++ ) {
900                                 ldap_back_map( &li->targets[ target]->oc_map,
901                                                 bv, &mapped, 1 );
902                                 if ( mapped.bv_val == NULL ) {
903                                         free( bv->bv_val );
904                                         bv->bv_val = NULL;
905                                         if ( --last < 0 ) {
906                                                 break;
907                                         }
908                                         *bv = attr->a_vals[ last ];
909                                         attr->a_vals[ last ].bv_val = NULL;
910                                         i--;
911                                 } else if ( mapped.bv_val != bv->bv_val ) {
912                                         free( bv->bv_val );
913                                         ber_dupbv( bv, &mapped );
914                                 }
915                         }
916                 /*
917                  * It is necessary to try to rewrite attributes with
918                  * dn syntax because they might be used in ACLs as
919                  * members of groups; since ACLs are applied to the
920                  * rewritten stuff, no dn-based subecj clause could
921                  * be used at the ldap backend side (see
922                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
923                  * The problem can be overcome by moving the dn-based
924                  * ACLs to the target directory server, and letting
925                  * everything pass thru the ldap backend.
926                  */
927                 } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid,
928                                 SLAPD_DN_SYNTAX ) == 0 ) {
929                         int i;
930                         for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++,i++ ) {
931                                 char *newval;
932                                 rewriteSession(li->targets[ target ]->rwinfo,
933                                                 "searchResult", bv->bv_val,
934                                                 lc->conn, &newval, result); 
935                                 if (result->type != SUCCESS) {
936                                         /* FIXME : Handle error */
937                                         result->type = SUCCESS; 
938                                 } else {
939                                         /* left as is */
940                                         if ( newval == NULL ) {
941                                                 break;
942                                         }
943 #ifdef NEW_LOGGING
944                                         LDAP_LOG( BACK_META, DETAIL1,
945                                                 "[rw] searchResult on "
946                                                 "attr=%s: \"%s\" -> \"%s\"\n",
947                                                 attr->a_desc->ad_type->
948                                                 sat_cname.bv_val,
949                                                 bv->bv_val, newval );
950 #else /* !NEW_LOGGING */
951                                         Debug( LDAP_DEBUG_ARGS,
952                                                 "rw> searchResult on attr=%s:"
953                                                 " \"%s\" -> \"%s\"\n",
954                                                 attr->a_desc->ad_type->
955                                                 sat_cname.bv_val,
956                                                 bv->bv_val, newval );
957 #endif /* !NEW_LOGGING */
958                                         free( bv->bv_val );
959                                         bv->bv_val = newval;
960                                         bv->bv_len = strlen( newval );
961                                 }
962                         }
963                 }
964                 *attrp = attr;
965                 attrp = &attr->a_next;
966         }
967         return ent; 
968 }
969
970 static int
971 is_one_level_rdn(
972         const char      *rdn,
973         int             from
974 )
975 {
976         for ( ; from--; ) {
977                 if ( DN_SEPARATOR( rdn[ from ] ) ) {
978                         return 0;
979                 }
980         }
981         return 1;
982 }
983
984 static struct metaconn*  
985 metaConnect(
986         struct metainfo* li, 
987         Connection* conn, 
988         Operation* op, 
989         int op_type, 
990         struct berval* nbase, 
991         struct exception* result)
992 {
993         struct metaconn* lc; 
994         result->type = SUCCESS; 
995         lc = meta_back_getconn( li, conn, op, op_type, nbase, NULL );
996         if (!lc) {
997                 result->type = CONN_ERR; 
998                 return 0; 
999         }
1000         return lc; 
1001 }
1002
1003 static void
1004 add_filter_attrs(
1005         AttributeName** new_attrs, 
1006         AttributeName* attrs, 
1007         AttributeName* filter_attrs )
1008 {
1009         struct berval all_user = { sizeof(LDAP_ALL_USER_ATTRIBUTES) -1,
1010                                    LDAP_ALL_USER_ATTRIBUTES };
1011
1012         struct berval all_op = { sizeof(LDAP_ALL_OPERATIONAL_ATTRIBUTES) -1,
1013                                         LDAP_ALL_OPERATIONAL_ATTRIBUTES}; 
1014
1015         int alluser = 0; 
1016         int allop = 0; 
1017         int i; 
1018         int count; 
1019
1020         /* duplicate attrs */
1021         for (count=0; attrs[count].an_name.bv_val; count++) 
1022                 ;
1023         *new_attrs =  (AttributeName*)(malloc((count+1)*sizeof(AttributeName))); 
1024         for (i=0; i<count; i++) {
1025                 /*
1026                 ber_dupbv(&((*new_attrs)[i].an_name), &(attrs[i].an_name)); 
1027                 */
1028                 (*new_attrs)[i].an_name = attrs[i].an_name; 
1029                 (*new_attrs)[i].an_desc = attrs[i].an_desc;  
1030         }
1031         (*new_attrs)[count].an_name.bv_val = NULL; 
1032         (*new_attrs)[count].an_name.bv_len = 0; 
1033
1034
1035         if ((*new_attrs)[0].an_name.bv_val == NULL) {
1036                 *new_attrs = (AttributeName*)(malloc(2*sizeof(AttributeName))); 
1037                 (*new_attrs)[0].an_name.bv_val = "*"; 
1038                 (*new_attrs)[0].an_name.bv_len = 1; 
1039                 (*new_attrs)[1].an_name.bv_val = NULL; 
1040                 (*new_attrs)[1].an_name.bv_len = 0; 
1041                 alluser = 1; 
1042                 count = 1; 
1043         } else {
1044                 alluser = an_find(*new_attrs, &all_user); 
1045                 allop = an_find(*new_attrs, &all_op); 
1046         }
1047
1048         for ( i=0; filter_attrs[i].an_name.bv_val; i++ ) {
1049                 if ( an_find(*new_attrs, &filter_attrs[i].an_name ))
1050                         continue; 
1051                 if ( is_at_operational(filter_attrs[i].an_desc->ad_type)
1052                                                 && allop )
1053                         continue; 
1054                 else if (alluser) 
1055                         continue; 
1056                 *new_attrs = (AttributeName*)(realloc(*new_attrs,
1057                                         (count+2)*sizeof(AttributeName))); 
1058                 (*new_attrs)[count].an_name.bv_val =
1059                                 filter_attrs[i].an_name.bv_val; 
1060                 (*new_attrs)[count].an_name.bv_len =
1061                                 filter_attrs[i].an_name.bv_len; 
1062                 (*new_attrs)[count].an_desc = filter_attrs[i].an_desc; 
1063                 (*new_attrs)[count+1].an_name.bv_val = NULL; 
1064                 (*new_attrs)[count+1].an_name.bv_len = 0; 
1065                 count++; 
1066         }
1067 }
1068
1069 static int 
1070 handleLdapResult(
1071         struct metaconn* lc,
1072         Operation* op, 
1073         int* msgid, Backend* be, 
1074         AttributeName* attrs, 
1075         int attrsonly, 
1076         int candidates, 
1077         int cacheable, 
1078         Entry*** entry_array, 
1079         int curr_limit, 
1080         int slimit,
1081         struct exception* result)
1082 {
1083         Entry  *entry;
1084         char *match = NULL, *err = NULL, *cache_ename = NULL;
1085         int sres; 
1086         int mres = LDAP_SUCCESS; 
1087         int num_entries = 0, count, i, rc;     
1088         struct timeval tv = {0, 0}; 
1089         struct metasingleconn* lsc; 
1090         struct metainfo         *li = ( struct metainfo * )be->be_private;
1091         result->rc = 0; 
1092         result->type = SUCCESS; 
1093
1094         for ( count = 0, rc = 0; candidates > 0; ) {
1095                 int ab, gotit = 0;
1096
1097                 /* check for abandon */
1098                 ab = op->o_abandon;
1099
1100                 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); lsc++, i++ ) {
1101                         if ( lsc->candidate != META_CANDIDATE ) {
1102                                 continue;
1103                         }
1104
1105                         if ( ab ) {
1106                                 ldap_abandon( lsc->ld, msgid[ i ] );
1107                                 result->type = ABANDON_ERR;
1108                                 break; 
1109                         }
1110
1111                         if ( slimit > 0 && num_entries == slimit ) {
1112                                 result->type = SLIMIT_ERR; 
1113                                 break; 
1114                         }
1115
1116                         if ((entry = get_result_entry(be, lc, lsc,
1117                                                 msgid, i, &tv, result))) { 
1118                                 send_search_entry( be, lc->conn, op, entry,
1119                                                 attrs, attrsonly, NULL );
1120                                 if ((cacheable) &&
1121                                                 (num_entries < curr_limit))  {
1122                                         rewriteSession( li->rwinfo,
1123                                                         "cacheResult",
1124                                                         entry->e_name.bv_val,
1125                                                         lc->conn,
1126                                                         &cache_ename, result );  
1127                                         free(entry->e_name.bv_val); 
1128                                         if (result->type != SUCCESS) {
1129                                                 return 0; 
1130                                         }
1131                                         ber_str2bv(cache_ename,
1132                                                 strlen(cache_ename),
1133                                                 0, &entry->e_name); 
1134                                         ber_dupbv(&entry->e_nname,
1135                                                 &entry->e_name); 
1136                                         *entry_array = (Entry**)realloc(
1137                                                         *entry_array,
1138                                                         (( num_entries+2 ) *
1139                                                          sizeof( Entry* )));
1140                                         (*entry_array)[num_entries] = entry;    
1141                                         (*entry_array)[num_entries+1] = NULL;
1142                                 }
1143                                 num_entries++; 
1144                                 gotit = 1; 
1145                         } else if (result->type == REWRITING_ERR) {
1146                                 return 0; 
1147                         } else if (result->type == TIMEOUT_ERR) {
1148                                 result->type = SUCCESS; 
1149                                 continue;  
1150                         } else if (result->type == CREATE_ENTRY_ERR) {
1151                                 break; 
1152                         } else if (result->rc == -1) {
1153                                 break; 
1154                         } else {
1155                                 sres = ldap_back_map_result(result->rc);
1156                                 if (mres == LDAP_SUCCESS &&
1157                                                 sres != LDAP_SUCCESS) {
1158                                         mres = sres; 
1159                                         ldap_get_option(lsc->ld,
1160                                                 LDAP_OPT_ERROR_STRING, &err);
1161                                         ldap_get_option(lsc->ld,
1162                                                 LDAP_OPT_MATCHED_DN, &match);
1163                                 }
1164                                 lsc->candidate = META_NOT_CANDIDATE; 
1165                                 candidates--; 
1166                                 result->type = SUCCESS; 
1167                         }
1168                 }
1169                 switch (result->type) {
1170                 case RESULT_ERR: 
1171 #ifdef NEW_LOGGING
1172                         LDAP_LOG( BACK_META, DETAIL1,
1173                                         "ldap_result error, rc = -1\n",
1174                                         0, 0, 0 );
1175 #else /* !NEW_LOGGING */
1176                         Debug( LDAP_DEBUG_ANY, "ldap_result error, rc = -1\n",
1177                                         0, 0, 0 );
1178 #endif /* !NEW_LOGGING */
1179                         send_search_result( lc->conn, op, LDAP_OTHER, NULL,
1180                                         NULL, NULL, NULL, num_entries );
1181                         return 0; 
1182                 case CREATE_ENTRY_ERR: 
1183 #ifdef NEW_LOGGING
1184                         LDAP_LOG( BACK_META, DETAIL1,
1185                                         "Error in parsing result \n",
1186                                         0, 0, 0 );
1187 #else /* !NEW_LOGGING */
1188                         Debug( LDAP_DEBUG_ANY, "Error in parsing result \n",
1189                                         0, 0, 0 );
1190 #endif /* !NEW_LOGGING */
1191                         send_search_result( lc->conn, op, LDAP_OTHER, NULL,
1192                                         NULL, NULL, NULL, num_entries );
1193                         result->type = RESULT_ERR; 
1194                         return 0; 
1195                 case SLIMIT_ERR: 
1196 #ifdef NEW_LOGGING
1197                         LDAP_LOG( BACK_META, DETAIL1, "Size limit exceeded \n",
1198                                         0, 0, 0 );
1199 #else /* !NEW_LOGGING */
1200                         Debug( LDAP_DEBUG_ANY, "Size limit exceeded \n",
1201                                         0, 0, 0 );
1202 #endif /* !NEW_LOGGING */
1203                         send_search_result( lc->conn, op,
1204                                         LDAP_SIZELIMIT_EXCEEDED,
1205                                         NULL, NULL, NULL, NULL, num_entries );
1206                         result->type = RESULT_ERR; 
1207                         return 0; 
1208                 case ABANDON_ERR: 
1209 #ifdef NEW_LOGGING
1210                         LDAP_LOG( BACK_META, DETAIL1,
1211                                         "search operation abandoned \n",
1212                                         0, 0, 0 );
1213 #else /* !NEW_LOGGING */
1214                         Debug( LDAP_DEBUG_ANY, "search operation abandoned \n",
1215                                         0, 0, 0 );
1216 #endif /* !NEW_LOGGING */
1217                         result->type = RESULT_ERR; 
1218                         return 0; 
1219                 default:
1220                         /* assert( 0 ); */
1221                 }
1222                 if ( gotit == 0 ) {
1223                         tv.tv_sec = 0;
1224                         tv.tv_usec = 100000;
1225                         ldap_pvt_thread_yield();
1226                 } else {
1227                         tv.tv_sec = 0;
1228                         tv.tv_usec = 0;
1229                 }
1230         }
1231
1232         send_search_result( lc->conn, op, mres, match, err,
1233                                 NULL, NULL, num_entries );
1234
1235         if (err) 
1236                 free(err); 
1237
1238         if (match) 
1239                 free(match); 
1240     
1241         result->type = (mres == LDAP_SUCCESS) ? SUCCESS : RESULT_ERR; 
1242         return num_entries; 
1243 }
1244
1245 static Entry* 
1246 get_result_entry(
1247         Backend* be, 
1248         struct metaconn* lc, 
1249         struct metasingleconn* lsc, 
1250         int* msgid,
1251         int i, 
1252         struct timeval* tv, 
1253         struct exception* result)
1254 {
1255         Entry* entry; 
1256         LDAPMessage     *res, *e; 
1257         int rc; 
1258         int sres = LDAP_SUCCESS; 
1259
1260         rc = ldap_result( lsc->ld, msgid[ i ],
1261                         0, tv, &res );
1262
1263         if ( rc == 0 ) {
1264                 result->type = TIMEOUT_ERR; 
1265                 return NULL; 
1266         } else if ( rc == -1 ) {
1267                 result->rc = -1; 
1268                 result->type = RESULT_ERR; 
1269                 return NULL; 
1270         } else if ( rc == LDAP_RES_SEARCH_ENTRY ) {
1271                 e = ldap_first_entry( lsc->ld, res );
1272                 entry = meta_create_entry(be, lc, i, e, result);  
1273                 if (!entry) {
1274                         return NULL; 
1275                 }    
1276                 ldap_msgfree( res );
1277                 result->type = SUCCESS; 
1278                 return entry; 
1279         } else {
1280                 sres = ldap_result2error( lsc->ld,
1281                                 res, 1 );
1282                 result->rc = sres; 
1283                 result->type = RESULT_ERR; 
1284                 return NULL; 
1285         }
1286 }       
1287
1288 static void
1289 rewriteSession(
1290         struct rewrite_info* info, 
1291         const char* rewriteContext, 
1292         const char* string, 
1293         const void* cookie,  
1294         char** base, 
1295         struct exception* result)
1296 {
1297         int rc = rewrite_session(info, rewriteContext, string, cookie, base); 
1298         if (rc != REWRITE_REGEXEC_OK) {
1299                 result->rc = rc; 
1300                 result->type = REWRITING_ERR; 
1301
1302                 if (strcmp(rewriteContext, "searchBase") == 0) 
1303 #ifdef NEW_LOGGING
1304                         LDAP_LOG( BACK_META, DETAIL1,
1305                                 "Problem in rewriting search base\n", 0, 0, 0 );
1306 #else /* !NEW_LOGGING */
1307                         Debug( LDAP_DEBUG_ANY,
1308                                 "Problem in rewriting search base\n", 0, 0, 0 );
1309 #endif /* !NEW_LOGGING */
1310                 if (strcmp(rewriteContext, "searchFilter") == 0) 
1311 #ifdef NEW_LOGGING
1312                         LDAP_LOG( BACK_META, DETAIL1,
1313                                 "Problem in rewriting search filter\n",
1314                                 0, 0, 0 );
1315 #else /* !NEW_LOGGING */
1316                         Debug( LDAP_DEBUG_ANY,
1317                                 "Problem in rewriting search filter\n",
1318                                 0, 0, 0 );
1319 #endif /* !NEW_LOGGING */
1320                 if (strcmp(rewriteContext, "searchResult") == 0) 
1321 #ifdef NEW_LOGGING
1322                         LDAP_LOG( BACK_META, DETAIL1,
1323                                 "Problem in rewriting DN, or DN syntax "
1324                                 "attributes of search result\n", 0, 0, 0 );
1325 #else /* !NEW_LOGGING */
1326                         Debug( LDAP_DEBUG_ANY,
1327                                 "Problem in rewriting DN, or DN syntax "
1328                                 "attributes of search result\n", 0, 0, 0 );
1329 #endif /* !NEW_LOGGING */
1330                 if (strcmp(rewriteContext, "cacheBase") == 0) 
1331 #ifdef NEW_LOGGING
1332                         LDAP_LOG( BACK_META, DETAIL1,
1333                                 "Problem in rewriting search base with "
1334                                 "cache base\n", 0, 0, 0 );
1335 #else /* !NEW_LOGGING */
1336                         Debug( LDAP_DEBUG_ANY,
1337                                 "Problem in rewriting search base with "
1338                                 "cache base\n", 0, 0, 0 );
1339 #endif /* !NEW_LOGGING */
1340                 if (strcmp(rewriteContext, "cacheResult") == 0) 
1341 #ifdef NEW_LOGGING
1342                         LDAP_LOG( BACK_META, DETAIL1,
1343                                 "Problem in rewriting DN for cached entries\n",
1344                                 0, 0, 0 );
1345 #else /* !NEW_LOGGING */
1346                         Debug( LDAP_DEBUG_ANY,
1347                                 "Problem in rewriting DN for cached entries\n",
1348                                 0, 0, 0 );
1349 #endif /* !NEW_LOGGING */
1350                 if (strcmp(rewriteContext, "cacheReturn") == 0) 
1351 #ifdef NEW_LOGGING
1352                         LDAP_LOG( BACK_META, DETAIL1,
1353                                 "Problem in rewriting DN for answerable "
1354                                 "entries\n", 0, 0, 0 );
1355 #else /* !NEW_LOGGING */
1356                         Debug( LDAP_DEBUG_ANY,
1357                                 "Problem in rewriting DN for answerable "
1358                                 "entries\n", 0, 0, 0 );
1359 #endif /* !NEW_LOGGING */
1360         } else {
1361                 result->type = SUCCESS;
1362         }
1363 }
1364
1365 static int 
1366 get_attr_set(
1367         AttributeName* attrs, 
1368         query_manager* qm, 
1369         int num )
1370 {
1371         int i; 
1372         for (i=0; i<num; i++) {
1373                 if (attrscmp(attrs, qm->attr_sets[i].attrs)) 
1374                         return i;
1375         }
1376         return -1; 
1377 }
1378
1379 static int 
1380 attrscmp(
1381         AttributeName* attrs_in, 
1382         AttributeName* attrs)
1383 {
1384         int i, count1, count2; 
1385         if ((attrs_in==NULL) || (attrs==NULL)) 
1386                 return 1; 
1387         for ( count1=0;
1388               attrs_in && attrs_in[count1].an_name.bv_val != NULL;
1389               count1++ )
1390                 ;
1391         for ( count2=0;
1392               attrs && attrs[count2].an_name.bv_val != NULL;
1393               count2++) 
1394                 ;
1395         if ( count1 != count2 )
1396                 return 0; 
1397
1398         for ( i=0; i<count1; i++ ) {
1399                 if ( !an_find(attrs, &attrs_in[i].an_name ))
1400                         return 0; 
1401         }
1402         return 1; 
1403 }
1404
1405 static char* 
1406 cache_entries(
1407         Entry** entry_array, 
1408         cache_manager* cm, 
1409         Backend* be, 
1410         Connection* conn, 
1411         struct exception* result)
1412 {
1413         int i; 
1414         int return_val; 
1415         int cache_size; 
1416         Entry* e; 
1417         struct berval query_uuid; 
1418         struct berval crp_uuid; 
1419         char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ], *crpid; 
1420         char crpuuid[40]; 
1421         query_manager* qm = cm->qm;
1422     
1423         result->type = SUCCESS; 
1424         query_uuid.bv_len = lutil_uuidstr(uuidbuf, sizeof(uuidbuf)); 
1425         query_uuid.bv_val = ch_strdup(uuidbuf);
1426
1427 #ifdef NEW_LOGGING
1428         LDAP_LOG( BACK_META, DETAIL1, "UUID for query being added = %s\n",
1429                         uuidbuf, 0, 0 );
1430 #else /* !NEW_LOGGING */
1431         Debug( LDAP_DEBUG_ANY, "UUID for query being added = %s\n",
1432                         uuidbuf, 0, 0 );
1433 #endif /* !NEW_LOGGING */
1434         
1435         for ( i=0; ( entry_array && (e=entry_array[i]) ); i++ ) {
1436 #ifdef NEW_LOGGING
1437                 LDAP_LOG( BACK_META, DETAIL2, "LOCKING REMOVE MUTEX\n",
1438                                 0, 0, 0 );
1439 #else /* !NEW_LOGGING */
1440                 Debug( LDAP_DEBUG_NONE, "LOCKING REMOVE MUTEX\n", 0, 0, 0 );
1441 #endif /* !NEW_LOGGING */
1442                 ldap_pvt_thread_mutex_lock(&cm->remove_mutex); 
1443 #ifdef NEW_LOGGING
1444                 LDAP_LOG( BACK_META, DETAIL2, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
1445 #else /* !NEW_LOGGING */
1446                 Debug( LDAP_DEBUG_NONE, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
1447 #endif /* !NEW_LOGGING */
1448                 if ( cm->cache_size > (cm->thresh_hi) ) {
1449                         while(cm->cache_size > (cm->thresh_lo)) {
1450                                 crpid = cache_replacement(qm);
1451                                 if (crpid == NULL) {
1452                                         result->type = REMOVE_ERR; 
1453                                 } else {
1454                                         strcpy(crpuuid, crpid); 
1455                                         crp_uuid.bv_val = crpuuid; 
1456                                         crp_uuid.bv_len = strlen(crpuuid); 
1457 #ifdef NEW_LOGGING
1458                                         LDAP_LOG( BACK_META, DETAIL1,
1459                                                 "Removing query UUID %s\n",
1460                                                 crpuuid, 0, 0 );
1461 #else /* !NEW_LOGGING */
1462                                         Debug( LDAP_DEBUG_ANY,
1463                                                 "Removing query UUID %s\n",
1464                                                 crpuuid, 0, 0 );
1465 #endif /* !NEW_LOGGING */
1466                                         return_val = remove_query_data(be, conn,
1467                                                         &crp_uuid, result); 
1468 #ifdef NEW_LOGGING
1469                                         LDAP_LOG( BACK_META, DETAIL1,
1470                                                 "QUERY REMOVED, SIZE=%d\n",
1471                                                 return_val, 0, 0);
1472 #else /* !NEW_LOGGING */
1473                                         Debug( LDAP_DEBUG_ANY,
1474                                                 "QUERY REMOVED, SIZE=%d\n",
1475                                                 return_val, 0, 0);
1476 #endif /* !NEW_LOGGING */
1477                                         ldap_pvt_thread_mutex_lock(
1478                                                         &cm->cache_mutex ); 
1479                                         cm->total_entries -= result->rc; 
1480                                         cm->num_cached_queries--; 
1481 #ifdef NEW_LOGGING
1482                                         LDAP_LOG( BACK_META, DETAIL1,
1483                                                 "STORED QUERIES = %d\n",
1484                                                 cm->num_cached_queries, 0, 0 );
1485 #else /* !NEW_LOGGING */
1486                                         Debug( LDAP_DEBUG_ANY,
1487                                                 "STORED QUERIES = %d\n",
1488                                                 cm->num_cached_queries, 0, 0 );
1489 #endif /* !NEW_LOGGING */
1490                                         ldap_pvt_thread_mutex_unlock(
1491                                                         &cm->cache_mutex );
1492                                         cm->cache_size = (return_val >
1493                                                 cm->cache_size) ?
1494                                                 0 : (cm->cache_size-return_val);
1495 #ifdef NEW_LOGGING
1496                                         LDAP_LOG( BACK_META, DETAIL1,
1497                                                 "QUERY REMOVED, CACHE SIZE="
1498                                                 "%d bytes %d entries\n",
1499                                                 cm->cache_size,
1500                                                 cm->total_entries, 0 );
1501 #else /* !NEW_LOGGING */
1502                                         Debug( LDAP_DEBUG_ANY,
1503                                                 "QUERY REMOVED, CACHE SIZE="
1504                                                 "%d bytes %d entries\n",
1505                                                 cm->cache_size,
1506                                                 cm->total_entries, 0 );
1507 #endif /* !NEW_LOGGING */
1508                                 }
1509                         }
1510                 }
1511                 return_val = merge_entry(be, conn, e, &query_uuid, result);
1512                 cm->cache_size += return_val;
1513 #ifdef NEW_LOGGING
1514                 LDAP_LOG( BACK_META, DETAIL1,
1515                         "ENTRY ADDED/MERGED, CACHE SIZE=%d bytes\n",
1516                         cm->cache_size, 0, 0 );
1517 #else /* !NEW_LOGGING */
1518                 Debug( LDAP_DEBUG_ANY,
1519                         "ENTRY ADDED/MERGED, CACHE SIZE=%d bytes\n",
1520                         cm->cache_size, 0, 0 );
1521 #endif /* !NEW_LOGGING */
1522 #ifdef NEW_LOGGING
1523                 LDAP_LOG( BACK_META, DETAIL2, "UNLOCKING REMOVE MUTEX\n",
1524                                 0, 0, 0 );
1525 #else /* !NEW_LOGGING */
1526                 Debug( LDAP_DEBUG_NONE, "UNLOCKING REMOVE MUTEX\n", 0, 0, 0 );
1527 #endif /* !NEW_LOGGING */
1528                 ldap_pvt_thread_mutex_unlock(&cm->remove_mutex); 
1529 #ifdef NEW_LOGGING
1530                 LDAP_LOG( BACK_META, DETAIL2, "UNLOCKED REMOVE MUTEX\n",
1531                                 0, 0, 0 );
1532 #else /* !NEW_LOGGING */
1533                 Debug( LDAP_DEBUG_NONE, "UNLOCKED REMOVE MUTEX\n", 0, 0, 0 );
1534 #endif /* !NEW_LOGGING */
1535                 if (result->type != SUCCESS) 
1536                         return 0; 
1537                 ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
1538                 cm->total_entries += result->rc; 
1539 #ifdef NEW_LOGGING
1540                 LDAP_LOG( BACK_META, DETAIL1,
1541                         "ENTRY ADDED/MERGED, SIZE=%d, CACHED ENTRIES=%d\n",
1542                         return_val, cm->total_entries, 0 );
1543 #else /* !NEW_LOGGING */
1544                 Debug( LDAP_DEBUG_ANY,
1545                         "ENTRY ADDED/MERGED, SIZE=%d, CACHED ENTRIES=%d\n",
1546                         return_val, cm->total_entries, 0 );
1547 #endif /* !NEW_LOGGING */
1548                 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
1549         }
1550         ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
1551         cm->num_cached_queries++; 
1552 #ifdef NEW_LOGGING
1553         LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %d\n",
1554                         cm->num_cached_queries, 0, 0 );
1555 #else /* !NEW_LOGGING */
1556         Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %d\n",
1557                         cm->num_cached_queries, 0, 0 );
1558 #endif /* !NEW_LOGGING */
1559         ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
1560
1561         return query_uuid.bv_val; 
1562 }
1563
1564 static int 
1565 is_temp_answerable(
1566         int attr_set, 
1567         struct berval* tempstr, 
1568         query_manager* qm, 
1569         int template_id )
1570 {
1571         int i; 
1572         int* id_array; 
1573         char* str;
1574         int result = 0; 
1575         i = qm->templates[template_id].attr_set_index; 
1576         str = qm->templates[template_id].querystr; 
1577
1578         if (attr_set == i) {
1579                 result = 1; 
1580         } else { 
1581                 id_array = qm->attr_sets[attr_set].ID_array;    
1582
1583                 while (*id_array != -1) {
1584                         if (*id_array == i) 
1585                                 result = 1; 
1586                         id_array++; 
1587                 }
1588         }
1589         if (!result) 
1590                 return 0; 
1591         if (strcasecmp(str, tempstr->bv_val) == 0)  
1592                 return 1; 
1593         return 0; 
1594 }
1595
1596 static void 
1597 consistency_check(Backend* be, Backend* glue_be, Connection* conn)
1598 {
1599         struct metainfo *li = ( struct metainfo * )be->be_private;
1600         cache_manager*  cm = li->cm; 
1601         query_manager* qm = cm->qm; 
1602         CachedQuery* query, *query_prev; 
1603         time_t curr_time; 
1604         struct berval uuid;  
1605         struct exception result; 
1606         int i, return_val; 
1607         QueryTemplate* templ; 
1608     
1609       
1610         for (i=0; qm->templates[i].querystr; i++) {
1611                 templ = qm->templates + i; 
1612                 query = templ->query_last; 
1613                 curr_time = slap_get_time(); 
1614                 ldap_pvt_thread_mutex_lock(&cm->remove_mutex); 
1615                 while (query && (query->expiry_time < curr_time)) {
1616                         ldap_pvt_thread_mutex_lock(&qm->lru_mutex); 
1617                         remove_query(qm, query); 
1618                         ldap_pvt_thread_mutex_unlock(&qm->lru_mutex); 
1619 #ifdef NEW_LOGGING
1620                         LDAP_LOG( BACK_META, DETAIL1, "Lock CR index = %d\n",
1621                                         i, 0, 0 );
1622 #else /* !NEW_LOGGING */
1623                         Debug( LDAP_DEBUG_ANY, "Lock CR index = %d\n",
1624                                         i, 0, 0 );
1625 #endif /* !NEW_LOGGING */
1626                         ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);  
1627                         remove_from_template(query, templ); 
1628 #ifdef NEW_LOGGING
1629                         LDAP_LOG( BACK_META, DETAIL1,
1630                                         "TEMPLATE %d QUERIES-- %d\n",
1631                                         i, templ->no_of_queries, 0 );
1632 #else /* !NEW_LOGGING */
1633                         Debug( LDAP_DEBUG_ANY, "TEMPLATE %d QUERIES-- %d\n",
1634                                         i, templ->no_of_queries, 0 );
1635 #endif /* !NEW_LOGGING */
1636 #ifdef NEW_LOGGING
1637                         LDAP_LOG( BACK_META, DETAIL1, "Unlock CR index = %d\n",
1638                                         i, 0, 0 );
1639 #else /* !NEW_LOGGING */
1640                         Debug( LDAP_DEBUG_ANY, "Unlock CR index = %d\n",
1641                                         i, 0, 0 );
1642 #endif /* !NEW_LOGGING */
1643                         ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);  
1644                         uuid.bv_val = query->q_uuid; 
1645                         uuid.bv_len = strlen(query->q_uuid); 
1646                         return_val = remove_query_data(glue_be, conn,
1647                                                 &uuid, &result); 
1648 #ifdef NEW_LOGGING
1649                         LDAP_LOG( BACK_META, DETAIL1,
1650                                         "STALE QUERY REMOVED, SIZE=%d\n",
1651                                         return_val, 0, 0 );
1652 #else /* !NEW_LOGGING */
1653                         Debug( LDAP_DEBUG_ANY, "STALE QUERY REMOVED, SIZE=%d\n",
1654                                                 return_val, 0, 0 );
1655 #endif /* !NEW_LOGGING */
1656                         ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
1657                         cm->total_entries -= result.rc; 
1658                         cm->num_cached_queries--; 
1659 #ifdef NEW_LOGGING
1660                         LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %d\n",
1661                                         cm->num_cached_queries, 0, 0 );
1662 #else /* !NEW_LOGGING */
1663                         Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %d\n",
1664                                         cm->num_cached_queries, 0, 0 );
1665 #endif /* !NEW_LOGGING */
1666                         ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
1667                         cm->cache_size = (return_val > cm->cache_size) ?
1668                                                 0: (cm->cache_size-return_val);
1669 #ifdef NEW_LOGGING
1670                         LDAP_LOG( BACK_META, DETAIL1,
1671                                 "STALE QUERY REMOVED, CACHE SIZE=%d bytes %d "
1672                                 "entries\n", cm->cache_size,
1673                                 cm->total_entries, 0 );
1674 #else /* !NEW_LOGGING */
1675                         Debug( LDAP_DEBUG_ANY,
1676                                 "STALE QUERY REMOVED, CACHE SIZE=%d bytes %d "
1677                                 "entries\n", cm->cache_size,
1678                                 cm->total_entries, 0 );
1679 #endif /* !NEW_LOGGING */
1680                         query_prev = query; 
1681                         query = query->prev; 
1682                         free_query(query_prev); 
1683                 }
1684                 ldap_pvt_thread_mutex_unlock(&cm->remove_mutex); 
1685         }
1686 }
1687
1688 static int
1689 cache_back_sentry(
1690         Backend* glue_be, 
1691         Connection* conn,
1692         Operation* op, 
1693         Entry* e, 
1694         AttributeName* attrs, 
1695         int attrsonly, 
1696         LDAPControl** ctrls )
1697
1698         slap_callback* cb = op->o_callback; 
1699         Backend* be = (Backend*)(cb->sc_private); 
1700         struct metainfo *li = ( struct metainfo * )be->be_private;
1701  
1702         char* ename = NULL; 
1703         struct exception result; 
1704         struct berval dn; 
1705         struct berval ndn; 
1706
1707         dn = e->e_name; 
1708         ndn = e->e_nname; 
1709
1710         rewriteSession( li->rwinfo,
1711                 "cacheReturn", e->e_name.bv_val, conn, &ename, &result );  
1712         ber_str2bv(ename, strlen(ename), 0, &e->e_name); 
1713         ber_dupbv(&e->e_nname, &e->e_name); 
1714
1715         op->o_callback = NULL; 
1716         send_search_entry(be, conn, op, e, attrs, attrsonly, ctrls); 
1717  
1718         e->e_name = dn; 
1719         e->e_nname = ndn; 
1720
1721         op->o_callback = cb; 
1722         return 0;  
1723 }
1724 #endif