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