Example #1
0
void bc_optimize(Bitcask *bc, int limit)
{
    int i;
    for (i=0; i < bc->curr; i++) {
        char data[20], hint[20], datapath[255], hintpath[255];
        sprintf(data, DATA_FILE, i);
        sprintf(hint, HINT_FILE, i);
        sprintf(datapath, "%s/%s", mgr_alloc(bc->mgr, data), data);
        sprintf(hintpath, "%s/%s", mgr_alloc(bc->mgr, hint), hint);
        
        uint32_t recoverd = 0;
        HTree *cur_tree = optimizeDataFile(bc->tree, i, datapath, hintpath, limit, &recoverd);
        if (NULL == cur_tree) continue;
        pthread_mutex_lock(&bc->buffer_lock);
        bc->bytes -= recoverd;
        pthread_mutex_unlock(&bc->buffer_lock);

        pthread_mutex_lock(&bc->write_lock);
        ht_visit(cur_tree, update_items, bc->tree);
        pthread_mutex_unlock(&bc->write_lock);

        build_hint(cur_tree, hintpath);
    }
}
Example #2
0
void bc_optimize(Bitcask *bc, int limit)
{
    int i, total, last = -1;
    bc->optimize_flag = 1;
    const char *base = mgr_base(bc->mgr);
    // remove htree
    for (i=0; i < bc->curr; i++)
    {
        mgr_unlink(gen_path(NULL, base, HTREE_FILE, i));
    }
    bc->last_snapshot = -1;

    time_t limit_time = 0;
    if (limit > 3600 * 24 * 365 * 10)   // more than 10 years
    {
        limit_time = limit; // absolute time
    }
    else
    {
        limit_time = time(NULL) - limit; // relative time
    }

    struct stat st;
    bool skipped = false;
    for (i=0; i < bc->curr && bc->optimize_flag == 1; i++)
    {
        char datapath[255], hintpath[255];
        gen_path(datapath, base, DATA_FILE, i);
        gen_path(hintpath, base, HINT_FILE, i);
        if (stat(datapath, &st) != 0)
        {
            continue; // skip empty file
        }
        // skip recent modified file
        if (st.st_mtime > limit_time)
        {
            skipped = true;

            last ++;
            if (last != i)   // rotate data file
            {
                char npath[255];
                gen_path(npath, base, DATA_FILE, last);
                if (symlink(datapath, npath) != 0)
                {
                    fprintf(stderr, "symlink failed: %s -> %s\n", datapath, npath);
                    last = i;
                    continue;
                }

                // update HTree to use new index
                if (stat(hintpath, &st) != 0)
                {
                    fprintf(stderr, "no hint file: %s, skip it\n", hintpath);
                    last = i;
                    continue;
                }
                HTree *tree = ht_new(bc->depth, bc->pos);
                scanHintFile(tree, i, hintpath, NULL);
                struct update_args args;
                args.tree = bc->tree;
                args.index = last;
                ht_visit(tree, update_item_pos, &args);
                ht_destroy(tree);

                unlink(npath);
                mgr_rename(datapath, npath);
                mgr_rename(hintpath, gen_path(npath, base, HINT_FILE, last));
            }
            continue;
        }

        int deleted = count_deleted_record(bc->tree, i, hintpath, &total);
        uint64_t curr_size = data_file_size(bc, i) * (total - deleted/2) / (total+1); // guess
        uint64_t last_size = last >= 0 ? data_file_size(bc, last) : -1;

        // last data file size
        uint32_t recoverd = 0;
        if (last == -1 || last_size + curr_size > MAX_BUCKET_SIZE)
        {
            last ++;
        }
        while (last < i)
        {
            char ldpath[255], lhpath[255];
            new_path(ldpath, bc->mgr, DATA_FILE, last);
            new_path(lhpath, bc->mgr, HINT_FILE, last);
            recoverd = optimizeDataFile(bc->tree, i, datapath, hintpath,
                                        skipped, MAX_BUCKET_SIZE, last, ldpath, lhpath);
            if (recoverd == 0)
            {
                last ++;
            }
            else
            {
                break;
            }
        }
        if (recoverd == 0)
        {
            // last == i
            recoverd = optimizeDataFile(bc->tree, i, datapath, hintpath,
                                        skipped, MAX_BUCKET_SIZE, last, NULL, NULL);
        }
        if (recoverd < 0) break; // failed

        pthread_mutex_lock(&bc->buffer_lock);
        bc->bytes -= recoverd;
        pthread_mutex_unlock(&bc->buffer_lock);
    }

    // update pos of items in curr_tree
    pthread_mutex_lock(&bc->write_lock);
    pthread_mutex_lock(&bc->flush_lock);
    if (i == bc->curr && ++last < bc->curr)
    {
        char opath[255], npath[255];
        gen_path(opath, base, DATA_FILE, bc->curr);

        if (file_exists(opath))
        {
            gen_path(npath, base, DATA_FILE, last);
            if (symlink(opath, npath) != 0)
                fprintf(stderr, "symlink failed: %s -> %s\n", opath, npath);

            struct update_args args;
            args.tree = bc->tree;
            args.index = last;
            ht_visit(bc->curr_tree, update_item_pos, &args);

            unlink(npath);
            mgr_rename(opath, npath);
        }

        bc->curr = last;
    }
    pthread_mutex_unlock(&bc->flush_lock);
    pthread_mutex_unlock(&bc->write_lock);

    bc->optimize_flag = 0;
}