2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
41 * Default entries, which always exist in the configuration
43 const char *c_default_entries[6] = {
52 static int configuration_entry_cmp(const void *, const void *);
53 static int configuration_entry_sort_cmp(const void *, const void *);
54 static int configuration_entry_cache_mp_sort_cmp(const void *, const void *);
55 static int configuration_entry_cache_mp_cmp(const void *, const void *);
56 static int configuration_entry_cache_mp_part_cmp(const void *, const void *);
57 static struct configuration_entry *create_configuration_entry(const char *,
58 struct timeval const *, struct timeval const *,
59 struct common_cache_entry_params const *,
60 struct common_cache_entry_params const *,
61 struct mp_cache_entry_params const *);
64 configuration_entry_sort_cmp(const void *e1, const void *e2)
66 return (strcmp((*((struct configuration_entry **)e1))->name,
67 (*((struct configuration_entry **)e2))->name
72 configuration_entry_cmp(const void *e1, const void *e2)
74 return (strcmp((const char *)e1,
75 (*((struct configuration_entry **)e2))->name
80 configuration_entry_cache_mp_sort_cmp(const void *e1, const void *e2)
82 return (strcmp((*((cache_entry *)e1))->params->entry_name,
83 (*((cache_entry *)e2))->params->entry_name
88 configuration_entry_cache_mp_cmp(const void *e1, const void *e2)
90 return (strcmp((const char *)e1,
91 (*((cache_entry *)e2))->params->entry_name
96 configuration_entry_cache_mp_part_cmp(const void *e1, const void *e2)
98 return (strncmp((const char *)e1,
99 (*((cache_entry *)e2))->params->entry_name,
100 strlen((const char *)e1)
104 static struct configuration_entry *
105 create_configuration_entry(const char *name,
106 struct timeval const *common_timeout,
107 struct timeval const *mp_timeout,
108 struct common_cache_entry_params const *positive_params,
109 struct common_cache_entry_params const *negative_params,
110 struct mp_cache_entry_params const *mp_params)
112 struct configuration_entry *retval;
116 TRACE_IN(create_configuration_entry);
117 assert(name != NULL);
118 assert(positive_params != NULL);
119 assert(negative_params != NULL);
120 assert(mp_params != NULL);
122 retval = (struct configuration_entry *)calloc(1,
123 sizeof(struct configuration_entry));
124 assert(retval != NULL);
126 res = pthread_mutex_init(&retval->positive_cache_lock, NULL);
129 LOG_ERR_2("create_configuration_entry",
130 "can't create positive cache lock");
131 TRACE_OUT(create_configuration_entry);
135 res = pthread_mutex_init(&retval->negative_cache_lock, NULL);
137 pthread_mutex_destroy(&retval->positive_cache_lock);
139 LOG_ERR_2("create_configuration_entry",
140 "can't create negative cache lock");
141 TRACE_OUT(create_configuration_entry);
145 res = pthread_mutex_init(&retval->mp_cache_lock, NULL);
147 pthread_mutex_destroy(&retval->positive_cache_lock);
148 pthread_mutex_destroy(&retval->negative_cache_lock);
150 LOG_ERR_2("create_configuration_entry",
151 "can't create negative cache lock");
152 TRACE_OUT(create_configuration_entry);
156 memcpy(&retval->positive_cache_params, positive_params,
157 sizeof(struct common_cache_entry_params));
158 memcpy(&retval->negative_cache_params, negative_params,
159 sizeof(struct common_cache_entry_params));
160 memcpy(&retval->mp_cache_params, mp_params,
161 sizeof(struct mp_cache_entry_params));
164 retval->name = (char *)calloc(1, size + 1);
165 assert(retval->name != NULL);
166 memcpy(retval->name, name, size);
168 memcpy(&retval->common_query_timeout, common_timeout,
169 sizeof(struct timeval));
170 memcpy(&retval->mp_query_timeout, mp_timeout,
171 sizeof(struct timeval));
173 asprintf(&retval->positive_cache_params.entry_name, "%s+", name);
174 assert(retval->positive_cache_params.entry_name != NULL);
176 asprintf(&retval->negative_cache_params.entry_name, "%s-", name);
177 assert(retval->negative_cache_params.entry_name != NULL);
179 asprintf(&retval->mp_cache_params.entry_name, "%s*", name);
180 assert(retval->mp_cache_params.entry_name != NULL);
182 TRACE_OUT(create_configuration_entry);
187 * Creates configuration entry and fills it with default values
189 struct configuration_entry *
190 create_def_configuration_entry(const char *name)
192 struct common_cache_entry_params positive_params, negative_params;
193 struct mp_cache_entry_params mp_params;
194 struct timeval default_common_timeout, default_mp_timeout;
196 struct configuration_entry *res = NULL;
198 TRACE_IN(create_def_configuration_entry);
199 memset(&positive_params, 0,
200 sizeof(struct common_cache_entry_params));
201 positive_params.entry_type = CET_COMMON;
202 positive_params.cache_entries_size = DEFAULT_CACHE_HT_SIZE;
203 positive_params.max_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE;
204 positive_params.satisf_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE / 2;
205 positive_params.max_lifetime.tv_sec = DEFAULT_POSITIVE_LIFETIME;
206 positive_params.policy = CPT_LRU;
208 memcpy(&negative_params, &positive_params,
209 sizeof(struct common_cache_entry_params));
210 negative_params.max_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE;
211 negative_params.satisf_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE / 2;
212 negative_params.max_lifetime.tv_sec = DEFAULT_NEGATIVE_LIFETIME;
213 negative_params.policy = CPT_FIFO;
215 memset(&default_common_timeout, 0, sizeof(struct timeval));
216 default_common_timeout.tv_sec = DEFAULT_COMMON_ENTRY_TIMEOUT;
218 memset(&default_mp_timeout, 0, sizeof(struct timeval));
219 default_mp_timeout.tv_sec = DEFAULT_MP_ENTRY_TIMEOUT;
221 memset(&mp_params, 0,
222 sizeof(struct mp_cache_entry_params));
223 mp_params.entry_type = CET_MULTIPART;
224 mp_params.max_elemsize = DEFAULT_MULTIPART_ELEMENTS_SIZE;
225 mp_params.max_sessions = DEFAULT_MULITPART_SESSIONS_SIZE;
226 mp_params.max_lifetime.tv_sec = DEFAULT_MULITPART_LIFETIME;
228 res = create_configuration_entry(name, &default_common_timeout,
229 &default_mp_timeout, &positive_params, &negative_params,
232 TRACE_OUT(create_def_configuration_entry);
237 destroy_configuration_entry(struct configuration_entry *entry)
239 TRACE_IN(destroy_configuration_entry);
240 assert(entry != NULL);
241 pthread_mutex_destroy(&entry->positive_cache_lock);
242 pthread_mutex_destroy(&entry->negative_cache_lock);
243 pthread_mutex_destroy(&entry->mp_cache_lock);
245 free(entry->positive_cache_params.entry_name);
246 free(entry->negative_cache_params.entry_name);
247 free(entry->mp_cache_params.entry_name);
248 free(entry->mp_cache_entries);
250 TRACE_OUT(destroy_configuration_entry);
254 add_configuration_entry(struct configuration *config,
255 struct configuration_entry *entry)
257 TRACE_IN(add_configuration_entry);
258 assert(entry != NULL);
259 assert(entry->name != NULL);
260 if (configuration_find_entry(config, entry->name) != NULL) {
261 TRACE_OUT(add_configuration_entry);
265 if (config->entries_size == config->entries_capacity) {
266 struct configuration_entry **new_entries;
268 config->entries_capacity *= 2;
269 new_entries = (struct configuration_entry **)calloc(1,
270 sizeof(struct configuration_entry *) *
271 config->entries_capacity);
272 assert(new_entries != NULL);
273 memcpy(new_entries, config->entries,
274 sizeof(struct configuration_entry *) *
275 config->entries_size);
277 free(config->entries);
278 config->entries = new_entries;
281 config->entries[config->entries_size++] = entry;
282 qsort(config->entries, config->entries_size,
283 sizeof(struct configuration_entry *),
284 configuration_entry_sort_cmp);
286 TRACE_OUT(add_configuration_entry);
291 configuration_get_entries_size(struct configuration *config)
293 TRACE_IN(configuration_get_entries_size);
294 assert(config != NULL);
295 TRACE_OUT(configuration_get_entries_size);
296 return (config->entries_size);
299 struct configuration_entry *
300 configuration_get_entry(struct configuration *config, size_t index)
302 TRACE_IN(configuration_get_entry);
303 assert(config != NULL);
304 assert(index < config->entries_size);
305 TRACE_OUT(configuration_get_entry);
306 return (config->entries[index]);
309 struct configuration_entry *
310 configuration_find_entry(struct configuration *config,
313 struct configuration_entry **retval;
315 TRACE_IN(configuration_find_entry);
317 retval = bsearch(name, config->entries, config->entries_size,
318 sizeof(struct configuration_entry *), configuration_entry_cmp);
319 TRACE_OUT(configuration_find_entry);
321 return ((retval != NULL) ? *retval : NULL);
325 * All multipart cache entries are stored in the configuration_entry in the
326 * sorted array (sorted by names). The 3 functions below manage this array.
330 configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry,
333 cache_entry *new_mp_entries, *old_mp_entries;
335 TRACE_IN(configuration_entry_add_mp_cache_entry);
336 ++config_entry->mp_cache_entries_size;
337 new_mp_entries = (cache_entry *)malloc(sizeof(cache_entry) *
338 config_entry->mp_cache_entries_size);
339 assert(new_mp_entries != NULL);
340 new_mp_entries[0] = c_entry;
342 if (config_entry->mp_cache_entries_size - 1 > 0) {
343 memcpy(new_mp_entries + 1,
344 config_entry->mp_cache_entries,
345 (config_entry->mp_cache_entries_size - 1) *
346 sizeof(cache_entry));
349 old_mp_entries = config_entry->mp_cache_entries;
350 config_entry->mp_cache_entries = new_mp_entries;
351 free(old_mp_entries);
353 qsort(config_entry->mp_cache_entries,
354 config_entry->mp_cache_entries_size,
356 configuration_entry_cache_mp_sort_cmp);
358 TRACE_OUT(configuration_entry_add_mp_cache_entry);
363 configuration_entry_find_mp_cache_entry(
364 struct configuration_entry *config_entry, const char *mp_name)
368 TRACE_IN(configuration_entry_find_mp_cache_entry);
369 result = bsearch(mp_name, config_entry->mp_cache_entries,
370 config_entry->mp_cache_entries_size,
371 sizeof(cache_entry), configuration_entry_cache_mp_cmp);
373 if (result == NULL) {
374 TRACE_OUT(configuration_entry_find_mp_cache_entry);
377 TRACE_OUT(configuration_entry_find_mp_cache_entry);
383 * Searches for all multipart entries with names starting with mp_name.
384 * Needed for cache flushing.
387 configuration_entry_find_mp_cache_entries(
388 struct configuration_entry *config_entry, const char *mp_name,
389 cache_entry **start, cache_entry **finish)
393 TRACE_IN(configuration_entry_find_mp_cache_entries);
394 result = bsearch(mp_name, config_entry->mp_cache_entries,
395 config_entry->mp_cache_entries_size,
396 sizeof(cache_entry), configuration_entry_cache_mp_part_cmp);
398 if (result == NULL) {
399 TRACE_OUT(configuration_entry_find_mp_cache_entries);
404 *finish = result + 1;
406 while (*start != config_entry->mp_cache_entries) {
407 if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0)
413 while (*finish != config_entry->mp_cache_entries +
414 config_entry->mp_cache_entries_size) {
416 if (configuration_entry_cache_mp_part_cmp(
417 mp_name, *finish) == 0)
418 *finish = *finish + 1;
423 TRACE_OUT(configuration_entry_find_mp_cache_entries);
428 * Configuration entry uses rwlock to handle access to its fields.
431 configuration_lock_rdlock(struct configuration *config)
433 TRACE_IN(configuration_lock_rdlock);
434 pthread_rwlock_rdlock(&config->rwlock);
435 TRACE_OUT(configuration_lock_rdlock);
439 configuration_lock_wrlock(struct configuration *config)
441 TRACE_IN(configuration_lock_wrlock);
442 pthread_rwlock_wrlock(&config->rwlock);
443 TRACE_OUT(configuration_lock_wrlock);
447 configuration_unlock(struct configuration *config)
449 TRACE_IN(configuration_unlock);
450 pthread_rwlock_unlock(&config->rwlock);
451 TRACE_OUT(configuration_unlock);
455 * Configuration entry uses 3 mutexes to handle cache operations. They are
456 * acquired by configuration_lock_entry and configuration_unlock_entry
460 configuration_lock_entry(struct configuration_entry *entry,
461 enum config_entry_lock_type lock_type)
463 TRACE_IN(configuration_lock_entry);
464 assert(entry != NULL);
468 pthread_mutex_lock(&entry->positive_cache_lock);
471 pthread_mutex_lock(&entry->negative_cache_lock);
474 pthread_mutex_lock(&entry->mp_cache_lock);
477 /* should be unreachable */
480 TRACE_OUT(configuration_lock_entry);
484 configuration_unlock_entry(struct configuration_entry *entry,
485 enum config_entry_lock_type lock_type)
487 TRACE_IN(configuration_unlock_entry);
488 assert(entry != NULL);
492 pthread_mutex_unlock(&entry->positive_cache_lock);
495 pthread_mutex_unlock(&entry->negative_cache_lock);
498 pthread_mutex_unlock(&entry->mp_cache_lock);
501 /* should be unreachable */
504 TRACE_OUT(configuration_unlock_entry);
507 struct configuration *
508 init_configuration(void)
510 struct configuration *retval;
512 TRACE_IN(init_configuration);
513 retval = (struct configuration *)calloc(1, sizeof(struct configuration));
514 assert(retval != NULL);
516 retval->entries_capacity = INITIAL_ENTRIES_CAPACITY;
517 retval->entries = (struct configuration_entry **)calloc(1,
518 sizeof(struct configuration_entry *) *
519 retval->entries_capacity);
520 assert(retval->entries != NULL);
522 pthread_rwlock_init(&retval->rwlock, NULL);
524 TRACE_OUT(init_configuration);
529 fill_configuration_defaults(struct configuration *config)
533 TRACE_IN(fill_configuration_defaults);
534 assert(config != NULL);
536 if (config->socket_path != NULL)
537 free(config->socket_path);
539 len = strlen(DEFAULT_SOCKET_PATH);
540 config->socket_path = (char *)calloc(1, len + 1);
541 assert(config->socket_path != NULL);
542 memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len);
544 len = strlen(DEFAULT_PIDFILE_PATH);
545 config->pidfile_path = (char *)calloc(1, len + 1);
546 assert(config->pidfile_path != NULL);
547 memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len);
549 config->socket_mode = S_IFSOCK | S_IRUSR | S_IWUSR |
550 S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
551 config->force_unlink = 1;
553 config->query_timeout = DEFAULT_QUERY_TIMEOUT;
554 config->threads_num = DEFAULT_THREADS_NUM;
556 for (i = 0; i < config->entries_size; ++i)
557 destroy_configuration_entry(config->entries[i]);
558 config->entries_size = 0;
560 TRACE_OUT(fill_configuration_defaults);
564 destroy_configuration(struct configuration *config)
567 TRACE_IN(destroy_configuration);
568 assert(config != NULL);
569 free(config->pidfile_path);
570 free(config->socket_path);
572 for (i = 0; i < config->entries_size; ++i)
573 destroy_configuration_entry(config->entries[i]);
574 free(config->entries);
576 pthread_rwlock_destroy(&config->rwlock);
578 TRACE_OUT(destroy_configuration);