size_t encode_root(void *buf, node_pointer *node) { if (!node) { return 0; } if (buf) { raw_btree_root *root = buf; root->pointer = encode_raw48(node->pointer); root->subtreesize = encode_raw48(node->subtreesize); memcpy(root + 1, node->reduce_value.buf, node->reduce_value.size); } return sizeof(raw_btree_root) + node->reduce_value.size; }
static size_t assemble_id_index_value(DocInfo *docinfo, char *dst) { char* const start = dst; raw_id_index_value *raw = (raw_id_index_value*)dst; raw->db_seq = encode_raw48(docinfo->db_seq); raw->size = encode_raw32((uint32_t)docinfo->size); raw->bp = encode_raw48(docinfo->bp | (docinfo->deleted ? 1LL<<47 : 0)); raw->content_meta = encode_raw08(docinfo->content_meta); raw->rev_seq = encode_raw48(docinfo->rev_seq); dst += sizeof(*raw); memcpy(dst, docinfo->rev_meta.buf, docinfo->rev_meta.size); dst += docinfo->rev_meta.size; return dst - start; }
static nodelist *encode_pointer(arena* a, node_pointer *ptr) { nodelist *pel = make_nodelist(a, sizeof(raw_node_pointer) + ptr->reduce_value.size); if (!pel) { return NULL; } raw_node_pointer *raw = (raw_node_pointer*)pel->data.buf; raw->pointer = encode_raw48(ptr->pointer); raw->subtreesize = encode_raw48(ptr->subtreesize); raw->reduce_value_size = encode_raw16((uint16_t)ptr->reduce_value.size); memcpy(raw + 1, ptr->reduce_value.buf, ptr->reduce_value.size); pel->pointer = ptr; pel->key = ptr->key; return pel; }
static void idfetch_update_cb(couchfile_modify_request *rq, sized_buf *k, sized_buf *v, void *arg) { (void)k; (void)rq; //v contains a seq we need to remove ( {Seq,_,_,_,_} ) uint64_t oldseq; sized_buf *delbuf = NULL; index_update_ctx *ctx = (index_update_ctx *) arg; if (v == NULL) { //Doc not found return; } const raw_id_index_value *raw = (raw_id_index_value*) v->buf; oldseq = decode_raw48(raw->db_seq); delbuf = (sized_buf *) fatbuf_get(ctx->deltermbuf, sizeof(sized_buf)); delbuf->buf = (char *) fatbuf_get(ctx->deltermbuf, 6); delbuf->size = 6; memset(delbuf->buf, 0, 6); *(raw_48*)delbuf->buf = encode_raw48(oldseq); ctx->seqacts[ctx->actpos].type = ACTION_REMOVE; ctx->seqacts[ctx->actpos].value.data = NULL; ctx->seqacts[ctx->actpos].key = delbuf; ctx->actpos++; }
LIBCOUCHSTORE_API couchstore_error_t couchstore_docinfos_by_sequence(Db *db, const uint64_t sequence[], unsigned numDocs, couchstore_docinfos_options options, couchstore_changes_callback_fn callback, void *ctx) { // Create the array of keys: sized_buf *keylist = malloc(numDocs * sizeof(sized_buf)); raw_by_seq_key *keyvalues = malloc(numDocs * sizeof(raw_by_seq_key)); couchstore_error_t errcode; error_unless(keylist && keyvalues, COUCHSTORE_ERROR_ALLOC_FAIL); unsigned i; for (i = 0; i< numDocs; ++i) { keyvalues[i].sequence = encode_raw48(sequence[i]); keylist[i].buf = (void*) &keyvalues[i]; keylist[i].size = sizeof(keyvalues[i]); } error_pass(iterate_docinfos(db, keylist, numDocs, db->header.by_seq_root, seq_ptr_cmp, seq_cmp, callback, (options & RANGES) != 0, ctx)); cleanup: free(keylist); free(keyvalues); return errcode; }
static void enc_uint48(uint64_t u, char **buf) { raw_48 r; encode_raw48(u, &r); memcpy(*buf, &r, 6); *buf += 6; }
static void test_raw_48(uint64_t value, const uint8_t expected[8]) { union { raw_48 raw; uint8_t bytes[8]; } data; memset(&data, 0, sizeof(data)); data.raw = encode_raw48(value); assert(memcmp(data.bytes, expected, 8) == 0); assert(decode_raw48(data.raw) == value); }
static couchstore_error_t add_doc_to_update_list(Db *db, const Doc *doc, const DocInfo *info, fatbuf *fb, sized_buf *seqterm, sized_buf *idterm, sized_buf *seqval, sized_buf *idval, uint64_t seq, couchstore_save_options options) { couchstore_error_t errcode = COUCHSTORE_SUCCESS; DocInfo updated = *info; updated.db_seq = seq; seqterm->buf = (char *) fatbuf_get(fb, 6); seqterm->size = 6; error_unless(seqterm->buf, COUCHSTORE_ERROR_ALLOC_FAIL); *(raw_48*)seqterm->buf = encode_raw48(seq); if (doc) { size_t disk_size; // Don't compress a doc unless the meta flag is set if (!(info->content_meta & COUCH_DOC_IS_COMPRESSED)) { options &= ~COMPRESS_DOC_BODIES; } errcode = write_doc(db, doc, &updated.bp, &disk_size, options); if (errcode != COUCHSTORE_SUCCESS) { return errcode; } updated.size = disk_size; } else { updated.deleted = 1; updated.bp = 0; updated.size = 0; } *idterm = updated.id; seqval->buf = (char *) fatbuf_get(fb, (44 + updated.id.size + updated.rev_meta.size)); error_unless(seqval->buf, COUCHSTORE_ERROR_ALLOC_FAIL); seqval->size = assemble_seq_index_value(&updated, seqval->buf); idval->buf = (char *) fatbuf_get(fb, (44 + 10 + updated.rev_meta.size)); error_unless(idval->buf, COUCHSTORE_ERROR_ALLOC_FAIL); idval->size = assemble_id_index_value(&updated, idval->buf); //We use 37 + id.size + 2 * rev_meta.size bytes cleanup: return errcode; }
LIBCOUCHSTORE_API couchstore_error_t couchstore_walk_seq_tree(Db *db, uint64_t startSequence, couchstore_docinfos_options options, couchstore_walk_tree_callback_fn callback, void *ctx) { raw_48 start_termbuf = encode_raw48(startSequence); sized_buf start_term = {(char*)&start_termbuf, 6}; return couchstore_walk_tree(db, 0, db->header.by_seq_root, &start_term, options, seq_cmp, callback, ctx); }
static couchstore_error_t write_header(Db *db) { sized_buf writebuf; size_t seqrootsize = 0, idrootsize = 0, localrootsize = 0; if (db->header.by_seq_root) { seqrootsize = ROOT_BASE_SIZE + db->header.by_seq_root->reduce_value.size; } if (db->header.by_id_root) { idrootsize = ROOT_BASE_SIZE + db->header.by_id_root->reduce_value.size; } if (db->header.local_docs_root) { localrootsize = ROOT_BASE_SIZE + db->header.local_docs_root->reduce_value.size; } writebuf.size = sizeof(raw_file_header) + seqrootsize + idrootsize + localrootsize; writebuf.buf = (char *) calloc(1, writebuf.size); raw_file_header* header = (raw_file_header*)writebuf.buf; header->version = encode_raw08(COUCH_DISK_VERSION); header->update_seq = encode_raw48(db->header.update_seq); header->purge_seq = encode_raw48(db->header.purge_seq); header->purge_ptr = encode_raw48(db->header.purge_ptr); header->seqrootsize = encode_raw16((uint16_t)seqrootsize); header->idrootsize = encode_raw16((uint16_t)idrootsize); header->localrootsize = encode_raw16((uint16_t)localrootsize); uint8_t *root = (uint8_t*)(header + 1); encode_root(root, db->header.by_seq_root); root += seqrootsize; encode_root(root, db->header.by_id_root); root += idrootsize; encode_root(root, db->header.local_docs_root); cs_off_t pos; couchstore_error_t errcode = db_write_header(&db->file, &writebuf, &pos); if (errcode == COUCHSTORE_SUCCESS) { db->header.position = pos; } free(writebuf.buf); return errcode; }
LIBCOUCHSTORE_API couchstore_error_t couchstore_changes_since(Db *db, uint64_t since, couchstore_docinfos_options options, couchstore_changes_callback_fn callback, void *ctx) { char since_termbuf[6]; sized_buf since_term; sized_buf *keylist = &since_term; lookup_context cbctx = {db, options, callback, ctx, 0, 0, NULL}; couchfile_lookup_request rq; sized_buf cmptmp; couchstore_error_t errcode; if (db->header.by_seq_root == NULL) { return COUCHSTORE_SUCCESS; } since_term.buf = since_termbuf; since_term.size = 6; *(raw_48*)since_term.buf = encode_raw48(since); rq.cmp.compare = seq_cmp; rq.cmp.arg = &cmptmp; rq.file = &db->file; rq.num_keys = 1; rq.keys = &keylist; rq.callback_ctx = &cbctx; rq.fetch_callback = lookup_callback; rq.node_callback = NULL; rq.fold = 1; errcode = btree_lookup(&rq, db->header.by_seq_root->pointer); return errcode; }