/* * bc_close() is not thread safe, should stop other threads before call it. * */ void bc_close(Bitcask *bc) { int i=0; pthread_mutex_lock(&bc->write_lock); bc_flush(bc, 0, 0); if (NULL != bc->curr_tree) { uint32_t curr; ht_get_hash(bc->curr_tree, "@", &curr); if (curr > 0) { char name[255], buf[255]; sprintf(name, HINT_FILE, bc->curr); sprintf(buf, "%s/%s", mgr_alloc(bc->mgr, name), name); build_hint(bc->curr_tree, buf); }else{ ht_destroy(bc->curr_tree); } bc->curr_tree = NULL; } bc->curr = 0; ht_destroy(bc->tree); mgr_destroy(bc->mgr); free(bc->write_buffer); free(bc); }
void hs_flush(HStore *store, int limit, int period) { if (!store) return; if (store->before > 0) return; int i; for (i=0; i<store->count; i++){ bc_flush(store->bitcasks[i], limit, period); } }
/* * bc_close() is not thread safe, should stop other threads before call it. * */ void bc_close(Bitcask *bc) { char datapath[255], hintpath[255]; if (bc->optimize_flag > 0) { bc->optimize_flag = 2; while (bc->optimize_flag > 0) { sleep(1); } } pthread_mutex_lock(&bc->write_lock); bc_flush(bc, 0, 0); if (NULL != bc->curr_tree) { if (bc->curr_bytes > 0) { build_hint(bc->curr_tree, new_path(hintpath, bc->mgr, HINT_FILE, bc->curr)); } else { ht_destroy(bc->curr_tree); } bc->curr_tree = NULL; } if (bc->curr_bytes == 0) bc->curr --; if (bc->curr - bc->last_snapshot >= SAVE_HTREE_LIMIT) { if (ht_save(bc->tree, new_path(datapath, bc->mgr, HTREE_FILE, bc->curr)) == 0) { mgr_unlink(gen_path(datapath, mgr_base(bc->mgr), HTREE_FILE, bc->last_snapshot)); } else { fprintf(stderr, "save HTree to %s failed\n", datapath); } } ht_destroy(bc->tree); mgr_destroy(bc->mgr); free(bc->write_buffer); free(bc); }
bool bc_set(Bitcask *bc, const char* key, char* value, int vlen, int flag, int version) { if (version < 0 && vlen > 0 || vlen > MAX_RECORD_SIZE) { fprintf(stderr, "invalid set cmd \n"); return false; } bool suc = false; pthread_mutex_lock(&bc->write_lock); int oldv = 0, ver = version; Item *it = ht_get(bc->tree, key); if (it != NULL) { oldv = it->ver; } if (version == 0 && oldv > 0) // replace { ver = oldv + 1; } else if (version == 0 && oldv <= 0) // add { ver = -oldv + 1; } else if (version < 0 && oldv <= 0) // delete, not exist { goto SET_FAIL; } else if (version == -1) // delete { ver = - abs(oldv) - 1; } else if (abs(version) <= abs(oldv)) // sync { goto SET_FAIL; } else // sync { ver = version; } uint16_t hash = gen_hash(value, vlen); if (ver < 0) hash = 0; if (NULL != it && hash == it->hash) { DataRecord *r = bc_get(bc, key); if (r != NULL && r->flag == flag && vlen == r->vsz && memcmp(value, r->value, vlen) == 0) { if (version != 0) { // update version if (it->pos & 0xff == bc->curr) { ht_add(bc->curr_tree, key, it->pos, it->hash, ver); } ht_add(bc->tree, key, it->pos, it->hash, ver); } suc = true; free_record(r); goto SET_FAIL; } if (r != NULL) free_record(r); } int klen = strlen(key); DataRecord *r = (DataRecord*)malloc(sizeof(DataRecord) + klen); r->ksz = klen; memcpy(r->key, key, klen); r->vsz = vlen; r->value = value; r->free_value = false; r->flag = flag; r->version = ver; r->tstamp = time(NULL); int rlen; char *rbuf = encode_record(r, &rlen); if (rbuf == NULL || (rlen & 0xff) != 0) { fprintf(stderr, "encode_record() failed with %d\n", rlen); if (rbuf != NULL) free(rbuf); goto SET_FAIL; } pthread_mutex_lock(&bc->buffer_lock); // record maybe larger than buffer if (bc->wbuf_curr_pos + rlen > bc->wbuf_size) { pthread_mutex_unlock(&bc->buffer_lock); bc_flush(bc, 0, 0); pthread_mutex_lock(&bc->buffer_lock); while (rlen > bc->wbuf_size) { bc->wbuf_size *= 2; free(bc->write_buffer); bc->write_buffer = (char*)malloc(bc->wbuf_size); } if (bc->wbuf_start_pos + bc->wbuf_size > MAX_BUCKET_SIZE) { bc_rotate(bc); } } memcpy(bc->write_buffer + bc->wbuf_curr_pos, rbuf, rlen); int pos = (bc->wbuf_start_pos + bc->wbuf_curr_pos) | bc->curr; bc->wbuf_curr_pos += rlen; pthread_mutex_unlock(&bc->buffer_lock); ht_add(bc->curr_tree, key, pos, hash, ver); ht_add(bc->tree, key, pos, hash, ver); suc = true; free(rbuf); free_record(r); SET_FAIL: pthread_mutex_unlock(&bc->write_lock); if (it != NULL) free(it); return suc; }