Page MenuHomePhabricator (Chris)

mongocrypt-cache.c
No OneTemporary

Authored By
Unknown
Size
6 KB
Referenced Files
None
Subscribers
None

mongocrypt-cache.c

/*
* Copyright 2019-present MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mongocrypt-cache-private.h"
#include "mongocrypt-private.h"
/* Did the cache pair expire? Caller must hold lock. */
static bool _pair_expired(_mongocrypt_cache_t *cache, _mongocrypt_cache_pair_t *pair) {
int64_t current;
BSON_ASSERT_PARAM(cache);
BSON_ASSERT_PARAM(pair);
current = bson_get_monotonic_time() / 1000;
BSON_ASSERT(current >= INT64_MIN + pair->last_updated);
BSON_ASSERT(cache->expiration <= INT64_MAX);
return cache->expiration > 0 && (current - pair->last_updated) > (int64_t)cache->expiration;
}
/* Return the pair after the one being destroyed. */
static _mongocrypt_cache_pair_t *
_destroy_pair(_mongocrypt_cache_t *cache, _mongocrypt_cache_pair_t *prev, _mongocrypt_cache_pair_t *pair) {
_mongocrypt_cache_pair_t *tmp;
BSON_ASSERT_PARAM(cache);
/* prev is checked before being used, so it can be NULL */
BSON_ASSERT_PARAM(pair);
tmp = pair->next;
/* Unlink */
if (!prev) {
cache->pair = cache->pair->next;
} else {
prev->next = pair->next;
}
/* Destroy pair */
cache->destroy_attr(pair->attr);
cache->destroy_value(pair->value);
bson_free(pair);
return tmp;
}
/* Caller must hold mutex. */
static void _mongocrypt_cache_evict(_mongocrypt_cache_t *cache) {
_mongocrypt_cache_pair_t *pair, *prev;
BSON_ASSERT_PARAM(cache);
prev = NULL;
pair = cache->pair;
while (pair) {
if (_pair_expired(cache, pair)) {
pair = _destroy_pair(cache, prev, pair);
continue;
}
prev = pair;
pair = pair->next;
}
}
/* Caller must hold mutex. */
static bool _mongocrypt_remove_matches(_mongocrypt_cache_t *cache, void *attr) {
_mongocrypt_cache_pair_t *pair, *prev;
BSON_ASSERT_PARAM(cache);
BSON_ASSERT_PARAM(attr);
prev = NULL;
pair = cache->pair;
while (pair) {
int res;
if (!cache->cmp_attr(pair->attr, attr, &res)) {
return false;
}
if (0 == res) {
pair = _destroy_pair(cache, prev, pair);
continue;
}
prev = pair;
pair = pair->next;
}
return true;
}
void _mongocrypt_cache_set_expiration(_mongocrypt_cache_t *cache, uint64_t milli) {
BSON_ASSERT_PARAM(cache);
cache->expiration = milli;
}
/* caller must hold lock. */
static bool _find_pair(_mongocrypt_cache_t *cache, void *attr, _mongocrypt_cache_pair_t **out) {
_mongocrypt_cache_pair_t *pair;
BSON_ASSERT_PARAM(cache);
BSON_ASSERT_PARAM(attr);
BSON_ASSERT_PARAM(out);
*out = NULL;
pair = cache->pair;
while (pair) {
int res;
/* TODO: this is a naive O(n) lookup. Consider optimizing
with a hash map (possibly vendor one). */
if (!cache->cmp_attr(pair->attr, attr, &res)) {
return false;
}
if (res == 0) {
*out = pair;
return true;
}
pair = pair->next;
}
return true;
}
/* Create a new pair on linked list. Caller must hold lock. */
static _mongocrypt_cache_pair_t *_pair_new(_mongocrypt_cache_t *cache, void *attr) {
_mongocrypt_cache_pair_t *pair;
BSON_ASSERT_PARAM(cache);
BSON_ASSERT_PARAM(attr);
pair = bson_malloc0(sizeof(_mongocrypt_cache_pair_t));
BSON_ASSERT(pair);
pair->attr = cache->copy_attr(attr);
/* add rest of values. */
pair->next = cache->pair;
pair->last_updated = bson_get_monotonic_time() / 1000;
cache->pair = pair;
return pair;
}
/* Caller must hold lock. */
static void _cache_pair_destroy(_mongocrypt_cache_t *cache, _mongocrypt_cache_pair_t *pair) {
BSON_ASSERT_PARAM(cache);
BSON_ASSERT_PARAM(pair);
cache->destroy_attr(pair->attr);
cache->destroy_value(pair->value);
bson_free(pair);
}
bool _mongocrypt_cache_get(_mongocrypt_cache_t *cache,
void *attr, /* attr of cache item */
void **value /* copied to. */) {
_mongocrypt_cache_pair_t *match;
BSON_ASSERT_PARAM(cache);
BSON_ASSERT_PARAM(attr);
BSON_ASSERT_PARAM(value);
*value = NULL;
_mongocrypt_mutex_lock(&cache->mutex);
/* TODO CDRIVER-3120: optimize the eviction algorithm to avoid unnecessary
* O(n) traversal */
_mongocrypt_cache_evict(cache);
if (!_find_pair(cache, attr, &match)) {
_mongocrypt_mutex_unlock(&cache->mutex);
return false;
}
if (match) {
*value = cache->copy_value(match->value);
}
_mongocrypt_mutex_unlock(&cache->mutex);
return true;
}
static bool
_cache_add(_mongocrypt_cache_t *cache, void *attr, void *value, mongocrypt_status_t *status, bool steal_value) {
_mongocrypt_cache_pair_t *pair;
BSON_ASSERT_PARAM(cache);
BSON_ASSERT_PARAM(attr);
BSON_ASSERT_PARAM(value);
_mongocrypt_mutex_lock(&cache->mutex);
_mongocrypt_cache_evict(cache);
if (!_mongocrypt_remove_matches(cache, attr)) {
CLIENT_ERR("error removing from cache");
_mongocrypt_mutex_unlock(&cache->mutex);
return false;
}
pair = _pair_new(cache, attr);
if (steal_value) {
pair->value = value;
} else {
pair->value = cache->copy_value(value);
}
_mongocrypt_mutex_unlock(&cache->mutex);
return true;
}
bool _mongocrypt_cache_add_copy(_mongocrypt_cache_t *cache, void *attr, void *value, mongocrypt_status_t *status) {
BSON_ASSERT_PARAM(cache);
BSON_ASSERT_PARAM(attr);
BSON_ASSERT_PARAM(value);
return _cache_add(cache, attr, value, status, false);
}
bool _mongocrypt_cache_add_stolen(_mongocrypt_cache_t *cache, void *attr, void *value, mongocrypt_status_t *status) {
BSON_ASSERT_PARAM(cache);
BSON_ASSERT_PARAM(attr);
BSON_ASSERT_PARAM(value);
return _cache_add(cache, attr, value, status, true);
}
void _mongocrypt_cache_cleanup(_mongocrypt_cache_t *cache) {
_mongocrypt_cache_pair_t *pair, *tmp;
if (!cache) {
return;
}
pair = cache->pair;
while (pair) {
tmp = pair->next;
_cache_pair_destroy(cache, pair);
pair = tmp;
}
}
uint32_t _mongocrypt_cache_num_entries(_mongocrypt_cache_t *cache) {
_mongocrypt_cache_pair_t *pair;
uint32_t count;
BSON_ASSERT_PARAM(cache);
_mongocrypt_mutex_lock(&cache->mutex);
count = 0;
for (pair = cache->pair; pair != NULL; pair = pair->next) {
count++;
}
_mongocrypt_mutex_unlock(&cache->mutex);
return count;
}

File Metadata

Mime Type
text/x-c
Expires
Sat, Nov 14, 5:05 PM (11 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
134849
Default Alt Text
mongocrypt-cache.c (6 KB)

Event Timeline