123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- /*
- Copyright (c) 2018 Anton Valentinov Kirilov
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
- associated documentation files (the "Software"), to deal in the Software without restriction,
- including without limitation the rights to use, copy, modify, merge, publish, distribute,
- sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all copies or
- substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
- NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
- OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- #include <assert.h>
- #include <pthread.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include <h2o/cache.h>
- #include "cache.h"
- #include "error.h"
- #include "utility.h"
- // Increasing the number of caches by the following factor reduces contention; must be a power of 2.
- #define CONCURRENCY_FACTOR 4
- static size_t get_index(size_t n, h2o_cache_hashcode_t keyhash)
- {
- assert(is_power_of_2(n));
- return keyhash & (n - 1);
- }
- int cache_create(size_t concurrency,
- size_t capacity,
- uint64_t duration,
- void (*destroy_cb)(h2o_iovec_t value),
- cache_t *cache)
- {
- memset(cache, 0, sizeof(*cache));
- assert(is_power_of_2(CONCURRENCY_FACTOR));
- // Rounding up to a power of 2 simplifies the calculations a little bit, and, as any increase in
- // the number of caches, potentially reduces thread contention.
- cache->cache_num = CONCURRENCY_FACTOR * round_up_to_power_of_2(concurrency);
- cache->cache_num = MAX(cache->cache_num, 1);
- capacity = (capacity + cache->cache_num - 1) / cache->cache_num;
- pthread_mutexattr_t attr;
- if (pthread_mutexattr_init(&attr))
- return 1;
- if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP))
- goto error;
- cache->cache = malloc(cache->cache_num * sizeof(*cache->cache));
- if (!cache->cache)
- goto error;
- cache->cache_lock = malloc(cache->cache_num * sizeof(*cache->cache_lock));
- if (!cache->cache_lock)
- goto error_malloc;
- for (size_t i = 0; i < cache->cache_num; i++) {
- cache->cache[i] = h2o_cache_create(0, capacity, duration, destroy_cb);
- if (!cache->cache[i] || pthread_mutex_init(cache->cache_lock + i, &attr)) {
- if (cache->cache[i])
- h2o_cache_destroy(cache->cache[i]);
- cache->cache_num = i;
- cache_destroy(cache);
- goto error;
- }
- }
- pthread_mutexattr_destroy(&attr);
- return 0;
- error_malloc:
- free(cache->cache);
- error:
- pthread_mutexattr_destroy(&attr);
- return 1;
- }
- void cache_destroy(cache_t *cache)
- {
- if (cache->cache) {
- assert(cache->cache_lock);
- for (size_t i = 0; i < cache->cache_num; i++) {
- h2o_cache_destroy(cache->cache[i]);
- pthread_mutex_destroy(cache->cache_lock + i);
- }
- free(cache->cache);
- free(cache->cache_lock);
- cache->cache = NULL;
- cache->cache_lock = NULL;
- }
- else
- assert(!cache->cache_lock);
- }
- h2o_cache_ref_t *cache_fetch(cache_t *cache,
- uint64_t now,
- h2o_iovec_t key,
- h2o_cache_hashcode_t keyhash)
- {
- if (!keyhash)
- keyhash = h2o_cache_calchash(key.base, key.len);
- const size_t idx = get_index(cache->cache_num, keyhash);
- pthread_mutex_t * const mutex = cache->cache_lock + idx;
- CHECK_ERROR(pthread_mutex_lock, mutex);
- h2o_cache_ref_t * const ret = h2o_cache_fetch(cache->cache[idx], now, key, keyhash);
- CHECK_ERROR(pthread_mutex_unlock, mutex);
- return ret;
- }
- void cache_release(cache_t *cache, h2o_cache_ref_t *ref, h2o_cache_hashcode_t keyhash)
- {
- if (!keyhash)
- keyhash = h2o_cache_calchash(ref->key.base, ref->key.len);
- const size_t idx = get_index(cache->cache_num, keyhash);
- h2o_cache_release(cache->cache[idx], ref);
- }
- int cache_set(uint64_t now,
- h2o_iovec_t key,
- h2o_cache_hashcode_t keyhash,
- h2o_iovec_t value,
- cache_t *cache)
- {
- if (!keyhash)
- keyhash = h2o_cache_calchash(key.base, key.len);
- const size_t idx = get_index(cache->cache_num, keyhash);
- pthread_mutex_t * const mutex = cache->cache_lock + idx;
- CHECK_ERROR(pthread_mutex_lock, mutex);
- const int ret = h2o_cache_set(cache->cache[idx], now, key, keyhash, value);
- CHECK_ERROR(pthread_mutex_unlock, mutex);
- return ret;
- }
|