void bc_scan(Bitcask* bc) { const char* path = mgr_base(bc->mgr); char dname[20], hname[20], datapath[255], hintpath[255]; int i=0; struct stat st; for (i=0; i<MAX_BUCKET_COUNT; i++) { sprintf(dname, DATA_FILE, i); sprintf(datapath, "%s/%s", path, dname); if (stat(datapath, &st) != 0) { break; } bc->bytes += st.st_size; sprintf(hname, HINT_FILE, i); sprintf(hintpath, "%s/%s", path, hname); if (bc->before == 0){ if (0 == stat(hintpath, &st)){ scanHintFile(bc->tree, i, hintpath, NULL); }else{ sprintf(hintpath, "%s/%s", mgr_alloc(bc->mgr, hname), hname); scanDataFile(bc->tree, i, datapath, hintpath); } }else{ if (0 == stat(hintpath, &st) && (st.st_mtime < bc->before || 0 == stat(datapath, &st) && st.st_mtime < bc->before)){ scanHintFile(bc->tree, i, hintpath, NULL); }else{ scanDataFileBefore(bc->tree, i, datapath, bc->before); } } } bc->curr = i; }
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; }
void bc_scan(Bitcask* bc) { char datapath[255], hintpath[255]; int i=0; struct stat st, hst; skip_empty_file(bc); const char* base = mgr_base(bc->mgr); // load snapshot of htree for (i=MAX_BUCKET_COUNT-1; i>=0; i--) { if (stat(gen_path(datapath, base, HTREE_FILE, i), &st) == 0 && stat(gen_path(hintpath, base, HINT_FILE, i), &hst) == 0 && st.st_mtime >= hst.st_mtime && (bc->before == 0 || st.st_mtime < bc->before)) { bc->tree = ht_open(bc->depth, bc->pos, datapath); if (bc->tree != NULL) { bc->last_snapshot = i; break; } else { fprintf(stderr, "open HTree from %s failed\n", datapath); mgr_unlink(datapath); } } } if (bc->tree == NULL) { bc->tree = ht_new(bc->depth, bc->pos); } for (i=0; i<MAX_BUCKET_COUNT; i++) { if (stat(gen_path(datapath, base, DATA_FILE, i), &st) != 0) { break; } bc->bytes += st.st_size; if (i <= bc->last_snapshot) continue; gen_path(hintpath, base, HINT_FILE, i); if (bc->before == 0) { if (0 == stat(hintpath, &st)) { scanHintFile(bc->tree, i, hintpath, NULL); } else { scanDataFile(bc->tree, i, datapath, new_path(hintpath, bc->mgr, HINT_FILE, i)); } } else { if (0 == stat(hintpath, &st) && (st.st_mtime < bc->before || 0 == stat(datapath, &st) && st.st_mtime < bc->before)) { scanHintFile(bc->tree, i, hintpath, NULL); } else { scanDataFileBefore(bc->tree, i, datapath, bc->before); } } } if (i - bc->last_snapshot > SAVE_HTREE_LIMIT) { if (ht_save(bc->tree, new_path(datapath, bc->mgr, HTREE_FILE, i-1)) == 0) { mgr_unlink(gen_path(NULL, base, HTREE_FILE, bc->last_snapshot)); bc->last_snapshot = i-1; } else { fprintf(stderr, "save HTree to %s failed\n", datapath); } } bc->curr = i; }