[svn-commits] rmudgett: branch rmudgett/ao2_enhancements r370733 - /team/rmudgett/ao2_enhan...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Wed Aug 1 17:36:05 CDT 2012
Author: rmudgett
Date: Wed Aug 1 17:36:01 2012
New Revision: 370733
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=370733
Log:
Containers can be sorted now.
Modified:
team/rmudgett/ao2_enhancements/main/astobj2.c
Modified: team/rmudgett/ao2_enhancements/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/ao2_enhancements/main/astobj2.c?view=diff&rev=370733&r1=370732&r2=370733
==============================================================================
--- team/rmudgett/ao2_enhancements/main/astobj2.c (original)
+++ team/rmudgett/ao2_enhancements/main/astobj2.c Wed Aug 1 17:36:01 2012
@@ -724,6 +724,15 @@
return obj;
}
+
+enum ao2_container_insert {
+ /*! The node was inserted into the container. */
+ AO2_CONTAINER_INSERT_NODE_INSERTED,
+ /*! The node object replaced an existing node object. */
+ AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED,
+ /*! The node was rejected (duplicate). */
+ AO2_CONTAINER_INSERT_NODE_REJECTED,
+};
/* BUGBUG may not be needed */
enum ao2_container_type {
@@ -1516,18 +1525,106 @@
adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1);
bucket = &my_container->buckets[doomed->my_bucket];
-/* BUGBUG need to check if hash_ao2_link() will have problems on failure paths. */
AST_DLLIST_REMOVE(&bucket->list, doomed, links);
}
/*
* We could have an object in the node if the container is being
- * destroyed or the object hasn't been linked in yet.
+ * destroyed or the node had not been linked in yet.
*/
if (doomed->obj) {
ao2_ref(doomed->obj, -1);
doomed->obj = NULL;
}
+}
+
+/*!
+ * \internal
+ * \brief Insert the given node into the specified bucket in the container.
+ * \since 11.0
+ *
+ * \param self Container to operate upon.
+ * \param bucket Hash bucket to insert the node.
+ * \param node What to put in the bucket list.
+ *
+ * \return enum ao2_container_insert value.
+ */
+static enum ao2_container_insert hash_ao2_link_insert(struct ao2_container_hash *self, struct hash_bucket *bucket, struct hash_bucket_node *node)
+{
+ int cmp;
+ struct hash_bucket_node *cur;
+ ao2_sort_fn *sort_fn;
+ uint32_t options;
+
+ sort_fn = self->common.sort_fn;
+ options = self->common.options;
+
+ if (options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
+ if (sort_fn) {
+ AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&bucket->list, cur, links) {
+ cmp = sort_fn(cur, node, OBJ_POINTER);
+ if (cmp > 0) {
+ continue;
+ }
+ if (cmp < 0) {
+ AST_DLLIST_INSERT_AFTER_CURRENT(node, links);
+ return AO2_CONTAINER_INSERT_NODE_INSERTED;
+ }
+ switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
+ default:
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
+ break;
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
+ /* Reject all objects with the same key. */
+ return AO2_CONTAINER_INSERT_NODE_REJECTED;
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
+ if (cur->obj == node->obj) {
+ /* Reject inserting the same object */
+ return AO2_CONTAINER_INSERT_NODE_REJECTED;
+ }
+ break;
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
+ SWAP(cur->obj, node->obj);
+ return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
+ }
+ }
+ AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
+ }
+ AST_DLLIST_INSERT_HEAD(&bucket->list, node, links);
+ } else {
+ if (sort_fn) {
+ AST_DLLIST_TRAVERSE_SAFE_BEGIN(&bucket->list, cur, links) {
+ cmp = sort_fn(cur, node, OBJ_POINTER);
+ if (cmp < 0) {
+ continue;
+ }
+ if (cmp > 0) {
+ AST_DLLIST_INSERT_BEFORE_CURRENT(node, links);
+ return AO2_CONTAINER_INSERT_NODE_INSERTED;
+ }
+ switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
+ default:
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
+ break;
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
+ /* Reject all objects with the same key. */
+ return AO2_CONTAINER_INSERT_NODE_REJECTED;
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
+ if (cur->obj == node->obj) {
+ /* Reject inserting the same object */
+ return AO2_CONTAINER_INSERT_NODE_REJECTED;
+ }
+ break;
+ case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
+ SWAP(cur->obj, node->obj);
+ return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
+ }
+ }
+ AST_DLLIST_TRAVERSE_SAFE_END;
+ }
+ AST_DLLIST_INSERT_TAIL(&bucket->list, node, links);
+ }
+ return AO2_CONTAINER_INSERT_NODE_INSERTED;
}
/*!
@@ -1549,12 +1646,9 @@
static int hash_ao2_link(struct ao2_container_hash *self, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
{
int i;
+ int res;
enum ao2_lock_req orig_lock;
struct hash_bucket_node *node;
-
-/*! BUGBUG hash_ao2_link() need to add sorting support */
-/*! BUGBUG hash_ao2_link() need to add insert option support */
-/*! BUGBUG hash_ao2_link() need to add duplicate handling option support */
node = __ao2_alloc(sizeof(*node), hash_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
if (!node) {
@@ -1580,20 +1674,28 @@
node->my_container = self;
node->my_bucket = i;
- if (self->common.options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
- AST_DLLIST_INSERT_HEAD(&self->buckets[i].list, node, links);
- } else {
- AST_DLLIST_INSERT_TAIL(&self->buckets[i].list, node, links);
- }
-
+ /* Insert the new node. */
+ res = 0;
+ switch (hash_ao2_link_insert(self, &self->buckets[i], node)) {
+ case AO2_CONTAINER_INSERT_NODE_INSERTED:
#if defined(AST_DEVMODE)
- ++self->buckets[i].elements;
- if (self->buckets[i].max_elements < self->buckets[i].elements) {
- self->buckets[i].max_elements = self->buckets[i].elements;
- }
+ ++self->buckets[i].elements;
+ if (self->buckets[i].max_elements < self->buckets[i].elements) {
+ self->buckets[i].max_elements = self->buckets[i].elements;
+ }
#endif /* defined(AST_DEVMODE) */
- ast_atomic_fetchadd_int(&self->common.elements, 1);
-
+ ast_atomic_fetchadd_int(&self->common.elements, 1);
+
+ res = 1;
+ break;
+ case AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED:
+ res = 1;
+ /* Fall through */
+ case AO2_CONTAINER_INSERT_NODE_REJECTED:
+ node->my_container = NULL;
+ ao2_ref(node, -1);
+ break;
+ }
if (flags & OBJ_NOLOCK) {
adjust_lock(self, orig_lock, 0);
@@ -1601,7 +1703,7 @@
ao2_unlock(self);
}
- return 1;
+ return res;
}
/*!
@@ -1644,8 +1746,8 @@
ao2_callback_data_fn *cb_withdata = NULL;
struct ao2_container *multi_container = NULL;
struct ao2_iterator *multi_iterator = NULL;
-
-/*! BUGBUG hash_ao2_callback() need to add sorting support */
+ ao2_sort_fn *sort_fn;
+
/*! BUGBUG hash_ao2_callback() need to add traverse order option support */
/*
* This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA
@@ -1697,9 +1799,11 @@
if ((flags & (OBJ_POINTER | OBJ_KEY))) {
/* we know hash can handle this case */
start = i = self->hash_fn(arg, flags & (OBJ_POINTER | OBJ_KEY)) % self->n_buckets;
+ sort_fn = self->common.sort_fn;
} else {
/* don't know, let's scan all buckets */
start = i = -1; /* XXX this must be fixed later. */
+ sort_fn = NULL;
}
/* determine the search boundaries: i..last-1 */
@@ -1743,6 +1847,21 @@
__ao2_ref(node, +1);
do {
+ if (sort_fn) {
+ int cmp;
+
+ cmp = sort_fn(node, arg, flags & (OBJ_POINTER | OBJ_KEY));
+ if (cmp < 0) {
+ match = 0;
+ goto next_bucket_node;
+ }
+ if (cmp > 0) {
+ /* No more nodes in this bucket are possible to match. */
+ match = 0;
+ break;
+ }
+ }
+
/* Visit the current node. */
match = (CMP_MATCH | CMP_STOP);
if (type == WITH_DATA) {
@@ -1930,15 +2049,7 @@
}
} else {
/* Find first non-empty node. */
- cur_bucket = 0;
- node = AST_DLLIST_FIRST(&self->buckets[cur_bucket].list);
- while (node && !node->obj) {
- node = AST_DLLIST_NEXT(node, links);
- }
- if (node) {
- /* Found a non-empty node. */
- goto hash_found;
- }
+ cur_bucket = -1;
}
/* Find a non-empty node in the remaining buckets */
More information about the svn-commits
mailing list