static lcb_error_t do_store3(lcb_t instance, const void *cookie, const lcb_CMDBASE *cmd, int is_durstore) { mc_PIPELINE *pipeline; mc_PACKET *packet; mc_REQDATA *rdata; mc_CMDQUEUE *cq = &instance->cmdq; int hsize; int should_compress = 0; lcb_error_t err; lcb_storage_t operation; lcb_U32 flags; const lcb_VALBUF *vbuf; lcb_datatype_t datatype; protocol_binary_request_set scmd; protocol_binary_request_header *hdr = &scmd.message.header; if (!is_durstore) { const lcb_CMDSTORE *simple_cmd = (const lcb_CMDSTORE *)cmd; operation = simple_cmd->operation; flags = simple_cmd->flags; vbuf = &simple_cmd->value; datatype = simple_cmd->datatype; } else { const lcb_CMDSTOREDUR *durcmd = (const lcb_CMDSTOREDUR *)cmd; operation = durcmd->operation; flags = durcmd->flags; vbuf = &durcmd->value; datatype = durcmd->datatype; } if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) { return LCB_EMPTY_KEY; } err = get_esize_and_opcode( operation, &hdr->request.opcode, &hdr->request.extlen); if (err != LCB_SUCCESS) { return err; } switch (operation) { case LCB_APPEND: case LCB_PREPEND: if (cmd->exptime || flags) { return LCB_OPTIONS_CONFLICT; } break; case LCB_ADD: if (cmd->cas) { return LCB_OPTIONS_CONFLICT; } break; default: break; } hsize = hdr->request.extlen + sizeof(*hdr); err = mcreq_basic_packet(cq, (const lcb_CMDBASE *)cmd, hdr, hdr->request.extlen, &packet, &pipeline, MCREQ_BASICPACKET_F_FALLBACKOK); if (err != LCB_SUCCESS) { return err; } should_compress = can_compress(instance, pipeline, vbuf, datatype); if (should_compress) { int rv = mcreq_compress_value(pipeline, packet, &vbuf->u_buf.contig); if (rv != 0) { mcreq_release_packet(pipeline, packet); return LCB_CLIENT_ENOMEM; } } else { mcreq_reserve_value(pipeline, packet, vbuf); } if (is_durstore) { int duropts = 0; lcb_U16 persist_u , replicate_u; const lcb_CMDSTOREDUR *dcmd = (const lcb_CMDSTOREDUR *)cmd; DURSTORECTX *dctx = calloc(1, sizeof(*dctx)); persist_u = dcmd->persist_to; replicate_u = dcmd->replicate_to; if (dcmd->replicate_to == -1 || dcmd->persist_to == -1) { duropts = LCB_DURABILITY_VALIDATE_CAPMAX; } err = lcb_durability_validate(instance, &persist_u, &replicate_u, duropts); if (err != LCB_SUCCESS) { mcreq_wipe_packet(pipeline, packet); mcreq_release_packet(pipeline, packet); return err; } dctx->instance = instance; dctx->persist_to = persist_u; dctx->replicate_to = replicate_u; packet->u_rdata.exdata = &dctx->base; packet->flags |= MCREQ_F_REQEXT; dctx->base.cookie = cookie; dctx->base.procs = &storedur_procs; } rdata = MCREQ_PKT_RDATA(packet); rdata->cookie = cookie; rdata->start = gethrtime(); scmd.message.body.expiration = htonl(cmd->exptime); scmd.message.body.flags = htonl(flags); hdr->request.magic = PROTOCOL_BINARY_REQ; hdr->request.cas = cmd->cas; hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES; if (should_compress || (datatype & LCB_VALUE_F_SNAPPYCOMP)) { hdr->request.datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED; } if (datatype & LCB_VALUE_F_JSON) { hdr->request.datatype |= PROTOCOL_BINARY_DATATYPE_JSON; } hdr->request.opaque = packet->opaque; hdr->request.bodylen = htonl( hdr->request.extlen + ntohs(hdr->request.keylen) + get_value_size(packet)); memcpy(SPAN_BUFFER(&packet->kh_span), scmd.bytes, hsize); mcreq_sched_add(pipeline, packet); TRACE_STORE_BEGIN(hdr, (lcb_CMDSTORE* )cmd); return LCB_SUCCESS; }
/** * Spool a store request * * @author Trond Norbye * @todo add documentation * @todo fix the expiration so that it works relative/absolute etc.. * @todo we might want to wait to write the data to the sockets if the * user want to run a batch of store requests? */ LIBCOUCHBASE_API lcb_error_t lcb_store(lcb_t instance, const void *command_cookie, lcb_size_t num, const lcb_store_cmd_t *const *items) { lcb_size_t ii; /* we need a vbucket config before we can start getting data.. */ if (instance->vbucket_config == NULL) { switch (instance->type) { case LCB_TYPE_CLUSTER: return lcb_synchandler_return(instance, LCB_EBADHANDLE); case LCB_TYPE_BUCKET: default: return lcb_synchandler_return(instance, LCB_CLIENT_ETMPFAIL); } } for (ii = 0; ii < num; ++ii) { lcb_server_t *server; protocol_binary_request_set req; lcb_size_t headersize; lcb_size_t bodylen; int vb, idx; lcb_storage_t operation = items[ii]->v.v0.operation; const void *key = items[ii]->v.v0.key; lcb_size_t nkey = items[ii]->v.v0.nkey; lcb_cas_t cas = items[ii]->v.v0.cas; lcb_uint32_t flags = items[ii]->v.v0.flags; lcb_time_t exp = items[ii]->v.v0.exptime; const void *bytes = items[ii]->v.v0.bytes; lcb_size_t nbytes = items[ii]->v.v0.nbytes; const void *hashkey = items[ii]->v.v0.hashkey; lcb_size_t nhashkey = items[ii]->v.v0.nhashkey; if (nhashkey == 0) { hashkey = key; nhashkey = nkey; } (void)vbucket_map(instance->vbucket_config, hashkey, nhashkey, &vb, &idx); if (idx < 0 || idx > (int)instance->nservers) { return lcb_synchandler_return(instance, LCB_NO_MATCHING_SERVER); } server = instance->servers + idx; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.keylen = ntohs((lcb_uint16_t)nkey); req.message.header.request.extlen = 8; req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.vbucket = ntohs((lcb_uint16_t)vb); req.message.header.request.opaque = ++instance->seqno; req.message.header.request.cas = cas; req.message.body.flags = htonl(flags); req.message.body.expiration = htonl((lcb_uint32_t)exp); headersize = sizeof(req.bytes); switch (operation) { case LCB_ADD: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_ADD; break; case LCB_REPLACE: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_REPLACE; break; case LCB_SET: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_SET; break; case LCB_APPEND: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_APPEND; req.message.header.request.extlen = 0; headersize -= 8; break; case LCB_PREPEND: req.message.header.request.opcode = PROTOCOL_BINARY_CMD_PREPEND; req.message.header.request.extlen = 0; headersize -= 8; break; default: /* We were given an unknown storage operation. */ return lcb_synchandler_return(instance, lcb_error_handler(instance, LCB_EINVAL, "Invalid value passed as storage operation")); } /* Make it known that this was a success. */ lcb_error_handler(instance, LCB_SUCCESS, NULL); bodylen = nkey + nbytes + req.message.header.request.extlen; req.message.header.request.bodylen = htonl((lcb_uint32_t)bodylen); TRACE_STORE_BEGIN(&req, key, nkey, bytes, nbytes, flags, exp); lcb_server_start_packet(server, command_cookie, &req, headersize); lcb_server_write_packet(server, key, nkey); lcb_server_write_packet(server, bytes, nbytes); lcb_server_end_packet(server); lcb_server_send_packets(server); } return lcb_synchandler_return(instance, LCB_SUCCESS); }
LIBCOUCHBASE_API lcb_error_t lcb_store3(lcb_t instance, const void *cookie, const lcb_CMDSTORE *cmd) { mc_PIPELINE *pipeline; mc_PACKET *packet; mc_REQDATA *rdata; mc_CMDQUEUE *cq = &instance->cmdq; int hsize; int should_compress = 0; lcb_error_t err; protocol_binary_request_set scmd; protocol_binary_request_header *hdr = &scmd.message.header; if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) { return LCB_EMPTY_KEY; } err = get_esize_and_opcode( cmd->operation, &hdr->request.opcode, &hdr->request.extlen); if (err != LCB_SUCCESS) { return err; } hsize = hdr->request.extlen + sizeof(*hdr); err = mcreq_basic_packet(cq, (const lcb_CMDBASE *)cmd, hdr, hdr->request.extlen, &packet, &pipeline, MCREQ_BASICPACKET_F_FALLBACKOK); if (err != LCB_SUCCESS) { return err; } should_compress = can_compress(instance, pipeline, cmd); if (should_compress) { int rv = mcreq_compress_value(pipeline, packet, &cmd->value.u_buf.contig); if (rv != 0) { mcreq_release_packet(pipeline, packet); return LCB_CLIENT_ENOMEM; } } else { mcreq_reserve_value(pipeline, packet, &cmd->value); } rdata = &packet->u_rdata.reqdata; rdata->cookie = cookie; rdata->start = gethrtime(); scmd.message.body.expiration = htonl(cmd->exptime); scmd.message.body.flags = htonl(cmd->flags); hdr->request.magic = PROTOCOL_BINARY_REQ; hdr->request.cas = cmd->cas; hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES; if (should_compress || (cmd->datatype & LCB_VALUE_F_SNAPPYCOMP)) { hdr->request.datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED; } if (cmd->datatype & LCB_VALUE_F_JSON) { hdr->request.datatype |= PROTOCOL_BINARY_DATATYPE_JSON; } hdr->request.opaque = packet->opaque; hdr->request.bodylen = htonl( hdr->request.extlen + ntohs(hdr->request.keylen) + get_value_size(packet)); memcpy(SPAN_BUFFER(&packet->kh_span), scmd.bytes, hsize); mcreq_sched_add(pipeline, packet); TRACE_STORE_BEGIN(hdr, cmd); return LCB_SUCCESS; }