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); } }
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; }