You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by tr...@apache.org on 2015/09/18 21:55:46 UTC

[1/2] qpid-dispatch git commit: DISPATCH-159: Introducing on a hierarchical/graduated address hashing scheme which retrieves the address based on the hash by progressively first exact matching or later prefix matching the address components

Repository: qpid-dispatch
Updated Branches:
  refs/heads/master 2e1bf7eeb -> 12d201960


DISPATCH-159: Introducing on a hierarchical/graduated address hashing scheme which retrieves the address based on the hash by progressively first exact matching or later prefix matching the address components


Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/029ab004
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/029ab004
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/029ab004

Branch: refs/heads/master
Commit: 029ab004dfcd7b8e82b1bdc28b104ac6bdc18b98
Parents: 2e1bf7e
Author: ganeshmurthy <gm...@redhat.com>
Authored: Fri Sep 18 15:27:29 2015 -0400
Committer: ganeshmurthy <gm...@redhat.com>
Committed: Fri Sep 18 15:34:21 2015 -0400

----------------------------------------------------------------------
 include/qpid/dispatch/hash.h                  |  19 +++
 include/qpid/dispatch/iterator.h              |  42 +++++
 python/qpid_dispatch/management/qdrouter.json |   4 +-
 src/hash.c                                    |  90 +++++++----
 src/iterator.c                                | 172 +++++++++++++++++++--
 src/router_node.c                             |  28 +---
 tests/field_test.c                            | 151 ++++++++++++++++++
 7 files changed, 438 insertions(+), 68 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/029ab004/include/qpid/dispatch/hash.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/hash.h b/include/qpid/dispatch/hash.h
index f3c362a..aaedc0b 100644
--- a/include/qpid/dispatch/hash.h
+++ b/include/qpid/dispatch/hash.h
@@ -45,5 +45,24 @@ const unsigned char *qd_hash_key_by_handle(const qd_hash_handle_t *handle);
 qd_error_t qd_hash_remove_by_handle(qd_hash_t *h, qd_hash_handle_t *handle);
 qd_error_t qd_hash_remove_by_handle2(qd_hash_t *h, qd_hash_handle_t *handle, unsigned char **key);
 
+/**
+ * Retrieves the value (qd_address_t) based on the hash by progressively first exact matching or prefix matching the address components.
+ * If the iterator contains an address string 'policy/org/apache/dev' and the hashtable contains the hash for 'policy/org',
+ * this function will look for the following in that order
+ *  1. 'policy/org/apache/dev' - no match, proceed to step 2
+ *  2. 'policy/org/apache' - no match, proceed to step 3
+ *  3. 'policy/org' - We got a match here. This match is a prefix match - return the qd_address_t associated with this
+ *
+ * @param qd_hash_t
+ * @param iter An iterator containing the address string to search on.
+ * @param **val The qd_address_t value if there is a full or prefix match.
+ */
+void qd_hash_retrieve_prefix(qd_hash_t *h, qd_field_iterator_t *iter, void **val);
+
+/**
+ * Same as qd_hash_retrieve_prefix but returns the value as a constant which cannot be modified.
+ * @see qd_hash_retrieve_prefix
+ */
+void qd_hash_retrieve_prefix_const(qd_hash_t *h, qd_field_iterator_t *iter, const void **val);
 
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/029ab004/include/qpid/dispatch/iterator.h
----------------------------------------------------------------------
diff --git a/include/qpid/dispatch/iterator.h b/include/qpid/dispatch/iterator.h
index 80b3bb0..f82db1b 100644
--- a/include/qpid/dispatch/iterator.h
+++ b/include/qpid/dispatch/iterator.h
@@ -20,6 +20,7 @@
  */
 
 #include <stdint.h>
+#include <stdbool.h>
 #include <qpid/dispatch/buffer.h>
 #include <qpid/dispatch/iovec.h>
 
