[asterisk-commits] rmudgett: branch rmudgett/stasis_cache r408732 - /team/rmudgett/stasis_cache/...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Feb 21 12:42:28 CST 2014
Author: rmudgett
Date: Fri Feb 21 12:42:25 2014
New Revision: 408732
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=408732
Log:
stasus_cache.c: Misc cache entries container improvements.
* Made the cache entries container callbacks support OBJ_SEARCH_KEY as
well as using the callback function templates.
* Made the cache entries container use a rwlock instead of a mutex.
* Fixed potential reentrancy issue when retrieving a snapshot from the
cache entries container in stasis_cache_get().
Modified:
team/rmudgett/stasis_cache/main/stasis_cache.c
Modified: team/rmudgett/stasis_cache/main/stasis_cache.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/stasis_cache/main/stasis_cache.c?view=diff&rev=408732&r1=408731&r2=408732
==============================================================================
--- team/rmudgett/stasis_cache/main/stasis_cache.c (original)
+++ team/rmudgett/stasis_cache/main/stasis_cache.c Fri Feb 21 12:42:25 2014
@@ -124,9 +124,13 @@
return NULL;
}
-struct cache_entry {
+struct cache_entry_key {
struct stasis_message_type *type;
const char *id;
+};
+
+struct cache_entry {
+ struct cache_entry_key key;
struct stasis_message *snapshot;
};
@@ -134,19 +138,12 @@
{
struct cache_entry *entry = obj;
- ao2_cleanup(entry->type);
- entry->type = NULL;
- ast_free((char *) entry->id);
- entry->id = NULL;
+ ao2_cleanup(entry->key.type);
+ entry->key.type = NULL;
+ ast_free((char *) entry->key.id);
+ entry->key.id = NULL;
ao2_cleanup(entry->snapshot);
entry->snapshot = NULL;
-}
-
-static void cache_entry_init(struct cache_entry *entry, struct stasis_message_type *type, const char *id, struct stasis_message *snapshot)
-{
- entry->type = type;
- entry->id = id;
- entry->snapshot = snapshot;
}
static struct cache_entry *cache_entry_create(struct stasis_message_type *type, const char *id, struct stasis_message *snapshot)
@@ -162,39 +159,79 @@
return NULL;
}
- cache_entry_init(entry, ao2_bump(type), ast_strdup(id), ao2_bump(snapshot));
- if (!entry->id) {
+ entry->key.id = ast_strdup(id);
+ if (!entry->key.id) {
ao2_cleanup(entry);
return NULL;
}
+ entry->key.type = ao2_bump(type);
+
+ entry->snapshot = ao2_bump(snapshot);
return entry;
}
static int cache_entry_hash(const void *obj, int flags)
{
- const struct cache_entry *entry = obj;
+ const struct cache_entry *object;
+ const struct cache_entry_key *key;
int hash = 0;
- ast_assert(!(flags & OBJ_KEY));
-
- hash += ast_hashtab_hash_string(stasis_message_type_name(entry->type));
- hash += ast_hashtab_hash_string(entry->id);
+ switch (flags & OBJ_SEARCH_MASK) {
+ case OBJ_SEARCH_KEY:
+ key = obj;
+ break;
+ case OBJ_SEARCH_OBJECT:
+ object = obj;
+ key = &object->key;
+ break;
+ default:
+ /* Hash can only work on something with a full key. */
+ ast_assert(0);
+ return 0;
+ }
+
+ hash += ast_hashtab_hash_string(stasis_message_type_name(key->type));
+ hash += ast_hashtab_hash_string(key->id);
return hash;
}
static int cache_entry_cmp(void *obj, void *arg, int flags)
{
- const struct cache_entry *left = obj;
- const struct cache_entry *right = arg;
-
- ast_assert(!(flags & OBJ_KEY));
-
- if (left->type == right->type && strcmp(left->id, right->id) == 0) {
- return CMP_MATCH | CMP_STOP;
- }
-
- return 0;
+ const struct cache_entry *object_left = obj;
+ const struct cache_entry *object_right = arg;
+ const struct cache_entry_key *right_key = obj;
+ int cmp;
+
+ switch (flags & OBJ_SEARCH_MASK) {
+ case OBJ_SEARCH_OBJECT:
+ right_key = &object_right->key;
+ /* Fall through */
+ case OBJ_SEARCH_KEY:
+ cmp = object_left->key.type != right_key->type
+ || strcmp(object_left->key.id, right_key->id);
+ break;
+ case OBJ_SEARCH_PARTIAL_KEY:
+ /* Not supported by container */
+ ast_assert(0);
+ cmp = -1;
+ break;
+ default:
+ /*
+ * What arg points to is specific to this traversal callback
+ * and has no special meaning to astobj2.
+ */
+ cmp = 0;
+ break;
+ }
+ if (cmp) {
+ return 0;
+ }
+ /*
+ * At this point the traversal callback is identical to a sorted
+ * container.
+ */
+ return CMP_MATCH;
}
static void cache_dtor(void *obj)
@@ -215,8 +252,8 @@
return NULL;
}
- cache->entries = ao2_container_alloc(NUM_CACHE_BUCKETS, cache_entry_hash,
- cache_entry_cmp);
+ cache->entries = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK, 0,
+ NUM_CACHE_BUCKETS, cache_entry_hash, NULL, cache_entry_cmp);
if (!cache->entries) {
ao2_cleanup(cache);
return NULL;
@@ -231,7 +268,7 @@
struct stasis_message_type *type, const char *id,
struct stasis_message *new_snapshot)
{
- struct cache_entry *new_entry;
+ struct cache_entry_key search_key;
struct cache_entry *cached_entry;
struct stasis_message *old_snapshot = NULL;
@@ -239,59 +276,63 @@
ast_assert(new_snapshot == NULL ||
type == stasis_message_type(new_snapshot));
- new_entry = cache_entry_create(type, id, new_snapshot);
- if (!new_entry) {
- return NULL;
- }
+ ao2_wrlock(cache->entries);
+
+ search_key.type = type;
+ search_key.id = id;
if (new_snapshot == NULL) {
/* Remove entry from cache */
- cached_entry = ao2_find(cache->entries, new_entry, OBJ_POINTER | OBJ_UNLINK);
+ cached_entry = ao2_find(cache->entries, &search_key, OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NOLOCK);
if (cached_entry) {
old_snapshot = cached_entry->snapshot;
cached_entry->snapshot = NULL;
}
} else {
/* Insert/update cache */
- SCOPED_AO2LOCK(lock, cache->entries);
-
- cached_entry = ao2_find(cache->entries, new_entry, OBJ_POINTER | OBJ_NOLOCK);
+ cached_entry = ao2_find(cache->entries, &search_key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
if (cached_entry) {
/* Update cache. Because objects are moving, no need to update refcounts. */
old_snapshot = cached_entry->snapshot;
- cached_entry->snapshot = new_entry->snapshot;
- new_entry->snapshot = NULL;
+ cached_entry->snapshot = ao2_bump(new_snapshot);
} else {
/* Insert into the cache */
- ao2_link_flags(cache->entries, new_entry, OBJ_NOLOCK);
+ cached_entry = cache_entry_create(type, id, new_snapshot);
+ if (cached_entry) {
+ ao2_link_flags(cache->entries, cached_entry, OBJ_NOLOCK);
+ }
}
}
- ao2_cleanup(new_entry);
+ ao2_unlock(cache->entries);
+
ao2_cleanup(cached_entry);
return old_snapshot;
}
struct stasis_message *stasis_cache_get(struct stasis_cache *cache, struct stasis_message_type *type, const char *id)
{
- struct cache_entry search_entry;
+ struct cache_entry_key search_key;
struct cache_entry *cached_entry;
- struct stasis_message *snapshot;
-
+ struct stasis_message *snapshot = NULL;
+
+ ast_assert(cache != NULL);
ast_assert(cache->entries != NULL);
ast_assert(type != NULL);
ast_assert(id != NULL);
- cache_entry_init(&search_entry, type, id, NULL);
-
- cached_entry = ao2_find(cache->entries, &search_entry, OBJ_POINTER);
- if (!cached_entry) {
- return NULL;
- }
-
- ast_assert(cached_entry->snapshot != NULL);
- snapshot = cached_entry->snapshot;
- ao2_ref(snapshot, +1);
+ ao2_rdlock(cache->entries);
+
+ search_key.type = type;
+ search_key.id = id;
+
+ cached_entry = ao2_find(cache->entries, &search_key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
+ if (cached_entry) {
+ snapshot = cached_entry->snapshot;
+ ao2_bump(snapshot);
+ }
+
+ ao2_unlock(cache->entries);
ao2_cleanup(cached_entry);
return snapshot;
@@ -307,7 +348,7 @@
struct cache_dump_data *cache_dump = arg;
struct cache_entry *entry = obj;
- if (!cache_dump->type || entry->type == cache_dump->type) {
+ if (!cache_dump->type || entry->key.type == cache_dump->type) {
ao2_link(cache_dump->cached, entry->snapshot);
}
More information about the asterisk-commits
mailing list