/** * Should be invoked by clients when they no longer * need to make use of the filter manager. This * allows the vacuum thread to cleanup garbage state. * @arg mgr The manager */ void filtmgr_client_leave(bloom_filtmgr *mgr) { // Get a reference to ourself pthread_t id = pthread_self(); // Critical section LOCK_BLOOM_SPIN(&mgr->clients_lock); // Look for our ID, and update the version // This is O(n), but N is small and its done infrequently filtmgr_client **last_next = &mgr->clients; filtmgr_client *cl = mgr->clients; while (cl) { if (cl->id == id) { // Set the last prev pointer to skip the current entry *last_next = cl->next; // Cleanup the memory associated free(cl); break; } last_next = &cl->next; cl = cl->next; } UNLOCK_BLOOM_SPIN(&mgr->clients_lock); }
/** * Should be invoked periodically by client threads to allow * the vacuum thread to cleanup garbage state. It should also * be called before making other calls into the filter manager * so that it is aware of a client making use of the current * state. * @arg mgr The manager */ void filtmgr_client_checkpoint(bloom_filtmgr *mgr) { // Get a reference to ourself pthread_t id = pthread_self(); // Look for our ID, and update the version // This is O(n), but N is small and its done infrequently filtmgr_client *cl = mgr->clients; while (cl) { if (cl->id == id) { cl->vsn = mgr->vsn; return; } cl = cl->next; } // If we make it here, we are not a client yet // so we need to safely add ourself cl = malloc(sizeof(filtmgr_client)); cl->id = id; cl->vsn = mgr->vsn; // Critical section for the flip LOCK_BLOOM_SPIN(&mgr->clients_lock); cl->next = mgr->clients; mgr->clients = cl; UNLOCK_BLOOM_SPIN(&mgr->clients_lock); }
/** * Adds a key to the given filter * @arg filter The filter to add to * @arg key The key to add * @return 0 if not added, 1 if added. */ int bloomf_add(bloom_filter *filter, char *key) { if (!filter->sbf) { if (thread_safe_fault(filter) != 0) return -1; } // Add the SBF int res = sbf_add((bloom_sbf*)filter->sbf, key); // Safely update the counters LOCK_BLOOM_SPIN(&filter->counter_lock); if (res == 1) filter->counters.set_hits += 1; else if (res == 0) filter->counters.set_misses += 1; UNLOCK_BLOOM_SPIN(&filter->counter_lock); return res; }
/** * Clears the pending deletes */ static void clear_pending_deletes(bloom_filtmgr *mgr) { // Get a reference to the head bloom_filter_list *pending = mgr->pending_deletes; if (!pending) return; // filter the pending list to NULL safely LOCK_BLOOM_SPIN(&mgr->pending_lock); mgr->pending_deletes = NULL; UNLOCK_BLOOM_SPIN(&mgr->pending_lock); // Free the nodes bloom_filter_list *next; while (pending) { free(pending->filter_name); next = pending->next; free(pending); pending = next; } }
/** * Updates the pending deletes list with a list of pending deletes */ static void mark_pending_deletes(bloom_filtmgr *mgr, unsigned long long min_vsn) { bloom_filter_list *tmp, *pending = NULL; // Add each delete filter_list *delta = mgr->delta; while (delta) { if (delta->vsn <= min_vsn && delta->type == DELETE) { tmp = malloc(sizeof(bloom_filter_list)); tmp->filter_name = strdup(delta->filter->filter->filter_name); tmp->next = pending; pending = tmp; } delta = delta->next; } LOCK_BLOOM_SPIN(&mgr->pending_lock); mgr->pending_deletes = pending; UNLOCK_BLOOM_SPIN(&mgr->pending_lock); }
/** * Creates a new filter of the given name and parameters. * @arg filter_name The name of the filter * @arg custom_config Optional, can be null. Configs that override the defaults. * @return 0 on success, -1 if the filter already exists. * -2 for internal error. -3 if there is a pending delete. */ int filtmgr_create_filter(bloom_filtmgr *mgr, char *filter_name, bloom_config *custom_config) { int res = 0; pthread_mutex_lock(&mgr->write_lock); // Bail if the filter already exists. bloom_filter_wrapper *filt = find_filter(mgr, filter_name); if (filt) { res = (filt->is_active) ? -1 : -3; goto LEAVE; } // Scan the pending delete queue LOCK_BLOOM_SPIN(&mgr->pending_lock); if (mgr->pending_deletes) { bloom_filter_list *node = mgr->pending_deletes; while (node) { if (!strcmp(node->filter_name, filter_name)) { res = -3; // Pending delete UNLOCK_BLOOM_SPIN(&mgr->pending_lock); goto LEAVE; } node = node->next; } } UNLOCK_BLOOM_SPIN(&mgr->pending_lock); // Use a custom config if provided, else the default bloom_config *config = (custom_config) ? custom_config : mgr->config; // Add the filter to the new version if (add_filter(mgr, filter_name, config, 1, 1)) { res = -2; // Internal error } LEAVE: pthread_mutex_unlock(&mgr->write_lock); return res; }