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>
45 * Default entries, which always exist in the configuration
47 const char *c_default_entries[6] = {
56 static int configuration_entry_cmp(const void *, const void *);
57 static int configuration_entry_sort_cmp(const void *, const void *);
58 static int configuration_entry_cache_mp_sort_cmp(const void *, const void *);
59 static int configuration_entry_cache_mp_cmp(const void *, const void *);
60 static int configuration_entry_cache_mp_part_cmp(const void *, const void *);
61 static struct configuration_entry *create_configuration_entry(const char *,
62 struct timeval const *, struct timeval const *,
63 struct common_cache_entry_params const *,
64 struct common_cache_entry_params const *,
65 struct mp_cache_entry_params const *);
68 configuration_entry_sort_cmp(const void *e1, const void *e2)
70 return (strcmp((*((struct configuration_entry **)e1))->name,
71 (*((struct configuration_entry **)e2))->name
76 configuration_entry_cmp(const void *e1, const void *e2)
78 return (strcmp((const char *)e1,
79 (*((struct configuration_entry **)e2))->name
84 configuration_entry_cache_mp_sort_cmp(const void *e1, const void *e2)
86 return (strcmp((*((cache_entry *)e1))->params->entry_name,
87 (*((cache_entry *)e2))->params->entry_name
92 configuration_entry_cache_mp_cmp(const void *e1, const void *e2)
94 return (strcmp((const char *)e1,
95 (*((cache_entry *)e2))->params->entry_name
100 configuration_entry_cache_mp_part_cmp(const void *e1, const void *e2)
102 return (strncmp((const char *)e1,
103 (*((cache_entry *)e2))->params->entry_name,
104 strlen((const char *)e1)
108 static struct configuration_entry *
109 create_configuration_entry(const char *name,
110 struct timeval const *common_timeout,
111 struct timeval const *mp_timeout,
112 struct common_cache_entry_params const *positive_params,
113 struct common_cache_entry_params const *negative_params,
114 struct mp_cache_entry_params const *mp_params)
116 struct configuration_entry *retval;
120 TRACE_IN(create_configuration_entry);
121 assert(name != NULL);
122 assert(positive_params != NULL);
123 assert(negative_params != NULL);
124 assert(mp_params != NULL);
128 assert(retval != NULL);
130 res = pthread_mutex_init(&retval->positive_cache_lock, NULL);
133 LOG_ERR_2("create_configuration_entry",
134 "can't create positive cache lock");
135 TRACE_OUT(create_configuration_entry);
139 res = pthread_mutex_init(&retval->negative_cache_lock, NULL);
141 pthread_mutex_destroy(&retval->positive_cache_lock);
143 LOG_ERR_2("create_configuration_entry",
144 "can't create negative cache lock");
145 TRACE_OUT(create_configuration_entry);
149 res = pthread_mutex_init(&retval->mp_cache_lock, NULL);
151 pthread_mutex_destroy(&retval->positive_cache_lock);
152 pthread_mutex_destroy(&retval->negative_cache_lock);
154 LOG_ERR_2("create_configuration_entry",
155 "can't create negative cache lock");
156 TRACE_OUT(create_configuration_entry);
160 memcpy(&retval->positive_cache_params, positive_params,
161 sizeof(struct common_cache_entry_params));
162 memcpy(&retval->negative_cache_params, negative_params,
163 sizeof(struct common_cache_entry_params));
164 memcpy(&retval->mp_cache_params, mp_params,
165 sizeof(struct mp_cache_entry_params));
168 retval->name = calloc(1, size + 1);
169 assert(retval->name != NULL);
170 memcpy(retval->name, name, size);
172 memcpy(&retval->common_query_timeout, common_timeout,
173 sizeof(struct timeval));
174 memcpy(&retval->mp_query_timeout, mp_timeout,
175 sizeof(struct timeval));
177 asprintf(&retval->positive_cache_params.cep.entry_name, "%s+", name);
178 assert(retval->positive_cache_params.cep.entry_name != NULL);
180 asprintf(&retval->negative_cache_params.cep.entry_name, "%s-", name);
181 assert(retval->negative_cache_params.cep.entry_name != NULL);
183 asprintf(&retval->mp_cache_params.cep.entry_name, "%s*", name);
184 assert(retval->mp_cache_params.cep.entry_name != NULL);
186 TRACE_OUT(create_configuration_entry);
191 * Creates configuration entry and fills it with default values
193 struct configuration_entry *
194 create_def_configuration_entry(const char *name)
196 struct common_cache_entry_params positive_params, negative_params;
197 struct mp_cache_entry_params mp_params;
198 struct timeval default_common_timeout, default_mp_timeout;
200 struct configuration_entry *res = NULL;
202 TRACE_IN(create_def_configuration_entry);
203 memset(&positive_params, 0,
204 sizeof(struct common_cache_entry_params));
205 positive_params.cep.entry_type = CET_COMMON;
206 positive_params.cache_entries_size = DEFAULT_CACHE_HT_SIZE;
207 positive_params.max_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE;
208 positive_params.satisf_elemsize = DEFAULT_POSITIVE_ELEMENTS_SIZE / 2;
209 positive_params.max_lifetime.tv_sec = DEFAULT_POSITIVE_LIFETIME;
210 positive_params.confidence_threshold = DEFAULT_POSITIVE_CONF_THRESH;
211 positive_params.policy = CPT_LRU;
213 memcpy(&negative_params, &positive_params,
214 sizeof(struct common_cache_entry_params));
215 negative_params.max_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE;
216 negative_params.satisf_elemsize = DEFAULT_NEGATIVE_ELEMENTS_SIZE / 2;
217 negative_params.max_lifetime.tv_sec = DEFAULT_NEGATIVE_LIFETIME;
218 negative_params.confidence_threshold = DEFAULT_NEGATIVE_CONF_THRESH;
219 negative_params.policy = CPT_FIFO;
221 memset(&default_common_timeout, 0, sizeof(struct timeval));
222 default_common_timeout.tv_sec = DEFAULT_COMMON_ENTRY_TIMEOUT;
224 memset(&default_mp_timeout, 0, sizeof(struct timeval));
225 default_mp_timeout.tv_sec = DEFAULT_MP_ENTRY_TIMEOUT;
227 memset(&mp_params, 0,
228 sizeof(struct mp_cache_entry_params));
229 mp_params.cep.entry_type = CET_MULTIPART;
230 mp_params.max_elemsize = DEFAULT_MULTIPART_ELEMENTS_SIZE;
231 mp_params.max_sessions = DEFAULT_MULITPART_SESSIONS_SIZE;
232 mp_params.max_lifetime.tv_sec = DEFAULT_MULITPART_LIFETIME;
234 res = create_configuration_entry(name, &default_common_timeout,
235 &default_mp_timeout, &positive_params, &negative_params,
238 TRACE_OUT(create_def_configuration_entry);
243 destroy_configuration_entry(struct configuration_entry *entry)
245 TRACE_IN(destroy_configuration_entry);
246 assert(entry != NULL);
247 pthread_mutex_destroy(&entry->positive_cache_lock);
248 pthread_mutex_destroy(&entry->negative_cache_lock);
249 pthread_mutex_destroy(&entry->mp_cache_lock);
251 free(entry->positive_cache_params.cep.entry_name);
252 free(entry->negative_cache_params.cep.entry_name);
253 free(entry->mp_cache_params.cep.entry_name);
254 free(entry->mp_cache_entries);
256 TRACE_OUT(destroy_configuration_entry);
260 add_configuration_entry(struct configuration *config,
261 struct configuration_entry *entry)
263 TRACE_IN(add_configuration_entry);
264 assert(entry != NULL);
265 assert(entry->name != NULL);
266 if (configuration_find_entry(config, entry->name) != NULL) {
267 TRACE_OUT(add_configuration_entry);
271 if (config->entries_size == config->entries_capacity) {
272 struct configuration_entry **new_entries;
274 config->entries_capacity *= 2;
275 new_entries = calloc(config->entries_capacity,
276 sizeof(*new_entries));
277 assert(new_entries != NULL);
278 memcpy(new_entries, config->entries,
279 sizeof(struct configuration_entry *) *
280 config->entries_size);
282 free(config->entries);
283 config->entries = new_entries;
286 config->entries[config->entries_size++] = entry;
287 qsort(config->entries, config->entries_size,
288 sizeof(struct configuration_entry *),
289 configuration_entry_sort_cmp);
291 TRACE_OUT(add_configuration_entry);
296 configuration_get_entries_size(struct configuration *config)
298 TRACE_IN(configuration_get_entries_size);
299 assert(config != NULL);
300 TRACE_OUT(configuration_get_entries_size);
301 return (config->entries_size);
304 struct configuration_entry *
305 configuration_get_entry(struct configuration *config, size_t index)
307 TRACE_IN(configuration_get_entry);
308 assert(config != NULL);
309 assert(index < config->entries_size);
310 TRACE_OUT(configuration_get_entry);
311 return (config->entries[index]);
314 struct configuration_entry *
315 configuration_find_entry(struct configuration *config,
318 struct configuration_entry **retval;
320 TRACE_IN(configuration_find_entry);
322 retval = bsearch(name, config->entries, config->entries_size,
323 sizeof(struct configuration_entry *), configuration_entry_cmp);
324 TRACE_OUT(configuration_find_entry);
326 return ((retval != NULL) ? *retval : NULL);
330 * All multipart cache entries are stored in the configuration_entry in the
331 * sorted array (sorted by names). The 3 functions below manage this array.
335 configuration_entry_add_mp_cache_entry(struct configuration_entry *config_entry,
338 cache_entry *new_mp_entries, *old_mp_entries;
340 TRACE_IN(configuration_entry_add_mp_cache_entry);
341 ++config_entry->mp_cache_entries_size;
342 new_mp_entries = malloc(sizeof(*new_mp_entries) *
343 config_entry->mp_cache_entries_size);
344 assert(new_mp_entries != NULL);
345 new_mp_entries[0] = c_entry;
347 if (config_entry->mp_cache_entries_size - 1 > 0) {
348 memcpy(new_mp_entries + 1,
349 config_entry->mp_cache_entries,
350 (config_entry->mp_cache_entries_size - 1) *
351 sizeof(cache_entry));
354 old_mp_entries = config_entry->mp_cache_entries;
355 config_entry->mp_cache_entries = new_mp_entries;
356 free(old_mp_entries);
358 qsort(config_entry->mp_cache_entries,
359 config_entry->mp_cache_entries_size,
361 configuration_entry_cache_mp_sort_cmp);
363 TRACE_OUT(configuration_entry_add_mp_cache_entry);
368 configuration_entry_find_mp_cache_entry(
369 struct configuration_entry *config_entry, const char *mp_name)
373 TRACE_IN(configuration_entry_find_mp_cache_entry);
374 result = bsearch(mp_name, config_entry->mp_cache_entries,
375 config_entry->mp_cache_entries_size,
376 sizeof(cache_entry), configuration_entry_cache_mp_cmp);
378 if (result == NULL) {
379 TRACE_OUT(configuration_entry_find_mp_cache_entry);
382 TRACE_OUT(configuration_entry_find_mp_cache_entry);
388 * Searches for all multipart entries with names starting with mp_name.
389 * Needed for cache flushing.
392 configuration_entry_find_mp_cache_entries(
393 struct configuration_entry *config_entry, const char *mp_name,
394 cache_entry **start, cache_entry **finish)
398 TRACE_IN(configuration_entry_find_mp_cache_entries);
399 result = bsearch(mp_name, config_entry->mp_cache_entries,
400 config_entry->mp_cache_entries_size,
401 sizeof(cache_entry), configuration_entry_cache_mp_part_cmp);
403 if (result == NULL) {
404 TRACE_OUT(configuration_entry_find_mp_cache_entries);
409 *finish = result + 1;
411 while (*start != config_entry->mp_cache_entries) {
412 if (configuration_entry_cache_mp_part_cmp(mp_name, *start - 1) == 0)
418 while (*finish != config_entry->mp_cache_entries +
419 config_entry->mp_cache_entries_size) {
421 if (configuration_entry_cache_mp_part_cmp(
422 mp_name, *finish) == 0)
423 *finish = *finish + 1;
428 TRACE_OUT(configuration_entry_find_mp_cache_entries);
433 * Configuration entry uses rwlock to handle access to its fields.
436 configuration_lock_rdlock(struct configuration *config)
438 TRACE_IN(configuration_lock_rdlock);
439 pthread_rwlock_rdlock(&config->rwlock);
440 TRACE_OUT(configuration_lock_rdlock);
444 configuration_lock_wrlock(struct configuration *config)
446 TRACE_IN(configuration_lock_wrlock);
447 pthread_rwlock_wrlock(&config->rwlock);
448 TRACE_OUT(configuration_lock_wrlock);
452 configuration_unlock(struct configuration *config)
454 TRACE_IN(configuration_unlock);
455 pthread_rwlock_unlock(&config->rwlock);
456 TRACE_OUT(configuration_unlock);
460 * Configuration entry uses 3 mutexes to handle cache operations. They are
461 * acquired by configuration_lock_entry and configuration_unlock_entry
465 configuration_lock_entry(struct configuration_entry *entry,
466 enum config_entry_lock_type lock_type)
468 TRACE_IN(configuration_lock_entry);
469 assert(entry != NULL);
473 pthread_mutex_lock(&entry->positive_cache_lock);
476 pthread_mutex_lock(&entry->negative_cache_lock);
479 pthread_mutex_lock(&entry->mp_cache_lock);
482 /* should be unreachable */
485 TRACE_OUT(configuration_lock_entry);
489 configuration_unlock_entry(struct configuration_entry *entry,
490 enum config_entry_lock_type lock_type)
492 TRACE_IN(configuration_unlock_entry);
493 assert(entry != NULL);
497 pthread_mutex_unlock(&entry->positive_cache_lock);
500 pthread_mutex_unlock(&entry->negative_cache_lock);
503 pthread_mutex_unlock(&entry->mp_cache_lock);
506 /* should be unreachable */
509 TRACE_OUT(configuration_unlock_entry);
512 struct configuration *
513 init_configuration(void)
515 struct configuration *retval;
517 TRACE_IN(init_configuration);
518 retval = calloc(1, sizeof(*retval));
519 assert(retval != NULL);
521 retval->entries_capacity = INITIAL_ENTRIES_CAPACITY;
522 retval->entries = calloc(retval->entries_capacity,
523 sizeof(*retval->entries));
524 assert(retval->entries != NULL);
526 pthread_rwlock_init(&retval->rwlock, NULL);
528 TRACE_OUT(init_configuration);
533 fill_configuration_defaults(struct configuration *config)
537 TRACE_IN(fill_configuration_defaults);
538 assert(config != NULL);
540 if (config->socket_path != NULL)
541 free(config->socket_path);
543 len = strlen(DEFAULT_SOCKET_PATH);
544 config->socket_path = calloc(1, len + 1);
545 assert(config->socket_path != NULL);
546 memcpy(config->socket_path, DEFAULT_SOCKET_PATH, len);
548 len = strlen(DEFAULT_PIDFILE_PATH);
549 config->pidfile_path = calloc(1, len + 1);
550 assert(config->pidfile_path != NULL);
551 memcpy(config->pidfile_path, DEFAULT_PIDFILE_PATH, len);
553 config->socket_mode = S_IFSOCK | S_IRUSR | S_IWUSR |
554 S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
555 config->force_unlink = 1;
557 config->query_timeout = DEFAULT_QUERY_TIMEOUT;
558 config->threads_num = DEFAULT_THREADS_NUM;
560 for (i = 0; i < config->entries_size; ++i)
561 destroy_configuration_entry(config->entries[i]);
562 config->entries_size = 0;
564 TRACE_OUT(fill_configuration_defaults);
568 destroy_configuration(struct configuration *config)
572 TRACE_IN(destroy_configuration);
573 assert(config != NULL);
574 free(config->pidfile_path);
575 free(config->socket_path);
577 for (i = 0; i < config->entries_size; ++i)
578 destroy_configuration_entry(config->entries[i]);
579 free(config->entries);
581 pthread_rwlock_destroy(&config->rwlock);
583 TRACE_OUT(destroy_configuration);