couchstore_error_t TreeWriterWrite(TreeWriter* writer, tree_file* treefile, node_pointer** out_root) { couchstore_error_t errcode = COUCHSTORE_SUCCESS; arena* transient_arena = new_arena(0); arena* persistent_arena = new_arena(0); error_unless(transient_arena && persistent_arena, COUCHSTORE_ERROR_ALLOC_FAIL); rewind(writer->file); // Create the structure to write the tree to the db: compare_info idcmp; sized_buf tmp; idcmp.compare = writer->key_compare; idcmp.arg = &tmp; couchfile_modify_result* target_mr = new_btree_modres(persistent_arena, transient_arena, treefile, &idcmp, writer->reduce, writer->rereduce, DB_CHUNK_THRESHOLD, DB_CHUNK_THRESHOLD); if(target_mr == NULL) { error_pass(COUCHSTORE_ERROR_ALLOC_FAIL); } // Read all the key/value pairs from the file and add them to the tree: uint16_t klen; uint32_t vlen; sized_buf k, v; while(1) { if(fread(&klen, sizeof(klen), 1, writer->file) != 1) { break; } if(fread(&vlen, sizeof(vlen), 1, writer->file) != 1) { break; } k.size = ntohs(klen); k.buf = arena_alloc(transient_arena, k.size); v.size = ntohl(vlen); v.buf = arena_alloc(transient_arena, v.size); if(fread(k.buf, k.size, 1, writer->file) != 1) { error_pass(COUCHSTORE_ERROR_READ); } if(fread(v.buf, v.size, 1, writer->file) != 1) { error_pass(COUCHSTORE_ERROR_READ); } //printf("K: '%.*s'\n", k.size, k.buf); mr_push_item(&k, &v, target_mr); if(target_mr->count == 0) { /* No items queued, we must have just flushed. We can safely rewind the transient arena. */ arena_free_all(transient_arena); } } // Check for file error: int readerr = ferror(writer->file); if(readerr != 0 && readerr != EOF) { error_pass(COUCHSTORE_ERROR_READ); } // Finish up the tree: *out_root = complete_new_btree(target_mr, &errcode); cleanup: delete_arena(transient_arena); delete_arena(persistent_arena); return errcode; }
static couchstore_error_t build_btree(const char *source_file, tree_file *dest_file, compare_info *cmp, reduce_fn reduce_fun, reduce_fn rereduce_fun, void *reduce_ctx, node_pointer **out_root) { couchstore_error_t ret = COUCHSTORE_SUCCESS; arena *transient_arena = new_arena(0); arena *persistent_arena = new_arena(0); couchfile_modify_result *mr; FILE *f = NULL; if (transient_arena == NULL || persistent_arena == NULL) { ret = COUCHSTORE_ERROR_ALLOC_FAIL; goto out; } mr = new_btree_modres(persistent_arena, transient_arena, dest_file, cmp, reduce_fun, rereduce_fun, reduce_ctx, VIEW_KV_CHUNK_THRESHOLD + (VIEW_KV_CHUNK_THRESHOLD / 3), VIEW_KP_CHUNK_THRESHOLD + (VIEW_KP_CHUNK_THRESHOLD / 3)); if (mr == NULL) { ret = COUCHSTORE_ERROR_ALLOC_FAIL; goto out; } f = fopen(source_file, "rb"); if (f == NULL) { ret = COUCHSTORE_ERROR_OPEN_FILE; goto out; } while (1) { sized_buf k, v; int read_ret; read_ret = read_record(f, transient_arena, &k, &v); if (read_ret == 0) { break; } else if (read_ret < 0) { ret = (couchstore_error_t) read_ret; goto out; } ret = mr_push_item(&k, &v, mr); if (ret != COUCHSTORE_SUCCESS) { goto out; } if (mr->count == 0) { arena_free_all(transient_arena); } } *out_root = complete_new_btree(mr, &ret); if (ret != COUCHSTORE_SUCCESS) { goto out; } /* Don't care about success/failure. Erlang side will eventually delete it. */ remove(source_file); out: if (f != NULL) { fclose(f); } if (transient_arena != NULL) { delete_arena(transient_arena); } if (persistent_arena != NULL) { delete_arena(persistent_arena); } return ret; }