1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1999-2011 The OpenLDAP Foundation.
5 * Portions Copyright 2001-2003 Pierangelo Masarati.
6 * Portions Copyright 1999-2003 Howard Chu.
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/* ACKNOWLEDGEMENTS:
18 * This work was initially developed by the Howard Chu for inclusion
19 * in OpenLDAP Software and subsequently enhanced by Pierangelo
20 * Masarati.
21 */
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-meta.h"
31
32/*
33 * The dncache, at present, maps an entry to the target that holds it.
34 */
35
36typedef struct metadncacheentry_t {
37	struct berval	dn;
38	int 		target;
39
40	time_t 		lastupdated;
41} metadncacheentry_t;
42
43/*
44 * meta_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 */
50int
51meta_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 * meta_dncache_dup
66 *
67 * returns -1 in case a duplicate struct metadncacheentry has been inserted;
68 * used by avl stuff
69 */
70int
71meta_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 * meta_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 */
90int
91meta_dncache_get_target(
92	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, meta_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 * meta_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 */
134int
135meta_dncache_update_entry(
136	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, meta_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				meta_dncache_cmp, meta_dncache_dup );
184	}
185
186error_return:;
187	ldap_pvt_thread_mutex_unlock( &cache->mutex );
188
189	return err;
190}
191
192/*
193 * meta_dncache_update_entry
194 *
195 * updates target and lastupdated of a struct metadncacheentry if exists,
196 * otherwise it gets created; returns -1 in case of error
197 */
198int
199meta_dncache_delete_entry(
200	metadncache_t	*cache,
201	struct berval	*ndn )
202{
203	metadncacheentry_t	*entry,
204				tmp_entry;
205
206	assert( cache != NULL );
207	assert( ndn != NULL );
208
209	tmp_entry.dn = *ndn;
210
211	ldap_pvt_thread_mutex_lock( &cache->mutex );
212	entry = avl_delete( &cache->tree, ( caddr_t )&tmp_entry,
213 			meta_dncache_cmp );
214	ldap_pvt_thread_mutex_unlock( &cache->mutex );
215
216	if ( entry != NULL ) {
217		meta_dncache_free( ( void * )entry );
218	}
219
220	return 0;
221}
222
223/*
224 * meta_dncache_free
225 *
226 * frees an entry
227 *
228 */
229void
230meta_dncache_free(
231	void		*e )
232{
233	free( e );
234}
235
236