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
35enum cache_entry_t	{
36	CET_COMMON = 0,	/* cache item is atomic */
37	CET_MULTIPART	/* cache item is formed part by part */
38};
39
40enum 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 */
46enum 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 */
53enum 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 */
63enum 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 */
72struct 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 */
80struct cache_entry_params {
81	enum cache_entry_t entry_type;
82	char	*entry_name;
83};
84
85/* params, used for most entries */
86struct 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 */
101struct	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
111struct 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
123struct cache_ht_item_ {
124	HASHTABLE_ENTRY_HEAD(ht_item_, struct cache_ht_item_data_) data;
125};
126
127struct cache_entry_ {
128	char	*name;
129	struct cache_entry_params *params;
130};
131
132struct 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
153struct cache_mp_data_item_ {
154	char	*value;
155	size_t	value_size;
156
157	TAILQ_ENTRY(cache_mp_data_item_) entries;
158};
159
160struct 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
173struct 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
180struct 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
211struct 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 */
220typedef struct cache_		*cache;
221typedef struct cache_entry_	*cache_entry;
222typedef struct cache_mp_write_session_	*cache_mp_write_session;
223typedef 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 */
236cache init_cache(struct cache_params const *);
237void destroy_cache(cache);
238
239/* cache entries manipulation routines */
240int register_cache_entry(cache, struct cache_entry_params const *);
241int unregister_cache_entry(cache, const char *);
242cache_entry find_cache_entry(cache, const char *);
243
244/* read/write operations used on common entries */
245int cache_read(cache_entry, const char *, size_t, char *, size_t *);
246int cache_write(cache_entry, const char *, size_t, char const *, size_t);
247
248/* read/write operations used on multipart entries */
249cache_mp_write_session open_cache_mp_write_session(cache_entry);
250int cache_mp_write(cache_mp_write_session, char *, size_t);
251void abandon_cache_mp_write_session(cache_mp_write_session);
252void close_cache_mp_write_session(cache_mp_write_session);
253
254cache_mp_read_session open_cache_mp_read_session(cache_entry);
255int cache_mp_read(cache_mp_read_session, char *, size_t *);
256void close_cache_mp_read_session(cache_mp_read_session);
257
258/* transformation routines */
259int transform_cache_entry(cache_entry, enum cache_transformation_t);
260int transform_cache_entry_part(cache_entry, enum cache_transformation_t,
261	const char *, size_t, enum part_position_t);
262
263#endif
264