/** * Allocates space for and returns a linked * list of all the filters. * @arg mgr The manager to list from * @arg prefix The prefix to list or NULL * @arg head Output, sets to the address of the list header * @return 0 on success. */ int filtmgr_list_filters(bloom_filtmgr *mgr, char *prefix, bloom_filter_list_head **head) { // Allocate the head bloom_filter_list_head *h = *head = calloc(1, sizeof(bloom_filter_list_head)); // Iterate through a callback to append int prefix_len = 0; if (prefix) { prefix_len = strlen(prefix); art_iter_prefix(mgr->filter_map, (unsigned char*)prefix, prefix_len, filter_map_list_cb, h); } else art_iter(mgr->filter_map, filter_map_list_cb, h); // Joy... we have to potentially handle the delta updates if (mgr->primary_vsn == mgr->vsn) return 0; filter_list *current = mgr->delta; bloom_filter_wrapper *f; while (current) { // Check if this is a match (potential prefix) if (current->type == CREATE) { f = current->filter; if (!prefix_len || !strncmp(f->filter->filter_name, prefix, prefix_len)) { f = current->filter; filter_map_list_cb(h, (unsigned char*)f->filter->filter_name, 0, f); } } // Don't seek past what the primary map incorporates if (current->vsn == mgr->primary_vsn + 1) break; current = current->next; } return 0; }
/** * Allocates space for and returns a linked * list of all the sets. * @arg mgr The manager to list from * @arg prefix The prefix to match on or NULL * @arg head Output, sets to the address of the list header * @return 0 on success. */ int setmgr_list_sets(hlld_setmgr *mgr, char *prefix, hlld_set_list_head **head) { // Allocate the head hlld_set_list_head *h = *head = calloc(1, sizeof(hlld_set_list_head)); // Check if we should use the prefix int prefix_len = 0; if (prefix) { prefix_len = strlen(prefix); art_iter_prefix(mgr->set_map, prefix, prefix_len, set_map_list_cb, h); } else art_iter(mgr->set_map, set_map_list_cb, h); // Joy... we have to potentially handle the delta updates if (mgr->primary_vsn == mgr->vsn) return 0; set_list *current = mgr->delta; hlld_set_wrapper *s; while (current) { // Check if this is a match (potential prefix) if (current->type == CREATE) { s = current->set; if (!prefix_len || !strncmp(s->set->set_name, prefix, prefix_len)) { s = current->set; set_map_list_cb(h, s->set->set_name, 0, s); } } // Don't seek past what the primary set map incorporates if (current->vsn == mgr->primary_vsn + 1) break; current = current->next; } return 0; }
void test_art_long_prefix(void) { art_tree t; int res = art_tree_init(&t); uintptr_t v; const char *s; fail_unless(res == 0); s = "this:key:has:a:long:prefix:3"; v = 3; fail_unless(NULL == art_insert(&t, (unsigned char *)s, (int)strlen(s) + 1, (void *)v)); s = "this:key:has:a:long:common:prefix:2"; v = 2; fail_unless(NULL == art_insert(&t, (unsigned char *)s, (int)strlen(s) + 1, (void *)v)); s = "this:key:has:a:long:common:prefix:1"; v = 1; fail_unless(NULL == art_insert(&t, (unsigned char *)s, (int)strlen(s) + 1, (void *)v)); // Search for the keys s = "this:key:has:a:long:common:prefix:1"; fail_unless( 1 == (uintptr_t)art_search(&t, (unsigned char *)s, (int)strlen(s) + 1)); s = "this:key:has:a:long:common:prefix:2"; fail_unless( 2 == (uintptr_t)art_search(&t, (unsigned char *)s, (int)strlen(s) + 1)); s = "this:key:has:a:long:prefix:3"; fail_unless( 3 == (uintptr_t)art_search(&t, (unsigned char *)s, (int)strlen(s) + 1)); { const char *expected[] = { "this:key:has:a:long:common:prefix:1", "this:key:has:a:long:common:prefix:2", "this:key:has:a:long:prefix:3", }; prefix_data p = {0, 3, expected}; fail_unless(!art_iter_prefix(&t, (unsigned char *)"this:key:has", 12, test_prefix_cb, &p)); diag("Count: %d Max: %d", p.count, p.max_count); fail_unless(p.count == p.max_count); } res = art_tree_destroy(&t); fail_unless(res == 0); }
static ERL_NIF_TERM elibart_prefix_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { art_tree* t; ErlNifBinary key; callback_data cb_data; // extract arguments atr_tree, key if (argc != 4) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], elibart_RESOURCE, (void**) &t)) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[1], &key)) return enif_make_badarg(env); cb_data.env = env; if(!enif_is_pid(env, argv[3])) return mk_error(env, "not_a_pid"); if(!enif_get_local_pid(env, argv[3], &cb_data.pid)) return mk_error(env, "not_a_local_pid"); cb_data.caller_ref = argv[2]; // TODO this should be a worker thread since it's a long opearation (?) if (art_iter_prefix(t, key.data, key.size, prefix_cb, &cb_data)) return mk_error(env, "art_prefix_search"); ErlNifEnv *msg_env = enif_alloc_env(); if(msg_env == NULL) return mk_error(env, "env_alloc_error");; ERL_NIF_TERM caller_ref = enif_make_copy(msg_env, argv[2]); ERL_NIF_TERM res = enif_make_tuple2(msg_env, caller_ref, mk_atom(msg_env, "ok")); if (!enif_send(env, &cb_data.pid, msg_env, res)) { enif_free(msg_env); return mk_error(env, "art_prefix_search"); } enif_free(msg_env); return mk_atom(env, "ok"); }
void test_art_iter_prefix(void) { art_tree t; int res = art_tree_init(&t); const char *s = "api.foo.bar"; const char *expected2[] = {"abc.123.456", "api", "api.foe.fum", "api.foo", "api.foo.bar", "api.foo.baz"}; fail_unless(res == 0); fail_unless(NULL == art_insert(&t, (unsigned char *)s, (int)strlen(s) + 1, NULL)); s = "api.foo.baz"; fail_unless(NULL == art_insert(&t, (unsigned char *)s, (int)strlen(s) + 1, NULL)); s = "api.foe.fum"; fail_unless(NULL == art_insert(&t, (unsigned char *)s, (int)strlen(s) + 1, NULL)); s = "abc.123.456"; fail_unless(NULL == art_insert(&t, (unsigned char *)s, (int)strlen(s) + 1, NULL)); s = "api.foo"; fail_unless(NULL == art_insert(&t, (unsigned char *)s, (int)strlen(s) + 1, NULL)); s = "api"; fail_unless(NULL == art_insert(&t, (unsigned char *)s, (int)strlen(s) + 1, NULL)); { // Iterate over api const char *expected[] = {"api", "api.foe.fum", "api.foo", "api.foo.bar", "api.foo.baz"}; prefix_data p = {0, 5, expected}; fail_unless( !art_iter_prefix(&t, (unsigned char *)"api", 3, test_prefix_cb, &p)); diag("Count: %d Max: %d", p.count, p.max_count); fail_unless(p.count == p.max_count); } { // Iterate over 'a' prefix_data p2 = {0, 6, expected2}; fail_unless( !art_iter_prefix(&t, (unsigned char *)"a", 1, test_prefix_cb, &p2)); fail_unless(p2.count == p2.max_count); } { // Check a failed iteration prefix_data p3 = {0, 0, NULL}; fail_unless( !art_iter_prefix(&t, (unsigned char *)"b", 1, test_prefix_cb, &p3)); fail_unless(p3.count == 0); } { // Iterate over api. const char *expected4[] = {"api.foe.fum", "api.foo", "api.foo.bar", "api.foo.baz"}; prefix_data p4 = {0, 4, expected4}; fail_unless( !art_iter_prefix(&t, (unsigned char *)"api.", 4, test_prefix_cb, &p4)); diag("Count: %d Max: %d", p4.count, p4.max_count); fail_unless(p4.count == p4.max_count); } { // Iterate over api.foo.ba const char *expected5[] = {"api.foo.bar"}; prefix_data p5 = {0, 1, expected5}; fail_unless(!art_iter_prefix(&t, (unsigned char *)"api.foo.bar", 11, test_prefix_cb, &p5)); diag("Count: %d Max: %d", p5.count, p5.max_count); fail_unless(p5.count == p5.max_count); } // Check a failed iteration on api.end { prefix_data p6 = {0, 0, NULL}; fail_unless(!art_iter_prefix(&t, (unsigned char *)"api.end", 7, test_prefix_cb, &p6)); fail_unless(p6.count == 0); } // Iterate over empty prefix { prefix_data p7 = {0, 6, expected2}; fail_unless( !art_iter_prefix(&t, (unsigned char *)"", 0, test_prefix_cb, &p7)); fail_unless(p7.count == p7.max_count); } res = art_tree_destroy(&t); fail_unless(res == 0); }