static couchstore_error_t write_doc(Db *db, const Doc *doc, uint64_t *bp, size_t* disk_size, couchstore_save_options writeopts) { couchstore_error_t errcode; if (writeopts & COMPRESS_DOC_BODIES) { errcode = db_write_buf_compressed(db, &doc->data, (off_t *) bp, disk_size); } else { errcode = db_write_buf(db, &doc->data, (off_t *) bp, disk_size); } return errcode; }
//Write a node using enough items from the values list to create a node //with uncompressed size of at least mr_quota static couchstore_error_t flush_mr_partial(couchfile_modify_result *res, size_t mr_quota) { char *dst; int errcode = COUCHSTORE_SUCCESS; int itmcount = 0; char *nodebuf = NULL; sized_buf writebuf; char reducebuf[30]; size_t reducesize = 0; uint64_t subtreesize = 0; off_t diskpos; size_t disk_size; sized_buf final_key = {NULL, 0}; if (res->values_end == res->values || ! res->modified) { //Empty return COUCHSTORE_SUCCESS; } // nodebuf/writebuf is very short-lived and can be large, so use regular malloc heap for it: nodebuf = malloc(res->node_len + 1); if (!nodebuf) { return COUCHSTORE_ERROR_ALLOC_FAIL; } writebuf.buf = nodebuf; dst = nodebuf; *(dst++) = (char) res->node_type; nodelist *i = res->values->next; //We don't care that we've reached mr_quota if we haven't written out //at least two items and we're not writing a leaf node. while (i != NULL && (mr_quota > 0 || (itmcount < 2 && res->node_type == KP_NODE))) { dst = write_kv(dst, i->key, i->data); if (i->pointer) { subtreesize += i->pointer->subtreesize; } mr_quota -= i->key.size + i->data.size + 5; final_key = i->key; i = i->next; res->count--; itmcount++; } writebuf.size = dst - nodebuf; errcode = db_write_buf_compressed(res->rq->db, &writebuf, &diskpos, &disk_size); free(nodebuf); // here endeth the nodebuf. if (errcode != COUCHSTORE_SUCCESS) { return errcode; } if (res->node_type == KV_NODE && res->rq->reduce) { res->rq->reduce(reducebuf, &reducesize, res->values->next, itmcount); } if (res->node_type == KP_NODE && res->rq->rereduce) { res->rq->rereduce(reducebuf, &reducesize, res->values->next, itmcount); } node_pointer *ptr = (node_pointer *) arena_alloc(res->arena, sizeof(node_pointer) + final_key.size + reducesize); if (!ptr) { return COUCHSTORE_ERROR_ALLOC_FAIL; } ptr->key.buf = ((char *)ptr) + sizeof(node_pointer); ptr->reduce_value.buf = ((char *)ptr) + sizeof(node_pointer) + final_key.size; ptr->key.size = final_key.size; ptr->reduce_value.size = reducesize; memcpy(ptr->key.buf, final_key.buf, final_key.size); memcpy(ptr->reduce_value.buf, reducebuf, reducesize); ptr->subtreesize = subtreesize + disk_size; ptr->pointer = diskpos; nodelist *pel = encode_pointer(res->arena, ptr); if (!pel) { return COUCHSTORE_ERROR_ALLOC_FAIL; } res->pointers_end->next = pel; res->pointers_end = pel; res->node_len -= (writebuf.size - 1); res->values->next = i; if(i == NULL) { res->values_end = res->values; } return COUCHSTORE_SUCCESS; }
/* Write a node using enough items from the values list to create a node * with uncompressed size of at least mr_quota */ static couchstore_error_t flush_spatial_partial(couchfile_modify_result *res, size_t mr_quota) { char *dst; couchstore_error_t errcode = COUCHSTORE_SUCCESS; int itmcount = 0; char *nodebuf = NULL; sized_buf writebuf; char reducebuf[MAX_REDUCTION_SIZE]; size_t reducesize = 0; uint64_t subtreesize = 0; cs_off_t diskpos; size_t disk_size; nodelist *i, *pel; node_pointer *ptr; if (res->values_end == res->values || ! res->modified) { /* Empty */ return COUCHSTORE_SUCCESS; } /* nodebuf/writebuf is very short-lived and can be large, so use regular * malloc heap for it: */ nodebuf = (char *) cb_malloc(res->node_len + 1); if (nodebuf == NULL) { return COUCHSTORE_ERROR_ALLOC_FAIL; } writebuf.buf = nodebuf; dst = nodebuf; *(dst++) = (char) res->node_type; i = res->values->next; /* We don't care that we've reached mr_quota if we haven't written out * at least two items and we're not writing a leaf node. */ while (i != NULL && (mr_quota > 0 || (itmcount < 2 && res->node_type == KP_NODE))) { dst = (char *) write_kv(dst, i->key, i->data); if (i->pointer) { subtreesize += i->pointer->subtreesize; } mr_quota -= i->key.size + i->data.size + sizeof(raw_kv_length); i = i->next; res->count--; itmcount++; } writebuf.size = dst - nodebuf; errcode = (couchstore_error_t) db_write_buf_compressed( res->rq->file, &writebuf, &diskpos, &disk_size); cb_free(nodebuf); /* here endeth the nodebuf. */ if (errcode != COUCHSTORE_SUCCESS) { return errcode; } /* Store the enclosing MBB in the reducebuf */ if (res->node_type == KV_NODE && res->rq->reduce) { errcode = res->rq->reduce( reducebuf, &reducesize, res->values->next, itmcount, res->rq->user_reduce_ctx); if (errcode != COUCHSTORE_SUCCESS) { return errcode; } cb_assert(reducesize <= sizeof(reducebuf)); } if (res->node_type == KP_NODE && res->rq->rereduce) { errcode = res->rq->rereduce( reducebuf, &reducesize, res->values->next, itmcount, res->rq->user_reduce_ctx); if (errcode != COUCHSTORE_SUCCESS) { return errcode; } cb_assert(reducesize <= sizeof(reducebuf)); } /* `reducesize` one time for the key, one time for the actual reduce */ ptr = (node_pointer *) arena_alloc( res->arena, sizeof(node_pointer) + 2 * reducesize); if (ptr == NULL) { return COUCHSTORE_ERROR_ALLOC_FAIL; } ptr->key.buf = ((char *)ptr) + sizeof(node_pointer); ptr->reduce_value.buf = ((char *)ptr) + sizeof(node_pointer) + reducesize; ptr->key.size = reducesize; ptr->reduce_value.size = reducesize; /* Store the enclosing MBB that was calculate in the reduce function * as the key. The reduce also stores it as it is the "Original MBB" * used in the RR*-tree algorithm */ memcpy(ptr->key.buf, reducebuf, reducesize); memcpy(ptr->reduce_value.buf, reducebuf, reducesize); ptr->subtreesize = subtreesize + disk_size; ptr->pointer = diskpos; pel = encode_pointer(res->arena, ptr); if (pel == NULL) { return COUCHSTORE_ERROR_ALLOC_FAIL; } res->pointers_end->next = pel; res->pointers_end = pel; res->node_len -= (writebuf.size - 1); res->values->next = i; if(i == NULL) { res->values_end = res->values; } return COUCHSTORE_SUCCESS; }