uintptr_t radix_insert_compressed (radix_compressed_t * tree, guint8 *key, gsize keylen, gsize masklen, uintptr_t value) { guint keybits = keylen * NBBY; uintptr_t old; int ret; g_assert (tree != NULL); g_assert (keybits >= masklen); msg_debug_radix ("want insert value %p with mask %z, key: %*xs", (gpointer)value, keybits - masklen, (int)keylen, key); old = radix_find_compressed (tree, key, keylen); ret = btrie_add_prefix (tree->tree, key, keybits - masklen, (gconstpointer)value); if (ret != BTRIE_OKAY) { msg_err_radix ("cannot insert %p with mask %z, key: %*xs, duplicate value", (gpointer)value, keybits - masklen, (int)keylen, key); } else { tree->size ++; } return old; }
uintptr_t radix_find_compressed_addr (radix_compressed_t *tree, const rspamd_inet_addr_t *addr) { const guchar *key; guint klen = 0; if (addr == NULL) { return RADIX_NO_VALUE; } key = rspamd_inet_address_get_radix_key (addr, &klen); if (key && klen) { return radix_find_compressed (tree, key, klen); } return RADIX_NO_VALUE; }
/* Radix and hash table functions */ static gint lua_radix_get_key (lua_State * L) { radix_compressed_t *radix = lua_check_radix (L); guint32 key; if (radix) { key = htonl (luaL_checkint (L, 2)); if (radix_find_compressed (radix, (guint8 *)&key, sizeof (key)) != RADIX_NO_VALUE) { lua_pushboolean (L, 1); return 1; } } lua_pushboolean (L, 0); return 1; }
static void rspamd_radix_text_vec (void) { radix_compressed_t *tree = radix_create_compressed (); struct _tv *t = &test_vec[0]; struct in_addr ina; struct in6_addr in6a; gulong i, val; while (t->ip != NULL) { t->addr = g_malloc (sizeof (in6a)); t->naddr = g_malloc (sizeof (in6a)); if (inet_pton (AF_INET, t->ip, &ina) == 1) { memcpy (t->addr, &ina, sizeof (ina)); t->len = sizeof (ina); } else if (inet_pton (AF_INET6, t->ip, &in6a) == 1) { memcpy (t->addr, &in6a, sizeof (in6a)); t->len = sizeof (in6a); } else { g_assert (0); } if (t->nip) { if (inet_pton (AF_INET, t->nip, &ina) == 1) { memcpy (t->naddr, &ina, sizeof (ina)); } else if (inet_pton (AF_INET6, t->nip, &in6a) == 1) { memcpy (t->naddr, &in6a, sizeof (in6a)); } else { g_assert (0); } } t->mask = t->len * NBBY - strtoul (t->m, NULL, 10); t ++; } t = &test_vec[0]; i = 0; while (t->ip != NULL) { radix_insert_compressed (tree, t->addr, t->len, t->mask, ++i); t ++; } i = 0; t = &test_vec[0]; while (t->ip != NULL) { val = radix_find_compressed (tree, t->addr, t->len); g_assert (val == ++i); //g_assert (val != RADIX_NO_VALUE); if (t->nip != NULL) { val = radix_find_compressed (tree, t->naddr, t->len); g_assert (val != i); } t ++; } radix_destroy_compressed (tree); }
void rspamd_radix_test_func (void) { #if 0 radix_tree_t *tree = radix_tree_create (); #endif radix_compressed_t *comp_tree = radix_create_compressed (); struct { guint32 addr; guint32 mask; guint8 addr6[16]; guint32 mask6; } *addrs; gsize nelts, i; gint lc; gboolean all_good = TRUE; gdouble ts1, ts2; double diff; /* Test suite for the compressed trie */ rspamd_radix_text_vec (); nelts = max_elts; /* First of all we generate many elements and push them to the array */ addrs = g_malloc (nelts * sizeof (addrs[0])); for (i = 0; i < nelts; i ++) { addrs[i].addr = ottery_rand_uint32 (); addrs[i].mask = masks[ottery_rand_range(G_N_ELEMENTS (masks) - 1)]; ottery_rand_bytes (addrs[i].addr6, sizeof(addrs[i].addr6)); addrs[i].mask6 = ottery_rand_range(128); } #if 0 msg_info ("old radix performance (%z elts)", nelts); ts1 = rspamd_get_ticks (); for (i = 0; i < nelts; i ++) { guint32 mask = G_MAXUINT32 << (32 - addrs[i].mask); radix32tree_insert (tree, addrs[i].addr, mask, 1); } ts2 = rspamd_get_ticks (); diff = (ts2 - ts1) * 1000.0; msg_info ("Added %z elements in %.6f ms", nelts, diff); ts1 = rspamd_get_ticks (); for (lc = 0; lc < lookup_cycles; lc ++) { for (i = 0; i < nelts; i ++) { g_assert (radix32tree_find (tree, addrs[i].addr) != RADIX_NO_VALUE); } } ts2 = rspamd_get_ticks (); diff = (ts2 - ts1) * 1000.0; msg_info ("Checked %z elements in %.6f ms", nelts, diff); ts1 = rspamd_get_ticks (); for (i = 0; i < nelts; i ++) { radix32tree_delete (tree, addrs[i].addr, addrs[i].mask); } ts2 = rspamd_get_ticks (); diff = (ts2 - ts1) * 1000.; msg_info ("Deleted %z elements in %.6f ms", nelts, diff); radix_tree_free (tree); #endif msg_info ("new radix performance (%z elts)", nelts); ts1 = rspamd_get_ticks (); for (i = 0; i < nelts; i ++) { radix_insert_compressed (comp_tree, addrs[i].addr6, sizeof (addrs[i].addr6), 128 - addrs[i].mask6, i); } ts2 = rspamd_get_ticks (); diff = (ts2 - ts1) * 1000.0; msg_info ("Added %z elements in %.6f ms", nelts, diff); ts1 = rspamd_get_ticks (); for (lc = 0; lc < lookup_cycles; lc ++) { for (i = 0; i < nelts; i ++) { if (radix_find_compressed (comp_tree, addrs[i].addr6, sizeof (addrs[i].addr6)) == RADIX_NO_VALUE) { all_good = FALSE; } } } #if 1 if (!all_good) { for (i = 0; i < nelts; i ++) { /* Used to write bad random vector */ char ipbuf[INET6_ADDRSTRLEN + 1]; inet_ntop(AF_INET6, addrs[i].addr6, ipbuf, sizeof(ipbuf)); msg_info("{\"%s\", NULL, \"%ud\", 0, 0, 0, 0},", ipbuf, addrs[i].mask6); } } #endif g_assert (all_good); ts2 = rspamd_get_ticks (); diff = (ts2 - ts1) * 1000.0; msg_info ("Checked %z elements in %.6f ms", nelts, diff); radix_destroy_compressed (comp_tree); g_free (addrs); }