/** * This method is used to force a vacuum up to the current * version. It is generally unsafe to use in bloomd, * but can be used in an embeded or test environment. */ void filtmgr_vacuum(bloom_filtmgr *mgr) { unsigned long long vsn = mgr->vsn; merge_old_versions(mgr, mgr->delta, vsn); swap_filter_maps(mgr, vsn); merge_old_versions(mgr, mgr->delta, vsn); delete_old_versions(mgr, vsn); }
/** * This method is used to force a vacuum up to the current * version. It is generally unsafe to use in hlld, * but can be used in an embeded or test environment. */ void setmgr_vacuum(hlld_setmgr *mgr) { unsigned long long vsn = mgr->vsn; merge_old_versions(mgr, mgr->delta, vsn); swap_set_maps(mgr, vsn); merge_old_versions(mgr, mgr->delta, vsn); delete_old_versions(mgr, vsn); }
/** * Merges changes into the alternate tree from the delta lists * Safety: Safe ONLY if no other thread is using alt_filter_map */ static void merge_old_versions(bloom_filtmgr *mgr, filter_list *delta, unsigned long long min_vsn) { // Handle older delta first (bottom up) if (delta->next) merge_old_versions(mgr, delta->next, min_vsn); // Check if we should skip this update if (delta->vsn > min_vsn) return; // Handle current update bloom_filter_wrapper *s = delta->filter; switch (delta->type) { case CREATE: art_insert(mgr->alt_filter_map, (unsigned char*)s->filter->filter_name, strlen(s->filter->filter_name)+1, s); break; case DELETE: art_delete(mgr->alt_filter_map, (unsigned char*)s->filter->filter_name, strlen(s->filter->filter_name)+1); break; case BARRIER: // Ignore the barrier... break; } }
/** * This thread is started after initialization to maintain * the state of the filter manager. It's current use is to * cleanup the garbage created by our MVCC model. We do this * by making use of periodic 'checkpoints'. Our worker threads * report the version they are currently using, and we are always * able to delete versions that are strictly less than the minimum. */ static void* filtmgr_thread_main(void *in) { // Extract our arguments bloom_filtmgr *mgr = in; unsigned long long min_vsn, mgr_vsn; while (mgr->should_run) { // Do nothing if there is no changes if (mgr->vsn == mgr->primary_vsn) { usleep(VACUUM_POLL_USEC); continue; } /* * Because we use a version barrier, we always * end up creating a new version when we try to * apply delta updates. We need to handle the special case * where we are 1 version behind and the only delta is * a barrier. Do this by just updating primary_vsn. */ mgr_vsn = mgr->vsn; if ((mgr_vsn - mgr->primary_vsn) == 1) { pthread_mutex_lock(&mgr->write_lock); // Ensure no version created in the mean time int should_continue = 0; if (mgr_vsn == mgr->vsn && mgr->delta->type == BARRIER) { mgr->primary_vsn = mgr_vsn; should_continue = 1; } // Release the lock and see if we should loop back pthread_mutex_unlock(&mgr->write_lock); if (should_continue) { syslog(LOG_INFO, "All updates applied. (vsn: %llu)", mgr_vsn); continue; } } // Determine the minimum version min_vsn = client_min_vsn(mgr); // Warn if there are a lot of outstanding deltas if (mgr->vsn - min_vsn > WARN_THRESHOLD) { syslog(LOG_WARNING, "Many delta versions detected! min: %llu (vsn: %llu)", min_vsn, mgr->vsn); } else { syslog(LOG_DEBUG, "Applying delta update up to: %llu (vsn: %llu)", min_vsn, mgr->vsn); } // Merge the old versions into the alternate three merge_old_versions(mgr, mgr->delta, min_vsn); /* * Mark any pending deletes so that create does not allow * a filter to be created before we manage to call delete_old_versions. * There is an unforunate race that can happen if a client * does a create/drop/create cycle, where the create/drop are * reflected in the filter_map, and thus the second create is allowed * BEFORE we have had a chance to actually handle the delete. */ mark_pending_deletes(mgr, min_vsn); // Swap the maps swap_filter_maps(mgr, min_vsn); // Wait on a barrier until nobody is using the old tree version_barrier(mgr); // Merge the changes into the other tree now that its safe merge_old_versions(mgr, mgr->delta, min_vsn); // Both trees have the changes incorporated, safe to delete delete_old_versions(mgr, min_vsn); // Clear the pending delete list, since delete_old_versions() will // block untill all deletes are completed. clear_pending_deletes(mgr); // Log that we finished syslog(LOG_INFO, "Finished delta updates up to: %llu (vsn: %llu)", min_vsn, mgr->vsn); } return NULL; }