Beispiel #1
0
/**
 * 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);
}
Beispiel #2
0
/**
 * 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);
}
Beispiel #3
0
/**
 * 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;
    }
}
Beispiel #4
0
/**
 * 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;
}