xref: /freebsd/usr.sbin/nscd/cachelib.h (revision ae1f3df43466466a21c7da0df93ecb58a3e53d74)
1 /*-
2  * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #ifndef __NSCD_CACHELIB_H__
30 #define __NSCD_CACHELIB_H__
31 
32 #include "hashtable.h"
33 #include "cacheplcs.h"
34 
35 enum cache_entry_t	{
36 	CET_COMMON = 0,	/* cache item is atomic */
37 	CET_MULTIPART	/* cache item is formed part by part */
38 };
39 
40 enum cache_transformation_t {
41 	CTT_FLUSH = 0,	/* flush the cache - delete all obsolete items */
42 	CTT_CLEAR = 1	/* delete all items in the cache */
43 };
44 
45 /* cache deletion policy type enum */
46 enum cache_policy_t {
47 	CPT_FIFO = 0, 	/* first-in first-out */
48 	CPT_LRU = 1,	/* least recently used */
49 	CPT_LFU = 2 	/* least frequently used */
50 };
51 
52 /* multipart sessions can be used for reading and writing */
53 enum cache_mp_session_t {
54 	CMPT_READ_SESSION,
55 	CMPT_WRITE_SESSION
56 };
57 
58 /*
59  * When doing partial transformations of entries (which are applied for
60  * elements with keys, that contain specified buffer in its left or
61  * right part), this enum will show the needed position of the key part.
62  */
63 enum part_position_t {
64 	KPPT_LEFT,
65 	KPPT_RIGHT
66 };
67 
68 /* num_levels attribute is obsolete, i think - user can always emulate it
69  * by using one entry.
70  * get_time_func is needed to have the clocks-independent counter
71  */
72 struct cache_params {
73 	void	(*get_time_func)(struct timeval *);
74 };
75 
76 /*
77  * base structure - normal_cache_entry_params and multipart_cache_entry_params
78  * are "inherited" from it
79  */
80 struct cache_entry_params {
81 	enum cache_entry_t entry_type;
82 	char	*entry_name;
83 };
84 
85 /* params, used for most entries */
86 struct common_cache_entry_params {
87 	struct cache_entry_params cep;
88 
89 	size_t	cache_entries_size;
90 
91 	size_t	max_elemsize;		/* if 0 then no check is made */
92 	size_t	satisf_elemsize;	/* if entry size is exceeded,
93 					 * this number of elements will be left,
94 					 * others will be deleted */
95 	int	confidence_threshold;	/* number matching replies required */
96 	struct timeval	max_lifetime;	/* if 0 then no check is made */
97 	enum cache_policy_t policy;	/* policy used for transformations */
98 };
99 
100 /* params, used for multipart entries */
101 struct	mp_cache_entry_params {
102 	struct cache_entry_params cep;
103 
104 	/* unique fields */
105 	size_t	max_elemsize;	/* if 0 then no check is made */
106 	size_t	max_sessions;	/* maximum number of active sessions */
107 
108 	struct timeval	max_lifetime;	/* maximum elements lifetime */
109 };
110 
111 struct cache_ht_item_data_ {
112     	/* key is the bytes sequence only - not the null-terminated string */
113 	char	*key;
114     	size_t	key_size;
115 
116 	char	*value;
117 	size_t	value_size;
118 
119 	struct cache_policy_item_ *fifo_policy_item;
120 	int	confidence;	/* incremented for each verification */
121 };
122 
123 struct cache_ht_item_ {
124 	HASHTABLE_ENTRY_HEAD(ht_item_, struct cache_ht_item_data_) data;
125 };
126 
127 struct cache_entry_ {
128 	char	*name;
129 	struct cache_entry_params *params;
130 };
131 
132 struct cache_common_entry_ {
133 	char	*name;
134 	struct cache_entry_params *params;
135 
136 	struct common_cache_entry_params common_params;
137 
138 	HASHTABLE_HEAD(cache_ht_, cache_ht_item_) items;
139 	size_t items_size;
140 
141 	/*
142 	 * Entry always has the FIFO policy, that is used to eliminate old
143 	 * elements (the ones, with lifetime more than max_lifetime). Besides,
144 	 * user can specify another policy to be applied, when there are too
145 	 * many elements in the entry. So policies_size can be 1 or 2.
146 	 */
147 	struct cache_policy_ **policies;
148 	size_t policies_size;
149 
150 	void	(*get_time_func)(struct timeval *);
151 };
152 
153 struct cache_mp_data_item_ {
154 	char	*value;
155 	size_t	value_size;
156 
157 	TAILQ_ENTRY(cache_mp_data_item_) entries;
158 };
159 
160 struct cache_mp_write_session_ {
161 	struct cache_mp_entry_	*parent_entry;
162 
163 	/*
164 	 * All items are accumulated in this queue. When the session is
165 	 * committed, they all will be copied to the multipart entry.
166 	 */
167 	TAILQ_HEAD(cache_mp_data_item_head, cache_mp_data_item_) items;
168 	size_t	items_size;
169 
170 	TAILQ_ENTRY(cache_mp_write_session_) entries;
171 };
172 
173 struct cache_mp_read_session_ {
174 	struct cache_mp_entry_ *parent_entry;
175 	struct cache_mp_data_item_ *current_item;
176 
177 	TAILQ_ENTRY(cache_mp_read_session_) entries;
178 };
179 
180 struct cache_mp_entry_ {
181 	char	*name;
182 	struct cache_entry_params *params;
183 
184 	struct mp_cache_entry_params mp_params;
185 
186 	/* All opened write sessions */
187 	TAILQ_HEAD(write_sessions_head, cache_mp_write_session_) ws_head;
188 	size_t	ws_size;
189 
190 	/* All opened read sessions */
191 	TAILQ_HEAD(read_sessions_head, cache_mp_read_session_) rs_head;
192 	size_t	rs_size;
193 
194 	/*
195 	 * completed_write_session is the committed write sessions. All read
196 	 * sessions use data from it. If the completed_write_session is out of
197 	 * date, but still in use by some of the read sessions, the newly
198 	 * committed write session is stored in the pending_write_session.
199 	 * In such a case, completed_write_session will be substituted with
200 	 * pending_write_session as soon as it won't be used by any of
201 	 * the read sessions.
202 	 */
203 	struct cache_mp_write_session_	*completed_write_session;
204 	struct cache_mp_write_session_	*pending_write_session;
205 	struct timeval	creation_time;
206 	struct timeval	last_request_time;
207 
208 	void	(*get_time_func)(struct timeval *);
209 };
210 
211 struct cache_ {
212 	struct cache_params params;
213 
214 	struct cache_entry_ **entries;
215 	size_t	entries_capacity;
216 	size_t	entries_size;
217 };
218 
219 /* simple abstractions - for not to write "struct" every time */
220 typedef struct cache_		*cache;
221 typedef struct cache_entry_	*cache_entry;
222 typedef struct cache_mp_write_session_	*cache_mp_write_session;
223 typedef struct cache_mp_read_session_	*cache_mp_read_session;
224 
225 #define INVALID_CACHE		(NULL)
226 #define INVALID_CACHE_ENTRY	(NULL)
227 #define INVALID_CACHE_MP_WRITE_SESSION	(NULL)
228 #define INVALID_CACHE_MP_READ_SESSION	(NULL)
229 
230 /*
231  * NOTE: all cache operations are thread-unsafe. You must ensure thread-safety
232  * externally, by yourself.
233  */
234 
235 /* cache initialization/destruction routines */
236 cache init_cache(struct cache_params const *);
237 void destroy_cache(cache);
238 
239 /* cache entries manipulation routines */
240 int register_cache_entry(cache, struct cache_entry_params const *);
241 int unregister_cache_entry(cache, const char *);
242 cache_entry find_cache_entry(cache, const char *);
243 
244 /* read/write operations used on common entries */
245 int cache_read(cache_entry, const char *, size_t, char *, size_t *);
246 int cache_write(cache_entry, const char *, size_t, char const *, size_t);
247 
248 /* read/write operations used on multipart entries */
249 cache_mp_write_session open_cache_mp_write_session(cache_entry);
250 int cache_mp_write(cache_mp_write_session, char *, size_t);
251 void abandon_cache_mp_write_session(cache_mp_write_session);
252 void close_cache_mp_write_session(cache_mp_write_session);
253 
254 cache_mp_read_session open_cache_mp_read_session(cache_entry);
255 int cache_mp_read(cache_mp_read_session, char *, size_t *);
256 void close_cache_mp_read_session(cache_mp_read_session);
257 
258 /* transformation routines */
259 int transform_cache_entry(cache_entry, enum cache_transformation_t);
260 int transform_cache_entry_part(cache_entry, enum cache_transformation_t,
261 	const char *, size_t, enum part_position_t);
262 
263 #endif
264