[svn-commits] rmudgett: branch rmudgett/stasis_cache r408732 - /team/rmudgett/stasis_cache/...

SVN commits to the Digium repositories svn-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 svn-commits mailing list