xref: /trunk/libcouchbase/src/operations/store.cc (revision f6822fcc)
107521d60SSergey Avseyev /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
26a82bf9aSMark Nunberg /*
3ebf3e5c1SSergey Avseyev  *     Copyright 2010-2020 Couchbase, Inc.
46a82bf9aSMark Nunberg  *
56a82bf9aSMark Nunberg  *   Licensed under the Apache License, Version 2.0 (the "License");
66a82bf9aSMark Nunberg  *   you may not use this file except in compliance with the License.
76a82bf9aSMark Nunberg  *   You may obtain a copy of the License at
86a82bf9aSMark Nunberg  *
96a82bf9aSMark Nunberg  *       http://www.apache.org/licenses/LICENSE-2.0
106a82bf9aSMark Nunberg  *
116a82bf9aSMark Nunberg  *   Unless required by applicable law or agreed to in writing, software
126a82bf9aSMark Nunberg  *   distributed under the License is distributed on an "AS IS" BASIS,
136a82bf9aSMark Nunberg  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
146a82bf9aSMark Nunberg  *   See the License for the specific language governing permissions and
156a82bf9aSMark Nunberg  *   limitations under the License.
166a82bf9aSMark Nunberg  */
176a82bf9aSMark Nunberg #include "internal.h"
18ebf3e5c1SSergey Avseyev #include "collections.h"
196a82bf9aSMark Nunberg #include "mc/compress.h"
206a82bf9aSMark Nunberg #include "trace.h"
213280c1b9SSergey Avseyev #include "defer.h"
226a82bf9aSMark Nunberg #include "durability_internal.h"
236a82bf9aSMark Nunberg 
241681996eSSergey Avseyev #include "capi/cmd_store.hh"
251681996eSSergey Avseyev 
lcb_mutation_token_is_valid(const lcb_MUTATION_TOKEN * token)2607521d60SSergey Avseyev LIBCOUCHBASE_API int lcb_mutation_token_is_valid(const lcb_MUTATION_TOKEN *token)
2707521d60SSergey Avseyev {
2807521d60SSergey Avseyev     return token && !(token->uuid_ == 0 && token->seqno_ == 0 && token->vbid_ == 0);
2907521d60SSergey Avseyev }
3007521d60SSergey Avseyev 
lcb_respstore_status(const lcb_RESPSTORE * resp)3107521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_status(const lcb_RESPSTORE *resp)
3207521d60SSergey Avseyev {
336ae99e49SSergey Avseyev     return resp->ctx.rc;
3407521d60SSergey Avseyev }
3507521d60SSergey Avseyev 
lcb_respstore_error_context(const lcb_RESPSTORE * resp,const lcb_KEY_VALUE_ERROR_CONTEXT ** ctx)366ae99e49SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_error_context(const lcb_RESPSTORE *resp,
376ae99e49SSergey Avseyev                                                         const lcb_KEY_VALUE_ERROR_CONTEXT **ctx)
3807521d60SSergey Avseyev {
396ae99e49SSergey Avseyev     *ctx = &resp->ctx;
4007521d60SSergey Avseyev     return LCB_SUCCESS;
4107521d60SSergey Avseyev }
4207521d60SSergey Avseyev 
lcb_respstore_cookie(const lcb_RESPSTORE * resp,void ** cookie)4307521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_cookie(const lcb_RESPSTORE *resp, void **cookie)
4407521d60SSergey Avseyev {
4507521d60SSergey Avseyev     *cookie = resp->cookie;
4607521d60SSergey Avseyev     return LCB_SUCCESS;
4707521d60SSergey Avseyev }
4807521d60SSergey Avseyev 
lcb_respstore_cas(const lcb_RESPSTORE * resp,uint64_t * cas)4907521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_cas(const lcb_RESPSTORE *resp, uint64_t *cas)
5007521d60SSergey Avseyev {
516ae99e49SSergey Avseyev     *cas = resp->ctx.cas;
5207521d60SSergey Avseyev     return LCB_SUCCESS;
5307521d60SSergey Avseyev }
5407521d60SSergey Avseyev 
lcb_respstore_key(const lcb_RESPSTORE * resp,const char ** key,size_t * key_len)5507521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_key(const lcb_RESPSTORE *resp, const char **key, size_t *key_len)
5607521d60SSergey Avseyev {
572d8ee3cdSSergey Avseyev     *key = resp->ctx.key.c_str();
582d8ee3cdSSergey Avseyev     *key_len = resp->ctx.key.size();
5907521d60SSergey Avseyev     return LCB_SUCCESS;
6007521d60SSergey Avseyev }
6107521d60SSergey Avseyev 
lcb_respstore_operation(const lcb_RESPSTORE * resp,lcb_STORE_OPERATION * operation)6207521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_operation(const lcb_RESPSTORE *resp, lcb_STORE_OPERATION *operation)
6307521d60SSergey Avseyev {
6407521d60SSergey Avseyev     *operation = resp->op;
6507521d60SSergey Avseyev     return LCB_SUCCESS;
6607521d60SSergey Avseyev }
6707521d60SSergey Avseyev 
lcb_respstore_observe_stored(const lcb_RESPSTORE * resp,int * store_ok)6807521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_observe_stored(const lcb_RESPSTORE *resp, int *store_ok)
6907521d60SSergey Avseyev {
702d8ee3cdSSergey Avseyev     if (resp->dur_resp == nullptr) {
71d0533ef7SSergey Avseyev         return LCB_ERR_UNSUPPORTED_OPERATION;
7207521d60SSergey Avseyev     }
7307521d60SSergey Avseyev     *store_ok = resp->store_ok;
7407521d60SSergey Avseyev     return LCB_SUCCESS;
7507521d60SSergey Avseyev }
7607521d60SSergey Avseyev 
lcb_respstore_observe_attached(const lcb_RESPSTORE * resp)7707521d60SSergey Avseyev LIBCOUCHBASE_API int lcb_respstore_observe_attached(const lcb_RESPSTORE *resp)
7807521d60SSergey Avseyev {
792d8ee3cdSSergey Avseyev     return resp->dur_resp != nullptr;
8007521d60SSergey Avseyev }
8107521d60SSergey Avseyev 
lcb_respstore_observe_master_exists(const lcb_RESPSTORE * resp,int * master_exists)8207521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_observe_master_exists(const lcb_RESPSTORE *resp, int *master_exists)
8307521d60SSergey Avseyev {
842d8ee3cdSSergey Avseyev     if (resp->dur_resp == nullptr) {
85d0533ef7SSergey Avseyev         return LCB_ERR_UNSUPPORTED_OPERATION;
8607521d60SSergey Avseyev     }
8707521d60SSergey Avseyev     *master_exists = resp->dur_resp->exists_master;
8807521d60SSergey Avseyev     return LCB_SUCCESS;
8907521d60SSergey Avseyev }
9007521d60SSergey Avseyev 
lcb_respstore_observe_master_persisted(const lcb_RESPSTORE * resp,int * master_persisted)9107521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_observe_master_persisted(const lcb_RESPSTORE *resp, int *master_persisted)
9207521d60SSergey Avseyev {
932d8ee3cdSSergey Avseyev     if (resp->dur_resp == nullptr) {
94d0533ef7SSergey Avseyev         return LCB_ERR_UNSUPPORTED_OPERATION;
9507521d60SSergey Avseyev     }
9607521d60SSergey Avseyev     *master_persisted = resp->dur_resp->persisted_master;
9707521d60SSergey Avseyev     return LCB_SUCCESS;
9807521d60SSergey Avseyev }
9907521d60SSergey Avseyev 
lcb_respstore_observe_num_responses(const lcb_RESPSTORE * resp,uint16_t * num_responses)10007521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_observe_num_responses(const lcb_RESPSTORE *resp, uint16_t *num_responses)
10107521d60SSergey Avseyev {
1022d8ee3cdSSergey Avseyev     if (resp->dur_resp == nullptr) {
103d0533ef7SSergey Avseyev         return LCB_ERR_UNSUPPORTED_OPERATION;
10407521d60SSergey Avseyev     }
10507521d60SSergey Avseyev     *num_responses = resp->dur_resp->nresponses;
10607521d60SSergey Avseyev     return LCB_SUCCESS;
10707521d60SSergey Avseyev }
10807521d60SSergey Avseyev 
lcb_respstore_observe_num_persisted(const lcb_RESPSTORE * resp,uint16_t * num_persisted)10907521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_observe_num_persisted(const lcb_RESPSTORE *resp, uint16_t *num_persisted)
11007521d60SSergey Avseyev {
1112d8ee3cdSSergey Avseyev     if (resp->dur_resp == nullptr) {
112d0533ef7SSergey Avseyev         return LCB_ERR_UNSUPPORTED_OPERATION;
11307521d60SSergey Avseyev     }
11407521d60SSergey Avseyev     *num_persisted = resp->dur_resp->npersisted;
11507521d60SSergey Avseyev     return LCB_SUCCESS;
11607521d60SSergey Avseyev }
11707521d60SSergey Avseyev 
lcb_respstore_observe_num_replicated(const lcb_RESPSTORE * resp,uint16_t * num_replicated)11807521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_observe_num_replicated(const lcb_RESPSTORE *resp, uint16_t *num_replicated)
11907521d60SSergey Avseyev {
1202d8ee3cdSSergey Avseyev     if (resp->dur_resp == nullptr) {
121d0533ef7SSergey Avseyev         return LCB_ERR_UNSUPPORTED_OPERATION;
12207521d60SSergey Avseyev     }
12307521d60SSergey Avseyev     *num_replicated = resp->dur_resp->nreplicated;
12407521d60SSergey Avseyev     return LCB_SUCCESS;
12507521d60SSergey Avseyev }
12607521d60SSergey Avseyev 
lcb_respstore_mutation_token(const lcb_RESPSTORE * resp,lcb_MUTATION_TOKEN * token)12707521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_respstore_mutation_token(const lcb_RESPSTORE *resp, lcb_MUTATION_TOKEN *token)
12807521d60SSergey Avseyev {
1292d8ee3cdSSergey Avseyev     if (token) {
1302d8ee3cdSSergey Avseyev         *token = resp->mt;
13107521d60SSergey Avseyev     }
13207521d60SSergey Avseyev     return LCB_SUCCESS;
13307521d60SSergey Avseyev }
13407521d60SSergey Avseyev 
lcb_cmdstore_create(lcb_CMDSTORE ** cmd,lcb_STORE_OPERATION operation)13507521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_create(lcb_CMDSTORE **cmd, lcb_STORE_OPERATION operation)
13607521d60SSergey Avseyev {
1373280c1b9SSergey Avseyev     *cmd = new lcb_CMDSTORE{};
1383280c1b9SSergey Avseyev     (*cmd)->operation(operation);
13907521d60SSergey Avseyev     return LCB_SUCCESS;
14007521d60SSergey Avseyev }
14107521d60SSergey Avseyev 
lcb_cmdstore_destroy(lcb_CMDSTORE * cmd)14207521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_destroy(lcb_CMDSTORE *cmd)
14307521d60SSergey Avseyev {
1443280c1b9SSergey Avseyev     delete cmd;
14507521d60SSergey Avseyev     return LCB_SUCCESS;
14607521d60SSergey Avseyev }
14707521d60SSergey Avseyev 
lcb_cmdstore_timeout(lcb_CMDSTORE * cmd,uint32_t timeout)14807521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_timeout(lcb_CMDSTORE *cmd, uint32_t timeout)
14907521d60SSergey Avseyev {
1503280c1b9SSergey Avseyev     return cmd->timeout_in_microseconds(timeout);
15107521d60SSergey Avseyev }
15207521d60SSergey Avseyev 
lcb_cmdstore_parent_span(lcb_CMDSTORE * cmd,lcbtrace_SPAN * span)15307521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_parent_span(lcb_CMDSTORE *cmd, lcbtrace_SPAN *span)
15407521d60SSergey Avseyev {
1553280c1b9SSergey Avseyev     return cmd->parent_span(span);
15607521d60SSergey Avseyev }
15707521d60SSergey Avseyev 
lcb_cmdstore_collection(lcb_CMDSTORE * cmd,const char * scope,size_t scope_len,const char * collection,size_t collection_len)1580b0310e1SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_collection(lcb_CMDSTORE *cmd, const char *scope, size_t scope_len,
1590b0310e1SSergey Avseyev                                                     const char *collection, size_t collection_len)
16007521d60SSergey Avseyev {
1613280c1b9SSergey Avseyev     try {
1623280c1b9SSergey Avseyev         lcb::collection_qualifier qualifier(scope, scope_len, collection, collection_len);
1633280c1b9SSergey Avseyev         return cmd->collection(std::move(qualifier));
1643280c1b9SSergey Avseyev     } catch (const std::invalid_argument &) {
1653280c1b9SSergey Avseyev         return LCB_ERR_INVALID_ARGUMENT;
1663280c1b9SSergey Avseyev     }
16707521d60SSergey Avseyev }
16807521d60SSergey Avseyev 
lcb_cmdstore_key(lcb_CMDSTORE * cmd,const char * key,size_t key_len)16907521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_key(lcb_CMDSTORE *cmd, const char *key, size_t key_len)
17007521d60SSergey Avseyev {
1713280c1b9SSergey Avseyev     if (key == nullptr || key_len == 0) {
1723280c1b9SSergey Avseyev         return LCB_ERR_INVALID_ARGUMENT;
1733280c1b9SSergey Avseyev     }
1743280c1b9SSergey Avseyev     return cmd->key(std::string(key, key_len));
17507521d60SSergey Avseyev }
17607521d60SSergey Avseyev 
lcb_cmdstore_value(lcb_CMDSTORE * cmd,const char * value,size_t value_len)17707521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_value(lcb_CMDSTORE *cmd, const char *value, size_t value_len)
17807521d60SSergey Avseyev {
1793280c1b9SSergey Avseyev     if (value == nullptr || value_len == 0) {
1803280c1b9SSergey Avseyev         return LCB_SUCCESS; /* empty values allowed */
1813280c1b9SSergey Avseyev     }
1823280c1b9SSergey Avseyev 
1833280c1b9SSergey Avseyev     return cmd->value(std::string(value, value_len));
18407521d60SSergey Avseyev }
18507521d60SSergey Avseyev 
lcb_cmdstore_value_iov(lcb_CMDSTORE * cmd,const lcb_IOV * value,size_t value_len)18607521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_value_iov(lcb_CMDSTORE *cmd, const lcb_IOV *value, size_t value_len)
18707521d60SSergey Avseyev {
1883280c1b9SSergey Avseyev     return cmd->value(value, value_len);
18907521d60SSergey Avseyev }
19007521d60SSergey Avseyev 
lcb_cmdstore_expiry(lcb_CMDSTORE * cmd,uint32_t expiration)191c145e61cSSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_expiry(lcb_CMDSTORE *cmd, uint32_t expiration)
19207521d60SSergey Avseyev {
1933280c1b9SSergey Avseyev     return cmd->expiry(expiration);
19407521d60SSergey Avseyev }
19507521d60SSergey Avseyev 
lcb_cmdstore_preserve_expiry(lcb_CMDSTORE * cmd,int should_preserve)196f1ce7ef8SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_preserve_expiry(lcb_CMDSTORE *cmd, int should_preserve)
197f1ce7ef8SSergey Avseyev {
198f1ce7ef8SSergey Avseyev     return cmd->preserve_expiry(should_preserve);
199f1ce7ef8SSergey Avseyev }
200f1ce7ef8SSergey Avseyev 
lcb_cmdstore_cas(lcb_CMDSTORE * cmd,uint64_t cas)20107521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_cas(lcb_CMDSTORE *cmd, uint64_t cas)
20207521d60SSergey Avseyev {
2033280c1b9SSergey Avseyev     return cmd->cas(cas);
20407521d60SSergey Avseyev }
20507521d60SSergey Avseyev 
lcb_cmdstore_flags(lcb_CMDSTORE * cmd,uint32_t flags)20607521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_flags(lcb_CMDSTORE *cmd, uint32_t flags)
20707521d60SSergey Avseyev {
2083280c1b9SSergey Avseyev     return cmd->flags(flags);
20907521d60SSergey Avseyev }
21007521d60SSergey Avseyev 
lcb_cmdstore_datatype(lcb_CMDSTORE * cmd,uint8_t datatype)21107521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_datatype(lcb_CMDSTORE *cmd, uint8_t datatype)
21207521d60SSergey Avseyev {
2133280c1b9SSergey Avseyev     if (datatype & LCB_VALUE_F_SNAPPYCOMP) {
2143280c1b9SSergey Avseyev         cmd->value_is_compressed(true);
2153280c1b9SSergey Avseyev     }
2163280c1b9SSergey Avseyev     if (datatype & LCB_VALUE_F_JSON) {
2173280c1b9SSergey Avseyev         cmd->value_is_json(true);
2183280c1b9SSergey Avseyev     }
21907521d60SSergey Avseyev     return LCB_SUCCESS;
22007521d60SSergey Avseyev }
22107521d60SSergey Avseyev 
lcb_cmdstore_durability(lcb_CMDSTORE * cmd,lcb_DURABILITY_LEVEL level)22207521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_durability(lcb_CMDSTORE *cmd, lcb_DURABILITY_LEVEL level)
22307521d60SSergey Avseyev {
2243280c1b9SSergey Avseyev     return cmd->durability_level(level);
22507521d60SSergey Avseyev }
22607521d60SSergey Avseyev 
lcb_cmdstore_durability_observe(lcb_CMDSTORE * cmd,int persist_to,int replicate_to)22707521d60SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_durability_observe(lcb_CMDSTORE *cmd, int persist_to, int replicate_to)
22807521d60SSergey Avseyev {
2293280c1b9SSergey Avseyev     return cmd->durability_poll(persist_to, replicate_to);
23007521d60SSergey Avseyev }
23107521d60SSergey Avseyev 
lcb_cmdstore_on_behalf_of(lcb_CMDSTORE * cmd,const char * data,size_t data_len)232ecbde082SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_on_behalf_of(lcb_CMDSTORE *cmd, const char *data, size_t data_len)
233ecbde082SSergey Avseyev {
234ecbde082SSergey Avseyev     return cmd->on_behalf_of(std::string(data, data_len));
235ecbde082SSergey Avseyev }
236ecbde082SSergey Avseyev 
lcb_cmdstore_on_behalf_of_extra_privilege(lcb_CMDSTORE * cmd,const char * privilege,size_t privilege_len)237*f6822fccSSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_on_behalf_of_extra_privilege(lcb_CMDSTORE *cmd, const char *privilege,
238*f6822fccSSergey Avseyev                                                                       size_t privilege_len)
239*f6822fccSSergey Avseyev {
240*f6822fccSSergey Avseyev     return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
241*f6822fccSSergey Avseyev }
242*f6822fccSSergey Avseyev 
2436a82bf9aSMark Nunberg struct DurStoreCtx : mc_REQDATAEX {
24407521d60SSergey Avseyev     lcb_INSTANCE *instance;
2456a82bf9aSMark Nunberg     lcb_U16 persist_to;
2466a82bf9aSMark Nunberg     lcb_U16 replicate_to;
2476a82bf9aSMark Nunberg 
2486a82bf9aSMark Nunberg     static mc_REQDATAPROCS proctable;
2496a82bf9aSMark Nunberg 
DurStoreCtxDurStoreCtx250e6120d06SSergey Avseyev     DurStoreCtx(lcb_INSTANCE *instance_, lcb_U16 persist_, lcb_U16 replicate_, void *cookie_)
251ebf3e5c1SSergey Avseyev         : mc_REQDATAEX(cookie_, proctable, 0), instance(instance_), persist_to(persist_), replicate_to(replicate_)
252fa499e8aSSergey Avseyev     {
2536a82bf9aSMark Nunberg     }
2546a82bf9aSMark Nunberg };
2556a82bf9aSMark Nunberg 
2566a82bf9aSMark Nunberg /** Observe stuff */
handle_dur_storecb(mc_PIPELINE *,mc_PACKET * pkt,lcb_CALLBACK_TYPE,lcb_STATUS err,const void * arg)2570edc7dc6SSergey Avseyev static void handle_dur_storecb(mc_PIPELINE *, mc_PACKET *pkt, lcb_CALLBACK_TYPE /* cbtype */, lcb_STATUS err,
2580edc7dc6SSergey Avseyev                                const void *arg)
2596a82bf9aSMark Nunberg {
2606a82bf9aSMark Nunberg     lcb_RESPCALLBACK cb;
2616ae99e49SSergey Avseyev     lcb_RESPSTORE resp{};
2626a82bf9aSMark Nunberg     lcb_CMDENDURE dcmd = {0};
2632d8ee3cdSSergey Avseyev     auto *dctx = static_cast<DurStoreCtx *>(pkt->u_rdata.exdata);
2646a82bf9aSMark Nunberg     lcb_MULTICMD_CTX *mctx;
2656a82bf9aSMark Nunberg     lcb_durability_opts_t opts = {0};
2662d8ee3cdSSergey Avseyev     const auto *sresp = (const lcb_RESPSTORE *)arg;
2672d8ee3cdSSergey Avseyev     lcbtrace_SPAN *span = nullptr;
2686a82bf9aSMark Nunberg 
2696a82bf9aSMark Nunberg     if (err != LCB_SUCCESS) {
2706a82bf9aSMark Nunberg         goto GT_BAIL;
2716a82bf9aSMark Nunberg     }
2726ae99e49SSergey Avseyev     if (sresp->ctx.rc != LCB_SUCCESS) {
2736ae99e49SSergey Avseyev         err = sresp->ctx.rc;
2746a82bf9aSMark Nunberg         goto GT_BAIL;
2756a82bf9aSMark Nunberg     }
2766a82bf9aSMark Nunberg 
2776a82bf9aSMark Nunberg     resp.store_ok = 1;
2782d8ee3cdSSergey Avseyev     LCB_CMD_SET_KEY(&dcmd, sresp->ctx.key.c_str(), sresp->ctx.key.size());
2796ae99e49SSergey Avseyev     dcmd.cas = sresp->ctx.cas;
2806a82bf9aSMark Nunberg 
2812d8ee3cdSSergey Avseyev     if (LCB_MUTATION_TOKEN_ISVALID(&sresp->mt)) {
2822d8ee3cdSSergey Avseyev         dcmd.mutation_token = &sresp->mt;
2836a82bf9aSMark Nunberg     }
2846a82bf9aSMark Nunberg 
2856a82bf9aSMark Nunberg     /* Set the options.. */
2866a82bf9aSMark Nunberg     opts.v.v0.persist_to = dctx->persist_to;
2876a82bf9aSMark Nunberg     opts.v.v0.replicate_to = dctx->replicate_to;
2886a82bf9aSMark Nunberg 
2896a82bf9aSMark Nunberg     mctx = lcb_endure3_ctxnew(dctx->instance, &opts, &err);
2902d8ee3cdSSergey Avseyev     if (mctx == nullptr) {
2916a82bf9aSMark Nunberg         goto GT_BAIL;
2926a82bf9aSMark Nunberg     }
2936a82bf9aSMark Nunberg 
29407521d60SSergey Avseyev     span = MCREQ_PKT_RDATA(pkt)->span;
2959c0ab8aaSSergey Avseyev     if (span) {
2969c0ab8aaSSergey Avseyev         mctx->setspan(mctx, span);
2979c0ab8aaSSergey Avseyev     }
2989c0ab8aaSSergey Avseyev 
2996a82bf9aSMark Nunberg     lcbdurctx_set_durstore(mctx, 1);
3002d8ee3cdSSergey Avseyev     err = mctx->add_endure(mctx, &dcmd);
3016a82bf9aSMark Nunberg     if (err != LCB_SUCCESS) {
3026a82bf9aSMark Nunberg         mctx->fail(mctx);
3036a82bf9aSMark Nunberg         goto GT_BAIL;
3046a82bf9aSMark Nunberg     }
3056a82bf9aSMark Nunberg     lcb_sched_enter(dctx->instance);
3066a82bf9aSMark Nunberg     err = mctx->done(mctx, sresp->cookie);
3076a82bf9aSMark Nunberg     lcb_sched_leave(dctx->instance);
3086a82bf9aSMark Nunberg 
3096a82bf9aSMark Nunberg     if (err == LCB_SUCCESS) {
3106a82bf9aSMark Nunberg         /* Everything OK? */
3116a82bf9aSMark Nunberg         delete dctx;
3126a82bf9aSMark Nunberg         return;
3136a82bf9aSMark Nunberg     }
3146a82bf9aSMark Nunberg 
315fa499e8aSSergey Avseyev GT_BAIL : {
3166ae99e49SSergey Avseyev     lcb_RESPENDURE dresp{};
3176ae99e49SSergey Avseyev     resp.ctx.key = sresp->ctx.key;
3186a82bf9aSMark Nunberg     resp.cookie = sresp->cookie;
3196ae99e49SSergey Avseyev     resp.ctx.rc = err;
3206a82bf9aSMark Nunberg     resp.dur_resp = &dresp;
32107521d60SSergey Avseyev     cb = lcb_find_callback(dctx->instance, LCB_CALLBACK_STORE);
32207521d60SSergey Avseyev     cb(dctx->instance, LCB_CALLBACK_STORE, (const lcb_RESPBASE *)&resp);
3236a82bf9aSMark Nunberg     delete dctx;
3246a82bf9aSMark Nunberg }
3256a82bf9aSMark Nunberg }
3266a82bf9aSMark Nunberg 
handle_dur_schedfail(mc_PACKET * pkt)327fa499e8aSSergey Avseyev static void handle_dur_schedfail(mc_PACKET *pkt)
328fa499e8aSSergey Avseyev {
3296a82bf9aSMark Nunberg     delete static_cast<DurStoreCtx *>(pkt->u_rdata.exdata);
3306a82bf9aSMark Nunberg }
3316a82bf9aSMark Nunberg 
332fa499e8aSSergey Avseyev mc_REQDATAPROCS DurStoreCtx::proctable = {handle_dur_storecb, handle_dur_schedfail};
3336a82bf9aSMark Nunberg 
get_value_size(const mc_PACKET * packet)3343280c1b9SSergey Avseyev static lcb_size_t get_value_size(const mc_PACKET *packet)
3356a82bf9aSMark Nunberg {
3366a82bf9aSMark Nunberg     if (packet->flags & MCREQ_F_VALUE_IOV) {
3376a82bf9aSMark Nunberg         return packet->u_value.multi.total_length;
3386a82bf9aSMark Nunberg     } else {
3396a82bf9aSMark Nunberg         return packet->u_value.single.size;
3406a82bf9aSMark Nunberg     }
3416a82bf9aSMark Nunberg }
3426a82bf9aSMark Nunberg 
can_compress(lcb_INSTANCE * instance,const mc_PIPELINE * pipeline,bool already_compressed)3433280c1b9SSergey Avseyev static bool can_compress(lcb_INSTANCE *instance, const mc_PIPELINE *pipeline, bool already_compressed)
3446a82bf9aSMark Nunberg {
3453280c1b9SSergey Avseyev     if (already_compressed) {
3463280c1b9SSergey Avseyev         return false;
3476a82bf9aSMark Nunberg     }
3486a82bf9aSMark Nunberg 
3493280c1b9SSergey Avseyev     const auto *server = static_cast<const lcb::Server *>(pipeline);
350ebf3e5c1SSergey Avseyev     uint8_t compressopts = LCBT_SETTING(instance, compressopts);
3516a82bf9aSMark Nunberg 
3526a82bf9aSMark Nunberg     if ((compressopts & LCB_COMPRESS_OUT) == 0) {
3533280c1b9SSergey Avseyev         return false;
3546a82bf9aSMark Nunberg     }
355fa499e8aSSergey Avseyev     if (server->supports_compression() == false && (compressopts & LCB_COMPRESS_FORCE) == 0) {
3563280c1b9SSergey Avseyev         return false;
3576a82bf9aSMark Nunberg     }
3583280c1b9SSergey Avseyev     return true;
3596a82bf9aSMark Nunberg }
3606a82bf9aSMark Nunberg 
store_validate(lcb_INSTANCE * instance,const lcb_CMDSTORE * cmd)361ebf3e5c1SSergey Avseyev static lcb_STATUS store_validate(lcb_INSTANCE *instance, const lcb_CMDSTORE *cmd)
3626a82bf9aSMark Nunberg {
3633280c1b9SSergey Avseyev     if (cmd->key().empty()) {
364ebf3e5c1SSergey Avseyev         return LCB_ERR_EMPTY_KEY;
365ebf3e5c1SSergey Avseyev     }
3663280c1b9SSergey Avseyev     if (!LCBT_SETTING(instance, use_collections) && !cmd->collection().is_default_collection()) {
3673280c1b9SSergey Avseyev         /* only allow default collection when collections disabled for the instance */
3683280c1b9SSergey Avseyev         return LCB_ERR_SDK_FEATURE_UNAVAILABLE;
3693280c1b9SSergey Avseyev     }
3703280c1b9SSergey Avseyev     if (!LCBT_SETTING(instance, enable_durable_write) && cmd->has_sync_durability_requirements()) {
371ebf3e5c1SSergey Avseyev         return LCB_ERR_UNSUPPORTED_OPERATION;
372ebf3e5c1SSergey Avseyev     }
373ebf3e5c1SSergey Avseyev 
374ebf3e5c1SSergey Avseyev     return LCB_SUCCESS;
375ebf3e5c1SSergey Avseyev }
376ebf3e5c1SSergey Avseyev 
store_schedule(lcb_INSTANCE * instance,std::shared_ptr<lcb_CMDSTORE> cmd)3773280c1b9SSergey Avseyev static lcb_STATUS store_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CMDSTORE> cmd)
378ebf3e5c1SSergey Avseyev {
37907521d60SSergey Avseyev     lcb_STATUS err;
38007521d60SSergey Avseyev 
3816a82bf9aSMark Nunberg     mc_PIPELINE *pipeline;
3826a82bf9aSMark Nunberg     mc_PACKET *packet;
3836a82bf9aSMark Nunberg     mc_CMDQUEUE *cq = &instance->cmdq;
384f1ce7ef8SSergey Avseyev     protocol_binary_request_header hdr{};
38507521d60SSergey Avseyev     int new_durability_supported = LCBT_SUPPORT_SYNCREPLICATION(instance);
3866a82bf9aSMark Nunberg 
387f1ce7ef8SSergey Avseyev     std::vector<std::uint8_t> framing_extras;
3883280c1b9SSergey Avseyev     if (new_durability_supported && cmd->has_sync_durability_requirements()) {
389324cddd6SSergey Avseyev         auto durability_timeout = htons(lcb_durability_timeout(instance, cmd->timeout_in_microseconds()));
390f1ce7ef8SSergey Avseyev         std::uint8_t frame_id = 0x01;
391324cddd6SSergey Avseyev         std::uint8_t frame_size = durability_timeout > 0 ? 3 : 1;
392f1ce7ef8SSergey Avseyev         framing_extras.emplace_back(frame_id << 4U | frame_size);
393f1ce7ef8SSergey Avseyev         framing_extras.emplace_back(cmd->durability_level());
394324cddd6SSergey Avseyev         if (durability_timeout > 0) {
395f1ce7ef8SSergey Avseyev             framing_extras.emplace_back(durability_timeout >> 8U);
396f1ce7ef8SSergey Avseyev             framing_extras.emplace_back(durability_timeout & 0xff);
3976a82bf9aSMark Nunberg         }
398324cddd6SSergey Avseyev     }
399f1ce7ef8SSergey Avseyev     if (cmd->should_preserve_expiry()) {
400f1ce7ef8SSergey Avseyev         std::uint8_t frame_id = 0x05;
401f1ce7ef8SSergey Avseyev         std::uint8_t frame_size = 0x00;
402f1ce7ef8SSergey Avseyev         framing_extras.emplace_back(frame_id << 4U | frame_size);
403f1ce7ef8SSergey Avseyev     }
404ecbde082SSergey Avseyev     if (cmd->want_impersonation()) {
405ecbde082SSergey Avseyev         err = lcb::flexible_framing_extras::encode_impersonate_user(cmd->impostor(), framing_extras);
406ecbde082SSergey Avseyev         if (err != LCB_SUCCESS) {
407ecbde082SSergey Avseyev             return err;
408ecbde082SSergey Avseyev         }
409*f6822fccSSergey Avseyev         for (const auto &privilege : cmd->extra_privileges()) {
410*f6822fccSSergey Avseyev             err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
411*f6822fccSSergey Avseyev             if (err != LCB_SUCCESS) {
412*f6822fccSSergey Avseyev                 return err;
413*f6822fccSSergey Avseyev             }
414*f6822fccSSergey Avseyev         }
415ecbde082SSergey Avseyev     }
416f1ce7ef8SSergey Avseyev     auto ffextlen = static_cast<std::uint8_t>(framing_extras.size());
417f1ce7ef8SSergey Avseyev     hdr.request.magic = (ffextlen == 0) ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
418f1ce7ef8SSergey Avseyev     hdr.request.opcode = cmd->opcode();
419f1ce7ef8SSergey Avseyev     hdr.request.extlen = cmd->extras_size();
4203280c1b9SSergey Avseyev     lcb_KEYBUF keybuf{LCB_KV_COPY, {cmd->key().c_str(), cmd->key().size()}};
421f1ce7ef8SSergey Avseyev     err = mcreq_basic_packet(cq, &keybuf, cmd->collection().collection_id(), &hdr, hdr.request.extlen, ffextlen,
4223280c1b9SSergey Avseyev                              &packet, &pipeline, MCREQ_BASICPACKET_F_FALLBACKOK);
4236a82bf9aSMark Nunberg     if (err != LCB_SUCCESS) {
4246a82bf9aSMark Nunberg         return err;
4256a82bf9aSMark Nunberg     }
4266a82bf9aSMark Nunberg 
427f1ce7ef8SSergey Avseyev     int should_compress = can_compress(instance, pipeline, cmd->value_is_compressed());
4283280c1b9SSergey Avseyev     lcb_VALBUF valuebuf{LCB_KV_COPY, {{cmd->value().c_str(), cmd->value().size()}}};
4296a82bf9aSMark Nunberg     if (should_compress) {
4303280c1b9SSergey Avseyev         int rv = mcreq_compress_value(pipeline, packet, &valuebuf, instance->settings, &should_compress);
4316a82bf9aSMark Nunberg         if (rv != 0) {
4326a82bf9aSMark Nunberg             mcreq_release_packet(pipeline, packet);
433d0533ef7SSergey Avseyev             return LCB_ERR_NO_MEMORY;
4346a82bf9aSMark Nunberg         }
4356a82bf9aSMark Nunberg     } else {
4363280c1b9SSergey Avseyev         mcreq_reserve_value(pipeline, packet, &valuebuf);
4376a82bf9aSMark Nunberg     }
4386a82bf9aSMark Nunberg 
4393280c1b9SSergey Avseyev     if (cmd->need_poll_durability()) {
4406a82bf9aSMark Nunberg         int duropts = 0;
4413280c1b9SSergey Avseyev         std::uint16_t persist_to = cmd->persist_to();
4423280c1b9SSergey Avseyev         std::uint16_t replicate_to = cmd->replicate_to();
4433280c1b9SSergey Avseyev         if (cmd->cap_to_maximum_nodes()) {
4446a82bf9aSMark Nunberg             duropts = LCB_DURABILITY_VALIDATE_CAPMAX;
4456a82bf9aSMark Nunberg         }
4463280c1b9SSergey Avseyev         err = lcb_durability_validate(instance, &persist_to, &replicate_to, duropts);
4476a82bf9aSMark Nunberg         if (err != LCB_SUCCESS) {
4486a82bf9aSMark Nunberg             mcreq_wipe_packet(pipeline, packet);
4496a82bf9aSMark Nunberg             mcreq_release_packet(pipeline, packet);
4506a82bf9aSMark Nunberg             return err;
4516a82bf9aSMark Nunberg         }
4526a82bf9aSMark Nunberg 
4533280c1b9SSergey Avseyev         auto *dctx = new DurStoreCtx(instance, persist_to, replicate_to, cmd->cookie());
4546a82bf9aSMark Nunberg         packet->u_rdata.exdata = dctx;
4556a82bf9aSMark Nunberg         packet->flags |= MCREQ_F_REQEXT;
456f1ce7ef8SSergey Avseyev     }
457fc4d2500SMark Nunberg     mc_REQDATA *rdata = MCREQ_PKT_RDATA(packet);
4583280c1b9SSergey Avseyev     rdata->cookie = cmd->cookie();
4593280c1b9SSergey Avseyev     rdata->start = cmd->start_time_or_default_in_nanoseconds(gethrtime());
460ebf3e5c1SSergey Avseyev     rdata->deadline =
4613280c1b9SSergey Avseyev         rdata->start + cmd->timeout_or_default_in_nanoseconds(LCB_US2NS(LCBT_SETTING(instance, operation_timeout)));
4626a82bf9aSMark Nunberg 
463f1ce7ef8SSergey Avseyev     hdr.request.cas = lcb_htonll(cmd->cas());
464f1ce7ef8SSergey Avseyev     hdr.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
4653280c1b9SSergey Avseyev     if (should_compress || cmd->value_is_compressed()) {
466f1ce7ef8SSergey Avseyev         hdr.request.datatype |= PROTOCOL_BINARY_DATATYPE_COMPRESSED;
4676a82bf9aSMark Nunberg     }
46814b02d2eSSergey Avseyev 
4693280c1b9SSergey Avseyev     if (cmd->value_is_json() && static_cast<const lcb::Server *>(pipeline)->supports_json()) {
470f1ce7ef8SSergey Avseyev         hdr.request.datatype |= PROTOCOL_BINARY_DATATYPE_JSON;
4716a82bf9aSMark Nunberg     }
4726a82bf9aSMark Nunberg 
473f1ce7ef8SSergey Avseyev     hdr.request.opaque = packet->opaque;
474f1ce7ef8SSergey Avseyev     hdr.request.bodylen = htonl(hdr.request.extlen + ffextlen + mcreq_get_key_size(&hdr) + get_value_size(packet));
4756a82bf9aSMark Nunberg 
4763280c1b9SSergey Avseyev     if (cmd->is_cookie_callback()) {
47737f0716aSSergey Avseyev         packet->flags |= MCREQ_F_PRIVCALLBACK;
47837f0716aSSergey Avseyev     }
479f1ce7ef8SSergey Avseyev 
480f1ce7ef8SSergey Avseyev     memcpy(SPAN_BUFFER(&packet->kh_span), &hdr, sizeof(hdr));
481f1ce7ef8SSergey Avseyev 
482f1ce7ef8SSergey Avseyev     std::size_t offset = sizeof(hdr);
483f1ce7ef8SSergey Avseyev     if (!framing_extras.empty()) {
484f1ce7ef8SSergey Avseyev         memcpy(SPAN_BUFFER(&packet->kh_span) + offset, framing_extras.data(), framing_extras.size());
485f1ce7ef8SSergey Avseyev         offset += framing_extras.size();
486f1ce7ef8SSergey Avseyev     }
487f1ce7ef8SSergey Avseyev 
488f1ce7ef8SSergey Avseyev     if (hdr.request.extlen == 2 * sizeof(std::uint32_t)) {
489f1ce7ef8SSergey Avseyev         std::uint32_t flags = htonl(cmd->flags());
490f1ce7ef8SSergey Avseyev         memcpy(SPAN_BUFFER(&packet->kh_span) + offset, &flags, sizeof(flags));
491f1ce7ef8SSergey Avseyev         offset += sizeof(flags);
492f1ce7ef8SSergey Avseyev 
493f1ce7ef8SSergey Avseyev         std::uint32_t expiry = htonl(cmd->expiry());
494f1ce7ef8SSergey Avseyev         memcpy(SPAN_BUFFER(&packet->kh_span) + offset, &expiry, sizeof(expiry));
495f1ce7ef8SSergey Avseyev     }
496f1ce7ef8SSergey Avseyev 
4973280c1b9SSergey Avseyev     if (cmd->is_replace_semantics()) {
4984cec4c60SSergey Avseyev         packet->flags |= MCREQ_F_REPLACE_SEMANTICS;
4994cec4c60SSergey Avseyev     }
500d57e4ccdSSergey Avseyev     rdata->span = lcb::trace::start_kv_span_with_durability(instance->settings, packet, cmd);
5014cec4c60SSergey Avseyev     LCB_SCHED_ADD(instance, pipeline, packet)
5023280c1b9SSergey Avseyev 
503f1ce7ef8SSergey Avseyev     TRACE_STORE_BEGIN(instance, &hdr, cmd);
50407521d60SSergey Avseyev 
5056a82bf9aSMark Nunberg     return LCB_SUCCESS;
5063280c1b9SSergey Avseyev }
507ebf3e5c1SSergey Avseyev 
store_execute(lcb_INSTANCE * instance,std::shared_ptr<lcb_CMDSTORE> cmd)5083280c1b9SSergey Avseyev static lcb_STATUS store_execute(lcb_INSTANCE *instance, std::shared_ptr<lcb_CMDSTORE> cmd)
5093280c1b9SSergey Avseyev {
510ebf3e5c1SSergey Avseyev     if (!LCBT_SETTING(instance, use_collections)) {
511ebf3e5c1SSergey Avseyev         /* fast path if collections are not enabled */
5123280c1b9SSergey Avseyev         return store_schedule(instance, cmd);
5136a82bf9aSMark Nunberg     }
5146a82bf9aSMark Nunberg 
5153280c1b9SSergey Avseyev     if (collcache_get(instance, cmd->collection()) == LCB_SUCCESS) {
5163280c1b9SSergey Avseyev         return store_schedule(instance, cmd);
5176a82bf9aSMark Nunberg     }
5183280c1b9SSergey Avseyev 
5193280c1b9SSergey Avseyev     return collcache_resolve(
5203280c1b9SSergey Avseyev         instance, cmd,
5213280c1b9SSergey Avseyev         [instance](lcb_STATUS status, const lcb_RESPGETCID *resp, std::shared_ptr<lcb_CMDSTORE> operation) {
5223280c1b9SSergey Avseyev             const auto callback_type = LCB_CALLBACK_STORE;
5233280c1b9SSergey Avseyev             lcb_RESPCALLBACK operation_callback = lcb_find_callback(instance, callback_type);
5243280c1b9SSergey Avseyev             lcb_RESPSTORE response{};
525073fa912SSergey Avseyev             if (resp != nullptr) {
526073fa912SSergey Avseyev                 response.ctx = resp->ctx;
527073fa912SSergey Avseyev             }
5283280c1b9SSergey Avseyev             response.ctx.key = operation->key();
529073fa912SSergey Avseyev             response.ctx.scope = operation->collection().scope();
530073fa912SSergey Avseyev             response.ctx.collection = operation->collection().collection();
5313280c1b9SSergey Avseyev             response.cookie = operation->cookie();
5323280c1b9SSergey Avseyev             if (status == LCB_ERR_SHEDULE_FAILURE || resp == nullptr) {
5333280c1b9SSergey Avseyev                 response.ctx.rc = LCB_ERR_TIMEOUT;
5343280c1b9SSergey Avseyev                 operation_callback(instance, callback_type, &response);
5353280c1b9SSergey Avseyev                 return;
5363280c1b9SSergey Avseyev             }
5373280c1b9SSergey Avseyev             if (resp->ctx.rc != LCB_SUCCESS) {
5383280c1b9SSergey Avseyev                 operation_callback(instance, callback_type, &response);
5393280c1b9SSergey Avseyev                 return;
5403280c1b9SSergey Avseyev             }
5413280c1b9SSergey Avseyev             response.ctx.rc = store_schedule(instance, operation);
5423280c1b9SSergey Avseyev             if (response.ctx.rc != LCB_SUCCESS) {
5433280c1b9SSergey Avseyev                 operation_callback(instance, callback_type, &response);
5443280c1b9SSergey Avseyev             }
5453280c1b9SSergey Avseyev         });
5463280c1b9SSergey Avseyev }
5473280c1b9SSergey Avseyev 
lcb_store(lcb_INSTANCE * instance,void * cookie,const lcb_CMDSTORE * command)5483280c1b9SSergey Avseyev LIBCOUCHBASE_API lcb_STATUS lcb_store(lcb_INSTANCE *instance, void *cookie, const lcb_CMDSTORE *command)
5493280c1b9SSergey Avseyev {
5503280c1b9SSergey Avseyev     lcb_STATUS rc;
5513280c1b9SSergey Avseyev 
5523280c1b9SSergey Avseyev     rc = store_validate(instance, command);
5533280c1b9SSergey Avseyev     if (rc != LCB_SUCCESS) {
5543280c1b9SSergey Avseyev         return rc;
5553280c1b9SSergey Avseyev     }
5563280c1b9SSergey Avseyev 
5573280c1b9SSergey Avseyev     auto cmd = std::make_shared<lcb_CMDSTORE>(*command);
5583280c1b9SSergey Avseyev     cmd->cookie(cookie);
5593280c1b9SSergey Avseyev 
5603280c1b9SSergey Avseyev     if (instance->cmdq.config == nullptr) {
5613280c1b9SSergey Avseyev         cmd->start_time_in_nanoseconds(gethrtime());
5623280c1b9SSergey Avseyev         return lcb::defer_operation(instance, [instance, cmd](lcb_STATUS status) {
5633280c1b9SSergey Avseyev             const auto callback_type = LCB_CALLBACK_STORE;
5643280c1b9SSergey Avseyev             lcb_RESPCALLBACK operation_callback = lcb_find_callback(instance, callback_type);
5653280c1b9SSergey Avseyev             lcb_RESPSTORE response{};
5663280c1b9SSergey Avseyev             response.ctx.key = cmd->key();
5673280c1b9SSergey Avseyev             response.cookie = cmd->cookie();
5683280c1b9SSergey Avseyev             if (status == LCB_ERR_REQUEST_CANCELED) {
5693280c1b9SSergey Avseyev                 response.ctx.rc = status;
5703280c1b9SSergey Avseyev                 operation_callback(instance, callback_type, &response);
5713280c1b9SSergey Avseyev                 return;
5723280c1b9SSergey Avseyev             }
5733280c1b9SSergey Avseyev             response.ctx.rc = store_execute(instance, cmd);
5743280c1b9SSergey Avseyev             if (response.ctx.rc != LCB_SUCCESS) {
5753280c1b9SSergey Avseyev                 operation_callback(instance, callback_type, &response);
5763280c1b9SSergey Avseyev             }
5773280c1b9SSergey Avseyev         });
5783280c1b9SSergey Avseyev     }
5793280c1b9SSergey Avseyev     return store_execute(instance, cmd);
5806a82bf9aSMark Nunberg }
581