Example #1
0
static couchstore_error_t local_doc_fetch(couchfile_lookup_request *rq,
        void *k,
        sized_buf *v)
{
    sized_buf *id = (sized_buf *) k;
    LocalDoc **lDoc = (LocalDoc **) rq->callback_ctx;
    LocalDoc *dp;

    if (!v) {
        *lDoc = NULL;
        return COUCHSTORE_SUCCESS;
    }
    fatbuf *ldbuf = fatbuf_alloc(sizeof(LocalDoc) + id->size + v->size);
    if (ldbuf == NULL) {
        return COUCHSTORE_ERROR_ALLOC_FAIL;
    }

    dp = *lDoc = (LocalDoc *) fatbuf_get(ldbuf, sizeof(LocalDoc));
    dp->id.buf = (char *) fatbuf_get(ldbuf, id->size);
    dp->id.size = id->size;

    dp->json.buf = (char *) fatbuf_get(ldbuf, v->size);
    dp->json.size = v->size;

    dp->deleted = 0;

    memcpy(dp->id.buf, id->buf, id->size);
    memcpy(dp->json.buf, v->buf, v->size);

    return COUCHSTORE_SUCCESS;
}
Example #2
0
static void docset_init(int numdocs)
{
    testdocset.size = numdocs;
    testdocset.pos = 0;
    testdocset.datasize = 0;
    if (docsetbuf) {
        fatbuf_free(docsetbuf);
        docsetbuf = NULL;
    }

    docsetbuf = fatbuf_alloc(numdocs * (sizeof(Doc) + sizeof(DocInfo)));
    testdocset.docs = fatbuf_get(docsetbuf, numdocs * sizeof(Doc));
    testdocset.infos = fatbuf_get(docsetbuf, numdocs * sizeof(DocInfo));
    ZERO(testdocset.counters);
}
Example #3
0
//Fill in doc from reading file.
static couchstore_error_t bp_to_doc(Doc **pDoc, Db *db, cs_off_t bp, couchstore_open_options options)
{
    couchstore_error_t errcode = COUCHSTORE_SUCCESS;
    int bodylen = 0;
    char *docbody = NULL;
    fatbuf *docbuf = NULL;

    if (options & DECOMPRESS_DOC_BODIES) {
        bodylen = pread_compressed(&db->file, bp, &docbody);
    } else {
        bodylen = pread_bin(&db->file, bp, &docbody);
    }

    error_unless(bodylen >= 0, bodylen);    // if bodylen is negative it's an error code
    error_unless(docbody || bodylen == 0, COUCHSTORE_ERROR_READ);

    error_unless(docbuf = fatbuf_alloc(sizeof(Doc) + bodylen), COUCHSTORE_ERROR_ALLOC_FAIL);
    *pDoc = (Doc *) fatbuf_get(docbuf, sizeof(Doc));

    if (bodylen == 0) { //Empty doc
        (*pDoc)->data.buf = NULL;
        (*pDoc)->data.size = 0;
        return 0;
    }

    (*pDoc)->data.buf = (char *) fatbuf_get(docbuf, bodylen);
    (*pDoc)->data.size = bodylen;
    memcpy((*pDoc)->data.buf, docbody, bodylen);

cleanup:
    free(docbody);
    if (errcode < 0) {
        fatbuf_free(docbuf);
    }
    return errcode;
}
Example #4
0
LIBCOUCHSTORE_API
couchstore_error_t couchstore_save_documents(Db *db,
                                             Doc* const docs[],
                                             DocInfo *infos[],
                                             unsigned numdocs,
                                             couchstore_save_options options)
{
    couchstore_error_t errcode = COUCHSTORE_SUCCESS;
    unsigned ii;
    sized_buf *seqklist, *idklist, *seqvlist, *idvlist;
    size_t term_meta_size = 0;
    const Doc *curdoc;
    uint64_t seq = db->header.update_seq;

    fatbuf *fb;
    
    for (ii = 0; ii < numdocs; ii++) {
        // Get additional size for terms to be inserted into indexes
        // IMPORTANT: This must match the sizes of the fatbuf_get calls in add_doc_to_update_list!
        term_meta_size += 6
                        + 44 + infos[ii]->id.size + infos[ii]->rev_meta.size
                        + 44 + 10 + infos[ii]->rev_meta.size;
    }

    fb = fatbuf_alloc(term_meta_size +
                      numdocs * (sizeof(sized_buf) * 4)); //seq/id key and value lists

    if (fb == NULL) {
        return COUCHSTORE_ERROR_ALLOC_FAIL;
    }


    seqklist = fatbuf_get(fb, numdocs * sizeof(sized_buf));
    idklist = fatbuf_get(fb, numdocs * sizeof(sized_buf));
    seqvlist = fatbuf_get(fb, numdocs * sizeof(sized_buf));
    idvlist = fatbuf_get(fb, numdocs * sizeof(sized_buf));

    for (ii = 0; ii < numdocs; ii++) {
        seq++;
        if (docs) {
            curdoc = docs[ii];
        } else {
            curdoc = NULL;
        }

        errcode = add_doc_to_update_list(db, curdoc, infos[ii], fb,
                                         &seqklist[ii], &idklist[ii],
                                         &seqvlist[ii], &idvlist[ii],
                                         seq, options);
        if (errcode != COUCHSTORE_SUCCESS) {
            break;
        }
    }

    if (errcode == COUCHSTORE_SUCCESS) {
        errcode = update_indexes(db, seqklist, seqvlist,
                                 idklist, idvlist, numdocs);
    }

    fatbuf_free(fb);
    if (errcode == COUCHSTORE_SUCCESS) {
        // Fill in the assigned sequence numbers for caller's later use:
        seq = db->header.update_seq;
        for (ii = 0; ii < numdocs; ii++) {
            infos[ii]->db_seq = ++seq;
        }
        db->header.update_seq = seq;
    }

    return errcode;
}
Example #5
0
static couchstore_error_t update_indexes(Db *db,
                                         sized_buf *seqs,
                                         sized_buf *seqvals,
                                         sized_buf *ids,
                                         sized_buf *idvals,
                                         int numdocs)
{
    couchfile_modify_action *idacts;
    couchfile_modify_action *seqacts;
    const sized_buf **sorted_ids = NULL;
    size_t size;
    fatbuf *actbuf;
    node_pointer *new_id_root;
    node_pointer *new_seq_root;
    couchstore_error_t errcode;
    couchfile_modify_request seqrq, idrq;
    sized_buf tmpsb;
    int ii;

    /*
    ** Two action list up to numdocs * 2 in size + Compare keys for ids,
    ** and compare keys for removed seqs found from id index +
    ** Max size of a int64 erlang term (for deleted seqs)
    */
    size = 4 * sizeof(couchfile_modify_action) + 2 * sizeof(sized_buf) + 10;

    actbuf = fatbuf_alloc(numdocs * size);
    error_unless(actbuf, COUCHSTORE_ERROR_ALLOC_FAIL);

    idacts = fatbuf_get(actbuf, numdocs * sizeof(couchfile_modify_action) * 2);
    seqacts = fatbuf_get(actbuf, numdocs * sizeof(couchfile_modify_action) * 2);
    error_unless(idacts && seqacts, COUCHSTORE_ERROR_ALLOC_FAIL);

    index_update_ctx fetcharg = {
        seqacts, 0, &seqs, &seqvals, 0, actbuf
    };

    // Sort the array indexes of ids[] by ascending id. Since we can't pass context info to qsort,
    // actually sort an array of pointers to the elements of ids[], rather than the array indexes.
    sorted_ids = malloc(numdocs * sizeof(sized_buf*));
    error_unless(sorted_ids, COUCHSTORE_ERROR_ALLOC_FAIL);
    for (ii = 0; ii < numdocs; ++ii) {
        sorted_ids[ii] = &ids[ii];
    }
    qsort(sorted_ids, numdocs, sizeof(sorted_ids[0]), &ebin_ptr_compare);

    // Assemble idacts[] array, in sorted order by id:
    for (ii = 0; ii < numdocs; ii++) {
        ptrdiff_t isorted = sorted_ids[ii] - ids;   // recover index of ii'th id in sort order

        idacts[ii * 2].type = ACTION_FETCH;
        idacts[ii * 2].value.arg = &fetcharg;
        idacts[ii * 2 + 1].type = ACTION_INSERT;
        idacts[ii * 2 + 1].value.data = &idvals[isorted];
        idacts[ii * 2].key = &ids[isorted];
        idacts[ii * 2 + 1].key = &ids[isorted];
    }

    idrq.cmp.compare = ebin_cmp;
    idrq.cmp.arg = &tmpsb;
    idrq.db = db;
    idrq.actions = idacts;
    idrq.num_actions = numdocs * 2;
    idrq.reduce = by_id_reduce;
    idrq.rereduce = by_id_rereduce;
    idrq.fetch_callback = idfetch_update_cb;
    idrq.db = db;
    idrq.compacting = 0;

    new_id_root = modify_btree(&idrq, db->header.by_id_root, &errcode);
    error_pass(errcode);

    while (fetcharg.valpos < numdocs) {
        seqacts[fetcharg.actpos].type = ACTION_INSERT;
        seqacts[fetcharg.actpos].value.data = &seqvals[fetcharg.valpos];
        seqacts[fetcharg.actpos].key = &seqs[fetcharg.valpos];
        fetcharg.valpos++;
        fetcharg.actpos++;
    }

    //printf("Total seq actions: %d\n", fetcharg.actpos);
    qsort(seqacts, fetcharg.actpos, sizeof(couchfile_modify_action),
          seq_action_compare);

    seqrq.cmp.compare = seq_cmp;
    seqrq.cmp.arg = &tmpsb;
    seqrq.actions = seqacts;
    seqrq.num_actions = fetcharg.actpos;
    seqrq.reduce = by_seq_reduce;
    seqrq.rereduce = by_seq_rereduce;
    seqrq.db = db;
    seqrq.compacting = 0;

    new_seq_root = modify_btree(&seqrq, db->header.by_seq_root, &errcode);
    if (errcode != COUCHSTORE_SUCCESS) {
        fatbuf_free(actbuf);
        return errcode;
    }

    if (db->header.by_id_root != new_id_root) {
        free(db->header.by_id_root);
        db->header.by_id_root = new_id_root;
    }

    if (db->header.by_seq_root != new_seq_root) {
        free(db->header.by_seq_root);
        db->header.by_seq_root = new_seq_root;
    }

cleanup:
    free(sorted_ids);
    fatbuf_free(actbuf);
    return errcode;
}