]> git.sur5r.net Git - openldap/blob - servers/slapd/back-asyncmeta/dncache.c
Merge remote-tracking branch 'origin/mdb.RE/0.9'
[openldap] / servers / slapd / back-asyncmeta / dncache.c
1 /* dncache.c - dn caching for back-asyncmeta */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2016-2017 The OpenLDAP Foundation.
6  * Portions Copyright 2016 Symas Corporation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17
18 /* ACKNOWLEDGEMENTS:
19  * This work was developed by Symas Corporation
20  * based on back-meta module for inclusion in OpenLDAP Software.
21  * This work was sponsored by Ericsson. */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26 #include <ac/string.h>
27
28 #include "slap.h"
29 #include "../back-ldap/back-ldap.h"
30 #include "back-asyncmeta.h"
31
32 /*
33  * The dncache, at present, maps an entry to the target that holds it.
34  */
35
36 typedef struct metadncacheentry_t {
37         struct berval   dn;
38         int             target;
39
40         time_t          lastupdated;
41 } metadncacheentry_t;
42
43 /*
44  * asyncmeta_dncache_cmp
45  *
46  * compares two struct metadncacheentry; used by avl stuff
47  * FIXME: modify avl stuff to delete an entry based on cmp
48  * (e.g. when ttl expired?)
49  */
50 int
51 asyncmeta_dncache_cmp(
52         const void      *c1,
53         const void      *c2 )
54 {
55         metadncacheentry_t      *cc1 = ( metadncacheentry_t * )c1;
56         metadncacheentry_t      *cc2 = ( metadncacheentry_t * )c2;
57
58         /*
59          * case sensitive, because the dn MUST be normalized
60          */
61         return ber_bvcmp( &cc1->dn, &cc2->dn);
62 }
63
64 /*
65  * asyncmeta_dncache_dup
66  *
67  * returns -1 in case a duplicate struct metadncacheentry has been inserted;
68  * used by avl stuff
69  */
70 int
71 asyncmeta_dncache_dup(
72         void            *c1,
73         void            *c2 )
74 {
75         metadncacheentry_t      *cc1 = ( metadncacheentry_t * )c1;
76         metadncacheentry_t      *cc2 = ( metadncacheentry_t * )c2;
77
78         /*
79          * case sensitive, because the dn MUST be normalized
80          */
81         return ( ber_bvcmp( &cc1->dn, &cc2->dn ) == 0 ) ? -1 : 0;
82 }
83
84 /*
85  * asyncmeta_dncache_get_target
86  *
87  * returns the target a dn belongs to, or -1 in case the dn is not
88  * in the cache
89  */
90 int
91 asyncmeta_dncache_get_target(
92         a_metadncache_t *cache,
93         struct berval   *ndn )
94 {
95         metadncacheentry_t      tmp_entry,
96                                 *entry;
97         int                     target = META_TARGET_NONE;
98
99         assert( cache != NULL );
100         assert( ndn != NULL );
101
102         tmp_entry.dn = *ndn;
103         ldap_pvt_thread_mutex_lock( &cache->mutex );
104         entry = ( metadncacheentry_t * )avl_find( cache->tree,
105                         ( caddr_t )&tmp_entry, asyncmeta_dncache_cmp );
106
107         if ( entry != NULL ) {
108
109                 /*
110                  * if cache->ttl < 0, cache never expires;
111                  * if cache->ttl = 0 no cache is used; shouldn't get here
112                  * else, cache is used with ttl
113                  */
114                 if ( cache->ttl < 0 ) {
115                         target = entry->target;
116
117                 } else {
118                         if ( entry->lastupdated+cache->ttl > slap_get_time() ) {
119                                 target = entry->target;
120                         }
121                 }
122         }
123         ldap_pvt_thread_mutex_unlock( &cache->mutex );
124
125         return target;
126 }
127
128 /*
129  * asyncmeta_dncache_update_entry
130  *
131  * updates target and lastupdated of a struct metadncacheentry if exists,
132  * otherwise it gets created; returns -1 in case of error
133  */
134 int
135 asyncmeta_dncache_update_entry(
136         a_metadncache_t *cache,
137         struct berval   *ndn,
138         int             target )
139 {
140         metadncacheentry_t      *entry,
141                                 tmp_entry;
142         time_t                  curr_time = 0L;
143         int                     err = 0;
144
145         assert( cache != NULL );
146         assert( ndn != NULL );
147
148         /*
149          * if cache->ttl < 0, cache never expires;
150          * if cache->ttl = 0 no cache is used; shouldn't get here
151          * else, cache is used with ttl
152          */
153         if ( cache->ttl > 0 ) {
154                 curr_time = slap_get_time();
155         }
156
157         tmp_entry.dn = *ndn;
158
159         ldap_pvt_thread_mutex_lock( &cache->mutex );
160         entry = ( metadncacheentry_t * )avl_find( cache->tree,
161                         ( caddr_t )&tmp_entry, asyncmeta_dncache_cmp );
162
163         if ( entry != NULL ) {
164                 entry->target = target;
165                 entry->lastupdated = curr_time;
166
167         } else {
168                 entry = ch_malloc( sizeof( metadncacheentry_t ) + ndn->bv_len + 1 );
169                 if ( entry == NULL ) {
170                         err = -1;
171                         goto error_return;
172                 }
173
174                 entry->dn.bv_len = ndn->bv_len;
175                 entry->dn.bv_val = (char *)&entry[ 1 ];
176                 AC_MEMCPY( entry->dn.bv_val, ndn->bv_val, ndn->bv_len );
177                 entry->dn.bv_val[ ndn->bv_len ] = '\0';
178
179                 entry->target = target;
180                 entry->lastupdated = curr_time;
181
182                 err = avl_insert( &cache->tree, ( caddr_t )entry,
183                                 asyncmeta_dncache_cmp, asyncmeta_dncache_dup );
184         }
185
186 error_return:;
187         ldap_pvt_thread_mutex_unlock( &cache->mutex );
188
189         return err;
190 }
191
192 int
193 asyncmeta_dncache_delete_entry(
194         a_metadncache_t *cache,
195         struct berval   *ndn )
196 {
197         metadncacheentry_t      *entry,
198                                 tmp_entry;
199
200         assert( cache != NULL );
201         assert( ndn != NULL );
202
203         tmp_entry.dn = *ndn;
204
205         ldap_pvt_thread_mutex_lock( &cache->mutex );
206         entry = avl_delete( &cache->tree, ( caddr_t )&tmp_entry,
207                         asyncmeta_dncache_cmp );
208         ldap_pvt_thread_mutex_unlock( &cache->mutex );
209
210         if ( entry != NULL ) {
211                 asyncmeta_dncache_free( ( void * )entry );
212         }
213
214         return 0;
215 }
216
217 /*
218  * meta_dncache_free
219  *
220  * frees an entry
221  *
222  */
223 void
224 asyncmeta_dncache_free(
225         void            *e )
226 {
227         free( e );
228 }