@@ -112,6 +113,7 @@ typedef enum {
  */
 qd_field_iterator_t* qd_address_iterator_string(const char         *text,
                                                 qd_iterator_view_t  view);
+
 static inline qd_field_iterator_t* qd_field_iterator_string(const char *text)
 {
     return qd_address_iterator_string(text, ITER_VIEW_ALL);
@@ -261,6 +263,46 @@ char* qd_field_iterator_strncpy(qd_field_iterator_t *iter, char* buffer, int n);
  */
 qd_iovec_t *qd_field_iterator_iovec(const qd_field_iterator_t *iter);
 
+/**
+ * Steps through the iterator hashing each octet and also trying to find a separator. The separator is hardcoded to be a '/'.
+ * It stores the hash of each segment as a node (qd_hash_segment_t) in the linked list qd_hash_segment_list_t of the iterator.
+ * The linked list contains as many nodes as there are segments.
+ *
+ *     +------------------------+
+ *     |                        |
+ *     | qd_hash_segment_list_t |----------->+
+ *     |                        |            |
+ *     +------------------------+            |       "policy"              "policy/org"            "policy/org/apache"
+ *                                           |    +-------------------+   +-------------------+   +-------------------+
+ *                                           +--->| qd_hash_segment_t |-->| qd_hash_segment_t |-->| qd_hash_segment_t |--/
+ *                                                +-------------------+   +-------------------+   +-------------------+
+ *
+ * In the above example the first qd_hash_segment_t stores the hash of the string "policy" and the next qd_hash_segment_t contains \
+ * the hash to "policy/org" and so on. The purpose of doing this is to pre-generate the hash and hash length and store
+ * it so matches can be quickly made.
+ *
+ *
+ * @param iter An address iterator
+ */
+void qd_iterator_hash_segments(qd_field_iterator_t *iter);
+
+/**
+ * Populates the passed in hash with the hash from the tail hash segment and deletes and frees it.
+ * This hash can be further used arrive at the hash bucket.
+ * Returns false if it cannot find anymore tail hash_segments, true otherwise.
+ *
+ * @param iter A field iterator
+ */
+bool qd_iterator_hash_and_reset(qd_field_iterator_t *iter, uint32_t *hash);
+
+/**
+ * Generates and returns a hash of the contents of the iterator by stepping through the iterator octet by octet.
+ * Uses the djb2 algorithm for hashing - can be found at http://www.cse.yorku.ca/~oz/hash.html
+ *
+ * @param iter A field iterator
+ */
+uint32_t qd_iterator_hash_function(qd_field_iterator_t *iter);
+
 /** @} */
 
 #endif

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/029ab004/python/qpid_dispatch/management/qdrouter.json
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json
index 045bae7..c5b1edb 100644
--- a/python/qpid_dispatch/management/qdrouter.json
+++ b/python/qpid_dispatch/management/qdrouter.json
@@ -794,7 +794,7 @@
             "operations": ["CREATE"],
             "attributes": {
                 "prefix": {
-                    "description":"An address prefix to match against target and source addresses.  For Dispatch 0.4, this pattern must be of the form '<text>.' and matches any address that contains that prefix.  Note that a prefix *must* end with a period (.) and *must not* contain any other periods.  If the string does not end in a period, it will match only addresses that are exactly equal.",
+                    "description":"An address prefix to match against target and source addresses.  From Dispatch 0.6 onwards, this pattern must be of the form '<text>/<text1>/...' or just '<text>' and matches any address that contains that prefix.  For example, if the prefix is set to org/apache any address that has the prefix 'org/apache' like org/apache/dev will match. Note that a prefix must not start or end with a slash (/) and can contain zero or more slashes (/).  Any characters between the slashes are simply treated as part of the address",
                     "type": "string",
                     "required": true,
                     "create": true
@@ -870,7 +870,7 @@
                     "type": "string"
                 },
                 "validOrigins": {
-                    "description": "List of valid origin nodes for messages arriving via the remote node, used for duplicate elimination in redundant networks.",
+                    "description": "List of valid origin nodes for messages arriving via the re mote node, used for duplicate elimination in redundant networks.",
                     "type": "list"
                 },
                 "address": {

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/029ab004/src/hash.c
----------------------------------------------------------------------
diff --git a/src/hash.c b/src/hash.c
index 22d3237..b5471f0 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -17,11 +17,13 @@
  * under the License.
  */
 
-#include <qpid/dispatch/hash.h>
-#include <qpid/dispatch/ctools.h>
-#include "alloc.h"
+
+
 #include <stdio.h>
 #include <string.h>
+#include "alloc.h"
+#include <qpid/dispatch/hash.h>
+#include <qpid/dispatch/ctools.h>
 
 typedef struct qd_hash_item_t {
     DEQ_LINKS(struct qd_hash_item_t);
@@ -61,22 +63,6 @@ ALLOC_DECLARE(qd_hash_handle_t);
 ALLOC_DEFINE(qd_hash_handle_t);
 
 
-// djb2 hash algorithm
-static unsigned long qd_hash_function(qd_field_iterator_t *iter)
-{
-    unsigned long hash = 5381;
-    int c;
-
-    qd_field_iterator_reset(iter);
-    while (!qd_field_iterator_end(iter)) {
-        c = (int) qd_field_iterator_octet(iter);
-        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
-    }
-
-    return hash;
-}
-
-
 qd_hash_t *qd_hash(int bucket_exponent, int batch_size, int value_is_const)
 {
     int i;
@@ -127,7 +113,7 @@ size_t qd_hash_size(qd_hash_t *h)
 
 static qd_hash_item_t *qd_hash_internal_insert(qd_hash_t *h, qd_field_iterator_t *key, int *exists, qd_hash_handle_t **handle)
 {
-    unsigned long   idx  = qd_hash_function(key) & h->bucket_mask;
+    unsigned long   idx  = qd_iterator_hash_function(key) & h->bucket_mask;
     qd_hash_item_t *item = DEQ_HEAD(h->buckets[idx].items);
 
     while (item) {
@@ -197,18 +183,68 @@ qd_error_t qd_hash_insert_const(qd_hash_t *h, qd_field_iterator_t *key, const vo
 }
 
 
+static qd_hash_item_t *qd_hash_internal_retrieve_with_hash(qd_hash_t *h, uint32_t hash, qd_field_iterator_t *key)
+{
+    uint32_t   idx  = hash & h->bucket_mask;
+
+	qd_hash_item_t *item = DEQ_HEAD(h->buckets[idx].items);
+
+	while (item) {
+		if (qd_field_iterator_equal(key, item->key))
+			break;
+		item = item->next;
+	}
+
+	return item;
+}
+
+
 static qd_hash_item_t *qd_hash_internal_retrieve(qd_hash_t *h, qd_field_iterator_t *key)
 {
-    unsigned long   idx  = qd_hash_function(key) & h->bucket_mask;
-    qd_hash_item_t *item = DEQ_HEAD(h->buckets[idx].items);
+    uint32_t hash = qd_iterator_hash_function(key);
+    return qd_hash_internal_retrieve_with_hash(h, hash, key);
+}
 
-    while (item) {
-        if (qd_field_iterator_equal(key, item->key))
+
+void qd_hash_retrieve_prefix(qd_hash_t *h, qd_field_iterator_t *iter, void **val)
+{
+	//Hash individual segments by iterating thru the octets in the iterator.
+	qd_iterator_hash_segments(iter);
+
+	uint32_t hash = 0;
+
+	qd_hash_item_t *item;
+	while (qd_iterator_hash_and_reset(iter, &hash)) {
+		item = qd_hash_internal_retrieve_with_hash(h, hash, iter);
+		if (item)
+			break;
+	}
+
+	if (item)
+		*val = item->v.val;
+	else
+		*val = 0;
+}
+
+
+void qd_hash_retrieve_prefix_const(qd_hash_t *h, qd_field_iterator_t *iter, const void **val)
+{
+    assert(h->is_const);
+
+    uint32_t hash = 0;
+
+    qd_hash_item_t *item;
+
+    while (qd_iterator_hash_and_reset(iter, &hash)) {
+        item = qd_hash_internal_retrieve_with_hash(h, hash, iter);
+        if (item)
             break;
-        item = item->next;
     }
 
-    return item;
+    if (item)
+        *val = item->v.val_const;
+    else
+        *val = 0;
 }
 
 
@@ -240,7 +276,7 @@ qd_error_t qd_hash_retrieve_const(qd_hash_t *h, qd_field_iterator_t *key, const
 
 qd_error_t qd_hash_remove(qd_hash_t *h, qd_field_iterator_t *key)
 {
-    unsigned long   idx  = qd_hash_function(key) & h->bucket_mask;
+    uint32_t   idx  = qd_iterator_hash_function(key) & h->bucket_mask;
     qd_hash_item_t *item = DEQ_HEAD(h->buckets[idx].items);
 
     while (item) {

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/029ab004/src/iterator.c
----------------------------------------------------------------------
diff --git a/src/iterator.c b/src/iterator.c
index 47af8f7..1068e1b 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -44,23 +44,35 @@ typedef struct {
     int            length;
 } pointer_t;
 
+typedef struct qd_hash_segment_t qd_hash_segment_t;
+
+struct qd_hash_segment_t {
+    DEQ_LINKS(qd_hash_segment_t); //Adds the *prev and *next links
+    uint32_t   hash; //The hash of the segment
+    uint32_t segment_length; //The length of each hash segment
+};
+
+DEQ_DECLARE(qd_hash_segment_t, qd_hash_segment_list_t);
+ALLOC_DECLARE(qd_hash_segment_t);
+ALLOC_DEFINE(qd_hash_segment_t);
+
 struct qd_field_iterator_t {
-    pointer_t           start_pointer;
-    pointer_t           view_start_pointer;
-    pointer_t           pointer;
-    qd_iterator_view_t  view;
-    parse_mode_t        mode;
-    addr_state_t        state;
-    bool                view_prefix;
-    unsigned char       prefix;
-    unsigned char       prefix_override;
-    unsigned char       phase;
+    pointer_t               start_pointer;
+    pointer_t               view_start_pointer;
+    pointer_t               pointer;
+    qd_iterator_view_t      view;
+    qd_hash_segment_list_t  hash_segments;
+    parse_mode_t            mode;
+    addr_state_t            state;
+    bool                    view_prefix;
+    unsigned char           prefix;
+    unsigned char           prefix_override;
+    unsigned char           phase;
 };
 
 ALLOC_DECLARE(qd_field_iterator_t);
 ALLOC_DEFINE(qd_field_iterator_t);
 
-
 typedef enum {
     STATE_START,
     STATE_SLASH_LEFT,
@@ -75,6 +87,9 @@ typedef enum {
 static char *my_area    = "";
 static char *my_router  = "";
 
+const char SEPARATOR_SLASH = '/';
+
+const uint32_t HASH_INIT = 5381;
 
 
 static void parse_address_view(qd_field_iterator_t *iter)
@@ -146,6 +161,27 @@ static void parse_node_view(qd_field_iterator_t *iter)
 }
 
 
+static void qd_address_iterator_check_trailing_octet(qd_field_iterator_t *iter, char octet)
+{
+    // Save the iterator's pointer so we can apply it back before returning from this function.
+    pointer_t save_pointer = iter->pointer;
+
+    char current_octet;
+    while(!qd_field_iterator_end(iter)) {
+        current_octet = qd_field_iterator_octet(iter);
+    }
+
+    // We have the last octet in current_octet
+    if (current_octet == octet) {
+        iter->pointer = save_pointer;
+        iter->pointer.length-- ;
+    }
+    else {
+        iter->pointer = save_pointer;
+    }
+}
+
+
 static void view_initialize(qd_field_iterator_t *iter)
 {
     //
@@ -168,6 +204,7 @@ static void view_initialize(qd_field_iterator_t *iter)
 
     while (!qd_field_iterator_end(iter) && state != STATE_AT_NODE_ID) {
         octet = qd_field_iterator_octet(iter);
+
         switch (state) {
         case STATE_START :
             if (octet == '/')
@@ -238,6 +275,7 @@ static void view_initialize(qd_field_iterator_t *iter)
 
     if (iter->view == ITER_VIEW_ADDRESS_HASH) {
         iter->mode = MODE_TO_END;
+        qd_address_iterator_check_trailing_octet(iter, '/');
         parse_address_view(iter);
         return;
     }
@@ -312,11 +350,13 @@ qd_field_iterator_t* qd_address_iterator_string(const char *text, qd_iterator_vi
     if (!iter)
         return 0;
 
-    iter->start_pointer.buffer = 0;
-    iter->start_pointer.cursor = (unsigned char*) text;
-    iter->start_pointer.length = strlen(text);
-    iter->phase                = '0';
-    iter->prefix_override      = '\0';
+    iter->start_pointer.buffer     = 0;
+    iter->start_pointer.cursor     = (unsigned char*) text;
+    iter->start_pointer.length     = strlen(text);
+    iter->phase                    = '0';
+    iter->prefix_override          = '\0';
+
+    DEQ_INIT(iter->hash_segments);
 
     qd_address_iterator_reset_view(iter, view);
 
@@ -479,8 +519,9 @@ uint32_t qd_field_iterator_remaining(const qd_field_iterator_t *iter)
 int qd_field_iterator_equal(qd_field_iterator_t *iter, const unsigned char *string)
 {
     qd_field_iterator_reset(iter);
+
     while (!qd_field_iterator_end(iter) && *string) {
-        if (*string != qd_field_iterator_octet(iter))
+    	if (*string != qd_field_iterator_octet(iter))
             break;
         string++;
     }
@@ -510,6 +551,7 @@ int qd_field_iterator_prefix(qd_field_iterator_t *iter, const char *prefix)
     return 1;
 }
 
+
 int qd_field_iterator_length(const qd_field_iterator_t *iter)
 {
     qd_field_iterator_t copy = *iter;
@@ -522,6 +564,7 @@ int qd_field_iterator_length(const qd_field_iterator_t *iter)
     return length;
 }
 
+
 int qd_field_iterator_ncopy(qd_field_iterator_t *iter, unsigned char* buffer, int n) {
     qd_field_iterator_reset(iter);
     int i = 0;
@@ -530,12 +573,14 @@ int qd_field_iterator_ncopy(qd_field_iterator_t *iter, unsigned char* buffer, in
     return i;
 }
 
+
 char* qd_field_iterator_strncpy(qd_field_iterator_t *iter, char* buffer, int n) {
     int i = qd_field_iterator_ncopy(iter, (unsigned char*)buffer, n-1);
     buffer[i] = '\0';
     return buffer;
 }
 
+
 unsigned char *qd_field_iterator_copy(qd_field_iterator_t *iter)
 {
     int length = qd_field_iterator_length(iter);
@@ -599,3 +644,96 @@ qd_iovec_t *qd_field_iterator_iovec(const qd_field_iterator_t *iter)
 
     return iov;
 }
+
+
+uint32_t qd_iterator_hash_function(qd_field_iterator_t *iter)
+{
+    uint32_t hash = HASH_INIT;
+
+    qd_field_iterator_reset(iter);
+    while (!qd_field_iterator_end(iter))
+        hash = ((hash << 5) + hash) + (int) qd_field_iterator_octet(iter); /* hash * 33 + c */
+
+    return hash;
+}
+
+
+/**
+ * Creates and returns a new qd_hash_segment_t and initializes it.
+ */
+static qd_hash_segment_t *qd_iterator_hash_segment(void)
+{
+    qd_hash_segment_t *hash_segment = new_qd_hash_segment_t();
+    DEQ_ITEM_INIT(hash_segment);
+    hash_segment->hash       = 0;
+    hash_segment->segment_length = 0;
+    return hash_segment;
+}
+
+
+/**
+ * Create a new hash segment and insert it at the end of the linked list
+ */
+static void qd_insert_hash_segment(qd_field_iterator_t *iter, uint32_t *hash, int segment_length)
+{
+    qd_hash_segment_t *hash_segment = qd_iterator_hash_segment();
+
+    // While storing the segment, don't include the hash of the separator in the segment but do include it in the overall hash.
+    hash_segment->hash = *hash;
+    hash_segment->segment_length = segment_length - 1;
+    DEQ_INSERT_TAIL(iter->hash_segments, hash_segment);
+}
+
+
+void qd_iterator_hash_segments(qd_field_iterator_t *iter)
+{
+    // Reset the pointers in the iterator
+    qd_field_iterator_reset(iter);
+    uint32_t hash = HASH_INIT;
+    char octet;
+    int segment_length=0;
+    while (!qd_field_iterator_end(iter)) {
+        // Get the octet at which the iterator is currently pointing to.
+        octet = qd_field_iterator_octet(iter);
+        segment_length += 1;
+
+        if (octet == SEPARATOR_SLASH) {
+            qd_insert_hash_segment(iter, &hash, segment_length);
+        }
+
+        hash = ((hash << 5) + hash) + octet; /* hash * 33 + c */
+    }
+
+    // Segments should never end with a separator. see view_initialize which in turn calls qd_address_iterator_check_trailing_octet
+    // Insert the last segment
+    qd_insert_hash_segment(iter, &hash, segment_length);
+
+    // Return the pointers in the iterator back to the original state.
+    qd_field_iterator_reset(iter);
+}
+
+
+bool qd_iterator_hash_and_reset(qd_field_iterator_t *iter, uint32_t *hash)
+{
+    qd_hash_segment_t *hash_segment = DEQ_TAIL(iter->hash_segments);
+    if (!hash_segment)
+        return false;
+
+    *hash = hash_segment->hash;
+
+    // Get the length of the hashed segment and set it on the iterator so that the iterator can only advance till that length
+    // Check for a non empty iter->prefix and reduce the segment length by 1
+    if (iter->view_prefix) {
+        if (iter->prefix == 'M')
+            iter->view_start_pointer.length = hash_segment->segment_length - 2;
+        else
+            iter->view_start_pointer.length = hash_segment->segment_length - 1;
+    }
+
+    // Remove the tail from the hash segments since we have already compared it.
+    DEQ_REMOVE_TAIL(iter->hash_segments);
+
+    free_qd_hash_segment_t(hash_segment);
+
+    return true;
+}

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/029ab004/src/router_node.c
----------------------------------------------------------------------
diff --git a/src/router_node.c b/src/router_node.c
index e907509..a26a3af 100644
--- a/src/router_node.c
+++ b/src/router_node.c
@@ -350,9 +350,6 @@ static int qd_router_find_mask_bit_LH(qd_router_t *router, qd_link_t *link)
 }
 
 
-/**
- *
- */
 static qd_address_t *router_lookup_terminus_LH(qd_router_t *router, const char *taddr, qd_direction_t dir)
 {
     char                 addr_prefix = (dir == QD_INCOMING) ? 'C' : 'D';
@@ -363,30 +360,17 @@ static qd_address_t *router_lookup_terminus_LH(qd_router_t *router, const char *
         return 0;
 
     //
-    // Start by searching for the entire address for a match
+    // Initialize the iterator with taddr so we can traverse through taddr by traversing the iterator.
     //
     iter = qd_address_iterator_string(taddr, ITER_VIEW_ADDRESS_HASH);
-    qd_address_iterator_override_prefix(iter, addr_prefix);
-    qd_hash_retrieve(router->addr_hash, iter, (void*) &addr);
-    qd_field_iterator_free(iter);
 
-    if (addr)
-        return addr;
+    //Set the iter->prefix_override to addr_prefix
+    qd_address_iterator_override_prefix(iter, addr_prefix);
 
-    //
-    // If there was no match on the entire address, do a prefix search for the address up to
-    // and including the first '.'
-    //
-    const char *cursor = taddr;
-    while (*cursor && *cursor != '.')
-        cursor++;
-    if (*cursor == '.')
-        cursor++;
-    int len = (int) (cursor - taddr);
+    //Populate addr with the appropriate qd_address_t if the string in the iterator generated a hash
+    //that is present in the addr_hash
+    qd_hash_retrieve_prefix(router->addr_hash, iter, (void*) &addr);
 
-    iter = qd_address_iterator_binary(taddr, len, ITER_VIEW_ADDRESS_HASH);
-    qd_address_iterator_override_prefix(iter, addr_prefix);
-    qd_hash_retrieve(router->addr_hash, iter, (void*) &addr);
     qd_field_iterator_free(iter);
 
     return addr;

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/029ab004/tests/field_test.c
----------------------------------------------------------------------
diff --git a/tests/field_test.c b/tests/field_test.c
index 7833795..fd3c947 100644
--- a/tests/field_test.c
+++ b/tests/field_test.c
@@ -21,6 +21,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <qpid/dispatch/iterator.h>
+#include <qpid/dispatch/hash.h>
+#include <qpid/dispatch/router.h>
 
 #define FAIL_TEXT_SIZE 10000
 static char fail_text[FAIL_TEXT_SIZE];
@@ -165,6 +167,23 @@ static char* test_view_address_hash(void *context)
     {"_topo/my-area/my-router/my-addr",         "Lmy-addr"},
     {"_topo/my-area/router",                    "Rrouter"},
     {"amqp:/mobile",                            "M1mobile"},
+
+    // Re-run the above tests to make sure trailing slashes are ignored.
+    {"amqp:/_local/my-addr/sub/",                "Lmy-addr/sub"},
+    {"amqp:/_local/my-addr/",                    "Lmy-addr"},
+    {"amqp:/_topo/area/router/local/sub/",       "Aarea"},
+    {"amqp:/_topo/my-area/router/local/sub/",    "Rrouter"},
+    {"amqp:/_topo/my-area/my-router/local/sub/", "Llocal/sub"},
+    {"amqp:/_topo/area/all/local/sub/",          "Aarea"},
+    {"amqp:/_topo/my-area/all/local/sub/",       "Llocal/sub"},
+    {"amqp:/_topo/all/all/local/sub/",           "Llocal/sub"},
+    {"amqp://host:port/_local/my-addr/",         "Lmy-addr"},
+    {"_topo/area/router/my-addr/",               "Aarea"},
+    {"_topo/my-area/router/my-addr/",            "Rrouter"},
+    {"_topo/my-area/my-router/my-addr/",         "Lmy-addr"},
+    {"_topo/my-area/router/",                    "Rrouter"},
+    {"_topo/my-area/router:",                    "Rrouter:"},
+
     {0, 0}
     };
     int idx;
@@ -305,6 +324,134 @@ static char* test_field_advance_buffer(void *context)
     return ret;
 }
 
+static char *test_qd_hash_retrieve_prefix_separator(void *context)
+{
+    qd_hash_t *hash = qd_hash(10, 32, 0);
+    qd_field_iterator_t *iter = qd_address_iterator_string("policy/org/apache", ITER_VIEW_ADDRESS_HASH);
+    qd_address_iterator_override_prefix(iter, 'C');
+
+    // Insert that hash
+    qd_error_t error_string = qd_hash_insert(hash, iter, "TEST", 0);
+
+    // There should be no error on the insert hash
+    assert(error_string == QD_ERROR_NONE);
+
+    const char *taddr = "policy/org/apache/dev";
+
+    qd_field_iterator_t *address_iter = qd_address_iterator_string(taddr, ITER_VIEW_ADDRESS_HASH);
+    qd_address_iterator_override_prefix(address_iter, 'C');
+
+    qd_address_t *addr;
+
+    qd_hash_retrieve_prefix(hash, address_iter, (void*) &addr);
+
+    qd_field_iterator_free(iter);
+    qd_field_iterator_free(address_iter);
+
+    if(addr)
+        return 0;
+
+    return "test_qd_hash_retrieve_prefix_separator() failed";
+}
+
+
+static char *test_qd_hash_retrieve_prefix(void *context)
+{
+    qd_hash_t *hash = qd_hash(10, 32, 0);
+
+    qd_field_iterator_t *iter = qd_address_iterator_string("policy", ITER_VIEW_ADDRESS_HASH);
+    qd_address_iterator_override_prefix(iter, 'C');
+
+    // Insert that hash
+    qd_error_t error_string = qd_hash_insert(hash, iter, "TEST", 0);
+
+    // There should be no error on the insert hash
+    assert(error_string == QD_ERROR_NONE);
+
+    const char *taddr = "policy/org/apache/dev";
+
+    qd_field_iterator_t *address_iter = qd_address_iterator_string(taddr, ITER_VIEW_ADDRESS_HASH);
+    qd_address_iterator_override_prefix(address_iter, 'C');
+
+    qd_address_t *addr;
+
+    qd_hash_retrieve_prefix(hash, address_iter, (void*) &addr);
+
+    qd_field_iterator_free(iter);
+    qd_field_iterator_free(address_iter);
+
+    if(addr)
+        return 0;
+
+    return "test_qd_hash_retrieve_prefix() failed";
+}
+
+
+static char *test_qd_hash_retrieve_prefix_no_match(void *context)
+{
+    qd_hash_t *hash = qd_hash(10, 32, 0);
+
+    // No 'y' in policy. There should be no match.
+    qd_field_iterator_t *iter = qd_address_iterator_string("polic", ITER_VIEW_ADDRESS_HASH);
+    qd_address_iterator_override_prefix(iter, 'C');
+
+    // Insert that hash
+    qd_error_t error_string = qd_hash_insert(hash, iter, "TEST", 0);
+
+    // There should be no error on the insert hash
+    assert(error_string == QD_ERROR_NONE);
+
+    const char *taddr = "policy/org/apache/dev";
+
+    qd_field_iterator_t *address_iter = qd_address_iterator_string(taddr, ITER_VIEW_ADDRESS_HASH);
+    qd_address_iterator_override_prefix(address_iter, 'C');
+
+    qd_address_t *addr;
+
+    qd_hash_retrieve_prefix(hash, address_iter, (void*) &addr);
+
+    qd_field_iterator_free(iter);
+    qd_field_iterator_free(address_iter);
+
+    if(addr)
+        return "test_qd_hash_retrieve_prefix_no_match() failed";
+
+    return 0;
+}
+
+
+static char *test_qd_hash_retrieve_prefix_no_match_separator(void *context)
+{
+    qd_hash_t *hash = qd_hash(10, 32, 0);
+
+    // No 'y' in policy. There should be no match.
+    qd_field_iterator_t *iter = qd_address_iterator_string("policy/org/apach", ITER_VIEW_ADDRESS_HASH);
+    qd_address_iterator_override_prefix(iter, 'C');
+
+    // Insert that hash
+    qd_error_t error_string = qd_hash_insert(hash, iter, "TEST", 0);
+
+    // There should be no error on the insert hash
+    assert(error_string == QD_ERROR_NONE);
+
+    const char *taddr = "policy/org/apache/dev";
+
+    qd_field_iterator_t *address_iter = qd_address_iterator_string(taddr, ITER_VIEW_ADDRESS_HASH);
+    qd_address_iterator_override_prefix(address_iter, 'C');
+
+    qd_address_t *addr;
+
+    qd_hash_retrieve_prefix(hash, address_iter, (void*) &addr);
+
+    qd_field_iterator_free(iter);
+    qd_field_iterator_free(address_iter);
+
+    if(addr)
+        return "test_qd_hash_retrieve_prefix_no_match_separator() failed";
+
+    return 0;
+}
+
 
 int field_tests(void)
 {
@@ -320,6 +467,10 @@ int field_tests(void)
     TEST_CASE(test_view_node_hash, 0);
     TEST_CASE(test_field_advance_string, 0);
     TEST_CASE(test_field_advance_buffer, 0);
+    TEST_CASE(test_qd_hash_retrieve_prefix_separator, 0);
+    TEST_CASE(test_qd_hash_retrieve_prefix, 0);
+    TEST_CASE(test_qd_hash_retrieve_prefix_no_match, 0);
+    TEST_CASE(test_qd_hash_retrieve_prefix_no_match_separator, 0);
 
     return result;
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[2/2] qpid-dispatch git commit: DISPATCH-159 - Doc updates related to this fix

Posted by tr...@apache.org.
DISPATCH-159 - Doc updates related to this fix


Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/12d20196
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/12d20196
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/12d20196

Branch: refs/heads/master
Commit: 12d2019604c38f2ae0fd9ea1fd13d941482bf92e
Parents: 029ab00
Author: Ted Ross <tr...@redhat.com>
Authored: Fri Sep 18 15:54:12 2015 -0400
Committer: Ted Ross <tr...@redhat.com>
Committed: Fri Sep 18 15:54:12 2015 -0400

----------------------------------------------------------------------
 doc/book/link_routing.rst | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/12d20196/doc/book/link_routing.rst
----------------------------------------------------------------------
diff --git a/doc/book/link_routing.rst b/doc/book/link_routing.rst
index 90c8fd9..b7e3d75 100644
--- a/doc/book/link_routing.rst
+++ b/doc/book/link_routing.rst
@@ -108,20 +108,25 @@ Now, the router must be configured to route certain addresses to B2:
 ::
 
     linkRoutePattern {
-        prefix: b2.
+        prefix: b2
         connector: broker
     }
 
 
 The linkRoutePattern tells router Ra that any sender or receiver that
 is attached with a target or source (respectively) whos address begins
-with "b2.", should be routed to the broker B2 (via the on-demand
+with "b2", should be routed to the broker B2 (via the on-demand
 connector).
 
+Examples of addresses that "begin with 'b2'" include:
+ - b2
+ - b2/queues
+ - b2/queues/app1
+
 When the on-demand connector is configured, router Ra establishes a
 connection to the broker.  Once the connection is open, Ra tells the
 other routers (Rp and Rb) that it is a valid destination for
-link-routes to the "b2." prefix.  This means that sender or receiver
+link-routes to the "b2" prefix.  This means that sender or receiver
 links attached to Rb or Rp will be routed via the shortest path to Ra
 where they are then routed outbound to the broker B2.
 
@@ -130,15 +135,15 @@ On Rp and Rb, it is advisable to add the following configuration:
 ::
 
     linkRoutePattern {
-        prefix: b2.
+        prefix: b2
     }
 
 This configuration tells the routers that link-routing is intended to
-be available for targets and sources starting with "b2.".  This is
+be available for targets and sources starting with "b2".  This is
 important because it is possible that B2 might be unavailable or shut
 off.  If B2 is unreachable, Ra will not advertize itself as a
-destination for "b2." and the other routers might never know that
-"b2." was intended for link-routing.
+destination for "b2" and the other routers might never know that
+"b2" was intended for link-routing.
 
 The above configuration allows Rb and Rp to reject attaches that
 should be routed to B2 with an error message that indicates that there


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org