]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
move "insert" to state tables keyed off of trie->type
authorAlan T. DeKok <aland@freeradius.org>
Thu, 14 Mar 2019 23:54:01 +0000 (19:54 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 14 Mar 2019 23:54:01 +0000 (19:54 -0400)
src/lib/util/trie.c

index f720f2fd45eae0d93437b97720cf3dfeea181cd2..399d105d9a742473c82369f962f1e9d9abfa8c2f 100644 (file)
@@ -913,338 +913,365 @@ static void *fr_trie_key_match(fr_trie_t *trie, uint8_t const *key, int start_bi
        return trie_match[trie->type](trie, key, start_bit, end_bit, exact);
 }
 
+static int fr_trie_key_insert(TALLOC_CTX *ctx, fr_trie_t *parent, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data);
 
-/** Insert a binary key into the trie
- *
- *  The key must have at least ((start_bit + keylen) >> 3) bytes
- *
- * @param ctx          the talloc ctx
- * @param parent       the parent trie
- * @param[in,out] trie_p the trie where things are inserted
- * @param key          the binary key
- * @param start_bit    the start bit
- * @param end_bit      the end bit
- * @param data         user data to insert
- * @return
- *     - <0 on error
- *     - 0 on success
- */
-static int fr_trie_key_insert(TALLOC_CTX *ctx, fr_trie_t *parent, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
+typedef int (*fr_trie_key_insert_t)(TALLOC_CTX *ctx, fr_trie_t *parent, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data);
+
+static int fr_trie_user_insert(TALLOC_CTX *ctx, UNUSED fr_trie_t *parent, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
 {
        fr_trie_t *trie = *trie_p;
+       fr_trie_user_t *user = (fr_trie_user_t *) trie;
 
        /*
-        *      We've reached the end of the trie, but may still have
-        *      key bits to insert.
+        *      This is in normal form already.  Don't change
+        *      it.
         */
-       if (!trie) {
-               *trie_p = fr_trie_key_alloc(ctx, parent, key, start_bit, end_bit, data);
-               if (!*trie_p) {
-                       MPRINT("Failed key_alloc at %d\n", __LINE__);
+       if (fr_trie_key_insert(ctx, (fr_trie_t *) user, &user->trie, key, start_bit, end_bit, data) < 0) {
+               MPRINT("failed key_insert at %d\n", __LINE__);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int fr_trie_node_insert(TALLOC_CTX *ctx, fr_trie_t *parent, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
+{
+       fr_trie_t *trie = *trie_p;
+       fr_trie_node_t *node = (fr_trie_node_t *) trie;
+       fr_trie_t *trie_to_free = NULL;
+       uint32_t chunk;
+
+       /*
+        *      The current node is longer than the input bits
+        *      for the key.  Split the node into a smaller
+        *      N-way node, and insert the key into the (now
+        *      fitting) node.
+        */
+       if ((start_bit + node->bits) > end_bit) {
+               fr_trie_node_t *split;
+
+               split = fr_trie_node_split(ctx, parent, node, (start_bit + node->bits) - end_bit);
+               if (!split) {
+                       MPRINT("Failed splitting node at %d\n", __LINE__);
                        return -1;
                }
 
-               return 0;
+               trie_to_free = (fr_trie_t *) node;
+               node = split;
        }
 
+       chunk = get_chunk(key, node->bits, start_bit, end_bit);
+
        /*
-        *      We've reached the end of the key.  Insert a user node
-        *      here.
+        *      The current node exactly fits the key bits.
         */
-       if (start_bit == end_bit) {
+       if ((start_bit + node->bits == end_bit)) {
                fr_trie_user_t *user;
 
-               if (trie->type == FR_TRIE_USER) {
-                       fr_strerror_printf("already has a user node at %d\n", __LINE__);
-                       return -1;
+               /*
+                *      No existing trie, create a brand new
+                *      user node from the key.
+                */
+               if (!node->trie[chunk]) {
+                       node->trie[chunk] = (fr_trie_t *) fr_trie_user_alloc(ctx, (fr_trie_t *) node, data);
+
+               add_new:
+                       node->used++;
+                       goto done_set;
                }
 
-               user = fr_trie_user_alloc(ctx, parent, data);
-               if (!user) return -1;
+               /*
+                *      Can't insert user data on top of user
+                *      data.
+                */
+               if (node->trie[chunk]->type == FR_TRIE_USER) {
+                       MPRINT("already has a user node at %d\n", __LINE__);
 
-               user->trie = trie;
-               trie->parent = (fr_trie_t *) user;
-               *trie_p = (fr_trie_t *) user;
-               return 0;
-       }
+               fail:
+                       if (trie_to_free) fr_trie_free(trie_to_free);
+                       return -1;
+               }
 
-       if (trie->type == FR_TRIE_USER) {
-               fr_trie_user_t *user = (fr_trie_user_t *) trie;
+               /*
+                *      Otherwise there is already a trie at
+                *      the end of the key, so there's another
+                *      key which is longer.  Just create a
+                *      user node and wedge it into place.
+                */
+               user = fr_trie_user_alloc(ctx, (fr_trie_t *) node, data);
+               if (!user) {
+                       MPRINT("Failed user_alloc at %d\n", __LINE__);
+                       goto fail;
+               }
 
                /*
-                *      This is in normal form already.  Don't change
-                *      it.
+                *      Add the existing trie *after* the new
+                *      user data.  We do this by just
+                *      rearranging the trie.
                 */
-               if (fr_trie_key_insert(ctx, (fr_trie_t *) user, &user->trie, key, start_bit, end_bit, data) < 0) {
-                       MPRINT("failed key_insert at %d\n", __LINE__);
-                       return -1;
+               user->trie = node->trie[chunk];
+               user->trie->parent = (fr_trie_t *) user;
+               node->trie[chunk] = (fr_trie_t *) user;
+               goto done_set;
+       }
+
+       /*
+        *      The current node is all within the key bits.
+        */
+       // assert ((start_bit + node->bits) < end_bit)
+
+       /*
+        *      No existing trie, create a brand new trie from
+        *      the key.
+        */
+       if (!node->trie[chunk]) {
+               node->trie[chunk] = fr_trie_key_alloc(ctx, (fr_trie_t *) node, key, start_bit + node->bits, end_bit, data);
+               if (!node->trie[chunk]) {
+                       MPRINT("Failed key_alloc at %d\n", __LINE__);
+                       goto fail;
                }
+               goto add_new;
+       }
 
-               return 0;
+       /*
+        *      Recurse in order to insert the key
+        *      into the current node.
+        */
+       if (fr_trie_key_insert(ctx, (fr_trie_t *) node, &node->trie[chunk], key, start_bit + node->bits, end_bit, data) < 0) {
+               MPRINT("Failed recursing at %d\n", __LINE__);
+               goto fail;
        }
 
-       if (trie->type == FR_TRIE_NODE) {
-               fr_trie_node_t *node = (fr_trie_node_t *) trie;
-               fr_trie_t *trie_to_free = NULL;
-               uint32_t chunk;
+               done_set:
+       if (trie_to_free) fr_trie_free(trie_to_free);
+       *trie_p = (fr_trie_t *) node;
+       return 0;
+}
+
+#ifdef WITH_PATH_COMPRESSION
+static int fr_trie_path_insert(TALLOC_CTX *ctx, fr_trie_t *parent, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
+{
+       fr_trie_t *trie = *trie_p;
+       fr_trie_path_t *path = (fr_trie_path_t *) trie;
+       uint32_t chunk;
+       int lcp, bits;
+       uint8_t const *key2;
+       int start_bit2;
+       fr_trie_node_t *node;
 
+       bits = path->bits;
+
+       if ((start_bit + bits) > end_bit) {
                /*
-                *      The current node is longer than the input bits
-                *      for the key.  Split the node into a smaller
-                *      N-way node, and insert the key into the (now
-                *      fitting) node.
+                *      Limit the number of bits we check to
+                *      the number of bits left in the key.
                 */
-               if ((start_bit + node->bits) > end_bit) {
-                       fr_trie_node_t *split;
+               bits = end_bit - start_bit;
+               MPRINT2("forcing bits %d\n", bits);
+
+       } else {        /* the key is equal in length to, or longer than the path */
+               chunk = get_chunk(key, path->bits, start_bit, end_bit);
 
-                       split = fr_trie_node_split(ctx, parent, node, (start_bit + node->bits) - end_bit);
-                       if (!split) {
-                               MPRINT("Failed splitting node at %d\n", __LINE__);
+               /*
+                *      The chunk matches exactly.  Recurse to
+                *      insert the key into the child trie.
+                */
+               if (chunk == path->chunk) {
+                       if (fr_trie_key_insert(ctx, (fr_trie_t *) path, &path->trie, key, start_bit + path->bits, end_bit, data) < 0) {
+                               MPRINT("failed key insert at %d\n", __LINE__);
                                return -1;
                        }
 
-                       trie_to_free = (fr_trie_t *) node;
-                       node = split;
+                       return 0;
                }
+       }
 
-               chunk = get_chunk(key, node->bits, start_bit, end_bit);
+       /*
+        *      Figure out what part of the key we need to
+        *      look at for LCP.
+        */
+       key2 = key;
+       start_bit2 = start_bit;
+       if (start_bit2 > 7) {
+               key2 += (start_bit2 >> 3);
+               start_bit2 -= 8 * (start_bit2 >> 3);
+       }
 
-               /*
-                *      The current node exactly fits the key bits.
-                */
-               if ((start_bit + node->bits == end_bit)) {
-                       fr_trie_user_t *user;
-
-                       /*
-                        *      No existing trie, create a brand new
-                        *      user node from the key.
-                        */
-                       if (!node->trie[chunk]) {
-                               node->trie[chunk] = (fr_trie_t *) fr_trie_user_alloc(ctx, (fr_trie_t *) node, data);
-
-                       add_new:
-                               node->used++;
-                       done_set:
-                               if (trie_to_free) fr_trie_free(trie_to_free);
-                               *trie_p = (fr_trie_t *) node;
-                               return 0;
-                       }
+       /*
+        *      Get the LCP.  If we have one, split the path
+        *      node at the LCP.  Replace the parent with the
+        *      first half of the path, and build an N-way
+        *      node for the second half.
+        */
+       lcp = fr_trie_key_lcp(&path->key[0], bits, key2, bits, start_bit2);
 
-                       /*
-                        *      Can't insert user data on top of user
-                        *      data.
-                        */
-                       if (node->trie[chunk]->type == FR_TRIE_USER) {
-                               MPRINT("already has a user node at %d\n", __LINE__);
+       /*
+        *      This should have been caught above.
+        */
+       if (lcp == path->bits) {
+               fr_strerror_printf("found lcp which should have been previously found");
+               return -1;
+       }
 
-                       fail:
-                               if (trie_to_free) fr_trie_free(trie_to_free);
-                               return -1;
-                       }
+       if (lcp > 0) {
+               fr_trie_path_t *split;
 
-                       /*
-                        *      Otherwise there is already a trie at
-                        *      the end of the key, so there's another
-                        *      key which is longer.  Just create a
-                        *      user node and wedge it into place.
-                        */
-                       user = fr_trie_user_alloc(ctx, (fr_trie_t *) node, data);
-                       if (!user) {
-                               MPRINT("Failed user_alloc at %d\n", __LINE__);
-                               goto fail;
-                       }
+               MPRINT2("splitting path length %d at lcp %d\n",
+                       path->bits, lcp);
 
-                       /*
-                        *      Add the existing trie *after* the new
-                        *      user data.  We do this by just
-                        *      rearranging the trie.
-                        */
-                       user->trie = node->trie[chunk];
-                       user->trie->parent = (fr_trie_t *) user;
-                       node->trie[chunk] = (fr_trie_t *) user;
-                       goto done_set;
+               split = fr_trie_path_split(ctx, parent, path, start_bit2, lcp);
+               if (!split) {
+                       MPRINT("failed path split at %d\n", __LINE__);
+                       return -1;
                }
 
                /*
-                *      The current node is all within the key bits.
+                *      Swap out the original path with our
+                *      new one.  And update the various
+                *      pointers to the new locations.
                 */
-               // assert ((start_bit + node->bits) < end_bit)
+               parent = (fr_trie_t *) split;
+               *trie_p = parent;
+               path = (fr_trie_path_t *) split->trie;
+               trie_p = &split->trie;
+
+               start_bit += lcp;
+               bits -= lcp;
 
                /*
-                *      No existing trie, create a brand new trie from
-                *      the key.
+                *      We've split "path" into two, and have
+                *      reached the end of the key.  Just
+                *      insert a user node.
                 */
-               if (!node->trie[chunk]) {
-                       node->trie[chunk] = fr_trie_key_alloc(ctx, (fr_trie_t *) node, key, start_bit + node->bits, end_bit, data);
-                       if (!node->trie[chunk]) {
-                               MPRINT("Failed key_alloc at %d\n", __LINE__);
-                               goto fail;
+               if (start_bit == end_bit) {
+                       if (fr_trie_key_insert(ctx, parent, trie_p, key, start_bit, end_bit, data) < 0) {
+                               MPRINT("failed key insert at %d\n", __LINE__);
+                               return -1;
                        }
-                       goto add_new;
-               }
 
-               /*
-                *      Recurse in order to insert the key
-                *      into the current node.
-                */
-               if (fr_trie_key_insert(ctx, (fr_trie_t *) node, &node->trie[chunk], key, start_bit + node->bits, end_bit, data) < 0) {
-                       MPRINT("Failed recursing at %d\n", __LINE__);
-                       goto fail;
+                       return 0;
                }
 
-               goto done_set;
+               /* else start_bit < end_bit */
        }
 
-#ifdef WITH_PATH_COMPRESSION
-       if (trie->type == FR_TRIE_PATH) {
-               fr_trie_path_t *path = (fr_trie_path_t *) trie;
-               uint32_t chunk;
-               int lcp, bits;
-               uint8_t const *key2;
-               int start_bit2;
-               fr_trie_node_t *node;
-
-               bits = path->bits;
-
-               if ((start_bit + bits) > end_bit) {
-                       /*
-                        *      Limit the number of bits we check to
-                        *      the number of bits left in the key.
-                        */
-                       bits = end_bit - start_bit;
-                       MPRINT2("forcing bits %d\n", bits);
-
-               } else {        /* the key is equal in length to, or longer than the path */
-                       chunk = get_chunk(key, path->bits, start_bit, end_bit);
-
-                       /*
-                        *      The chunk matches exactly.  Recurse to
-                        *      insert the key into the child trie.
-                        */
-                       if (chunk == path->chunk) {
-                               if (fr_trie_key_insert(ctx, (fr_trie_t *) path, &path->trie, key, start_bit + path->bits, end_bit, data) < 0) {
-                                       MPRINT("failed key insert at %d\n", __LINE__);
-                                       return -1;
-                               }
-
-                               return 0;
-                       }
-               }
+       /*
+        *      Else there's no common prefix.  Just create an
+        *      N-way node.
+        */
+       if (bits > DEFAULT_BITS) bits = DEFAULT_BITS;
 
-               /*
-                *      Figure out what part of the key we need to
-                *      look at for LCP.
-                */
-               key2 = key;
-               start_bit2 = start_bit;
-               if (start_bit2 > 7) {
-                       key2 += (start_bit2 >> 3);
-                       start_bit2 -= 8 * (start_bit2 >> 3);
-               }
+       MPRINT2("path key alloc after split bits %d, start=%d end %d \n", bits, start_bit, end_bit);
 
-               /*
-                *      Get the LCP.  If we have one, split the path
-                *      node at the LCP.  Replace the parent with the
-                *      first half of the path, and build an N-way
-                *      node for the second half.
-                */
-               lcp = fr_trie_key_lcp(&path->key[0], bits, key2, bits, start_bit2);
+       node = fr_trie_node_alloc(ctx, parent, bits);
+       if (!node) return -1; /* @todo - don't leave "path" split in two */
 
-               /*
-                *      This should have been caught above.
-                */
-               if (lcp == path->bits) {
-                       fr_strerror_printf("found lcp which should have been previously found");
+       chunk = get_chunk(key, node->bits, start_bit, end_bit);
+       node->trie[chunk] = fr_trie_key_alloc(ctx, (fr_trie_t *) node, key, start_bit + node->bits, end_bit, data);
+       if (!node->trie[chunk]) {
+               MPRINT("Failed key_alloc at %d\n", __LINE__);
+               return -1;
+       }
+       node->used++;
+
+       /*
+        *      We may have to split "path" *again*.
+        */
+       if (node->bits == path->bits) {
+               if (node->trie[path->chunk]) {
+                       MPRINT("False duplicate in insert at %d\n", __LINE__);
+                       fr_trie_free((fr_trie_t *) node);
                        return -1;
                }
 
-               if (lcp > 0) {
-                       fr_trie_path_t *split;
-
-                       MPRINT2("splitting path length %d at lcp %d\n",
-                              path->bits, lcp);
-
-                       split = fr_trie_path_split(ctx, parent, path, start_bit2, lcp);
-                       if (!split) {
-                               MPRINT("failed path split at %d\n", __LINE__);
-                               return -1;
-                       }
+               node->trie[path->chunk] = path->trie;
+               node->used++;
 
-                       /*
-                        *      Swap out the original path with our
-                        *      new one.  And update the various
-                        *      pointers to the new locations.
-                        */
-                       parent = (fr_trie_t *) split;
-                       *trie_p = parent;
-                       path = (fr_trie_path_t *) split->trie;
-                       trie_p = &split->trie;
-
-                       start_bit += lcp;
-                       bits -= lcp;
-
-                       /*
-                        *      We've split "path" into two, and have
-                        *      reached the end of the key.  Just
-                        *      insert a user node.
-                        */
-                       if (start_bit == end_bit) {
-                               if (fr_trie_key_insert(ctx, parent, trie_p, key, start_bit, end_bit, data) < 0) {
-                                       MPRINT("failed key insert at %d\n", __LINE__);
-                                       return -1;
-                               }
-
-                               return 0;
-                       }
+               path->trie->parent = (fr_trie_t *) node;
+               talloc_free(path);
+               *trie_p = (fr_trie_t *) node;
+               return 0;
+       }
 
-                       /* else start_bit < end_bit */
-               }
+       fr_strerror_printf("logic not implemented for path in key_insert");
+       return -1;
+}
+#endif
 
-               /*
-                *      Else there's no common prefix.  Just create an
-                *      N-way node.
-                */
-               if (bits > DEFAULT_BITS) bits = DEFAULT_BITS;
+static fr_trie_key_insert_t trie_insert[FR_TRIE_MAX] = {
+       [ FR_TRIE_USER ] = fr_trie_user_insert,
+       [ FR_TRIE_NODE ] = fr_trie_node_insert,
+#ifdef WITH_PATH_COMPRESSION
+       [ FR_TRIE_PATH ] = fr_trie_path_insert,
+#endif
+};
 
-               MPRINT2("path key alloc after split bits %d, start=%d end %d \n", bits, start_bit, end_bit);
 
-               node = fr_trie_node_alloc(ctx, parent, bits);
-               if (!node) return -1; /* @todo - don't leave "path" split in two */
+/** Insert a binary key into the trie
+ *
+ *  The key must have at least ((start_bit + keylen) >> 3) bytes
+ *
+ * @param ctx          the talloc ctx
+ * @param parent       the parent trie
+ * @param[in,out] trie_p the trie where things are inserted
+ * @param key          the binary key
+ * @param start_bit    the start bit
+ * @param end_bit      the end bit
+ * @param data         user data to insert
+ * @return
+ *     - <0 on error
+ *     - 0 on success
+ */
+static int fr_trie_key_insert(TALLOC_CTX *ctx, fr_trie_t *parent, fr_trie_t **trie_p, uint8_t const *key, int start_bit, int end_bit, void *data)
+{
+       fr_trie_t *trie = *trie_p;
 
-               chunk = get_chunk(key, node->bits, start_bit, end_bit);
-               node->trie[chunk] = fr_trie_key_alloc(ctx, (fr_trie_t *) node, key, start_bit + node->bits, end_bit, data);
-               if (!node->trie[chunk]) {
+       /*
+        *      We've reached the end of the trie, but may still have
+        *      key bits to insert.
+        */
+       if (!trie) {
+               *trie_p = fr_trie_key_alloc(ctx, parent, key, start_bit, end_bit, data);
+               if (!*trie_p) {
                        MPRINT("Failed key_alloc at %d\n", __LINE__);
                        return -1;
                }
-               node->used++;
 
-               /*
-                *      We may have to split "path" *again*.
-                */
-               if (node->bits == path->bits) {
-                       if (node->trie[path->chunk]) {
-                               MPRINT("False duplicate in insert at %d\n", __LINE__);
-                               fr_trie_free((fr_trie_t *) node);
-                               return -1;
-                       }
+               return 0;
+       }
 
-                       node->trie[path->chunk] = path->trie;
-                       node->used++;
+       /*
+        *      We've reached the end of the key.  Insert a user node
+        *      here.
+        */
+       if (start_bit == end_bit) {
+               fr_trie_user_t *user;
 
-                       path->trie->parent = (fr_trie_t *) node;
-                       talloc_free(path);
-                       *trie_p = (fr_trie_t *) node;
-                       return 0;
+               if (trie->type == FR_TRIE_USER) {
+                       fr_strerror_printf("already has a user node at %d\n", __LINE__);
+                       return -1;
                }
 
-               fr_strerror_printf("logic not implemented for path in key_insert");
-               return -1;
+               user = fr_trie_user_alloc(ctx, parent, data);
+               if (!user) return -1;
+
+               user->trie = trie;
+               trie->parent = (fr_trie_t *) user;
+               *trie_p = (fr_trie_t *) user;
+               return 0;
        }
-#endif
 
-       fr_strerror_printf("unknown trie type %d in key_insert", trie->type);
-       return -1;
+       /*
+        *      Catch problems.
+        */
+       if ((trie->type == FR_TRIE_INVALID) ||
+           (trie->type >= FR_TRIE_MAX) ||
+           !trie_insert[trie->type]) {
+               fr_strerror_printf("unknown trie type %d in insert", trie->type);
+               return NULL;
+       }
+
+       return trie_insert[trie->type](ctx, parent, trie_p, key, start_bit, end_bit, data);
 }
 
 /** Insert a key and user ctx into a trie