couchbase 3.2.0 → 3.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. package/README.md +24 -18
  2. package/binding.gyp +88 -85
  3. package/deps/lcb/CMakeLists.txt +1 -1
  4. package/deps/lcb/CONTRIBUTING.md +1 -1
  5. package/deps/lcb/README.markdown +2 -2
  6. package/deps/lcb/RELEASE_NOTES.markdown +99 -14
  7. package/deps/lcb/cmake/Modules/GetVersionInfo.cmake +1 -1
  8. package/deps/lcb/contrib/cbsasl/src/scram-sha/scram_utils.cc +22 -26
  9. package/deps/lcb/contrib/lcb-jsoncpp/lcb-jsoncpp.cpp +20 -7
  10. package/deps/lcb/doc/Doxyfile +1 -1
  11. package/deps/lcb/example/CMakeLists.txt +4 -4
  12. package/deps/lcb/example/libuvdirect/main.c +39 -12
  13. package/deps/lcb/example/minimal/durability.cc +149 -0
  14. package/deps/lcb/example/minimal/query.c +11 -9
  15. package/deps/lcb/gyp_config/common/libcouchbase/configuration.h +3 -3
  16. package/deps/lcb/gyp_config/linux/arm64/config.h +243 -0
  17. package/deps/lcb/include/libcouchbase/couchbase.h +80 -5
  18. package/deps/lcb/include/libcouchbase/error.h +2 -0
  19. package/deps/lcb/include/libcouchbase/ixmgmt.h +15 -10
  20. package/deps/lcb/include/libcouchbase/tracing.h +2 -2
  21. package/deps/lcb/include/memcached/protocol_binary.h +21 -0
  22. package/deps/lcb/libcouchbase.gyp +347 -349
  23. package/deps/lcb/packaging/deb/control +1 -1
  24. package/deps/lcb/src/analytics/analytics_handle.cc +13 -5
  25. package/deps/lcb/src/analytics/analytics_handle.hh +29 -0
  26. package/deps/lcb/src/bootstrap.cc +6 -3
  27. package/deps/lcb/src/capi/cmd_analytics.cc +12 -1
  28. package/deps/lcb/src/capi/cmd_analytics.hh +30 -0
  29. package/deps/lcb/src/capi/cmd_counter.hh +23 -0
  30. package/deps/lcb/src/capi/cmd_exists.hh +24 -1
  31. package/deps/lcb/src/capi/cmd_get.hh +22 -0
  32. package/deps/lcb/src/capi/cmd_get_replica.hh +23 -0
  33. package/deps/lcb/src/capi/cmd_http.hh +7 -0
  34. package/deps/lcb/src/capi/cmd_query.cc +11 -1
  35. package/deps/lcb/src/capi/cmd_query.hh +31 -0
  36. package/deps/lcb/src/capi/cmd_remove.hh +23 -0
  37. package/deps/lcb/src/capi/cmd_search.cc +6 -0
  38. package/deps/lcb/src/capi/cmd_search.hh +23 -0
  39. package/deps/lcb/src/capi/cmd_store.hh +33 -21
  40. package/deps/lcb/src/capi/cmd_subdoc.hh +35 -0
  41. package/deps/lcb/src/capi/cmd_touch.hh +23 -0
  42. package/deps/lcb/src/capi/cmd_unlock.hh +23 -0
  43. package/deps/lcb/src/capi/cmd_view.hh +6 -0
  44. package/deps/lcb/src/capi/collection_qualifier.hh +2 -2
  45. package/deps/lcb/src/cntl.cc +45 -11
  46. package/deps/lcb/src/crypto.cc +2 -2
  47. package/deps/lcb/src/dns-srv.cc +5 -3
  48. package/deps/lcb/src/errmap.cc +5 -9
  49. package/deps/lcb/src/errmap.h +7 -3
  50. package/deps/lcb/src/handler.cc +24 -18
  51. package/deps/lcb/src/hostlist.h +2 -2
  52. package/deps/lcb/src/http/http-priv.h +2 -2
  53. package/deps/lcb/src/http/http.cc +5 -2
  54. package/deps/lcb/src/instance.cc +20 -11
  55. package/deps/lcb/src/internal.h +9 -0
  56. package/deps/lcb/src/lcbio/connect.cc +14 -2
  57. package/deps/lcb/src/lcbio/connect.h +2 -2
  58. package/deps/lcb/src/lcbio/ctx.cc +4 -2
  59. package/deps/lcb/src/lcbio/ioutils.cc +9 -10
  60. package/deps/lcb/src/lcbio/manager.cc +1 -1
  61. package/deps/lcb/src/mcserver/mcserver.cc +9 -6
  62. package/deps/lcb/src/mcserver/negotiate.cc +39 -17
  63. package/deps/lcb/src/n1ql/ixmgmt.cc +1 -2
  64. package/deps/lcb/src/n1ql/query_handle.cc +41 -19
  65. package/deps/lcb/src/n1ql/query_handle.hh +28 -1
  66. package/deps/lcb/src/operations/counter.cc +18 -5
  67. package/deps/lcb/src/operations/exists.cc +25 -4
  68. package/deps/lcb/src/operations/get.cc +39 -19
  69. package/deps/lcb/src/operations/get_replica.cc +28 -8
  70. package/deps/lcb/src/operations/observe.cc +1 -1
  71. package/deps/lcb/src/operations/ping.cc +8 -8
  72. package/deps/lcb/src/operations/pktfwd.cc +2 -1
  73. package/deps/lcb/src/operations/remove.cc +39 -22
  74. package/deps/lcb/src/operations/store.cc +18 -5
  75. package/deps/lcb/src/operations/subdoc.cc +18 -6
  76. package/deps/lcb/src/operations/touch.cc +34 -16
  77. package/deps/lcb/src/operations/unlock.cc +24 -5
  78. package/deps/lcb/src/packetutils.h +3 -2
  79. package/deps/lcb/src/retryq.cc +24 -5
  80. package/deps/lcb/src/search/search.cc +1 -0
  81. package/deps/lcb/src/search/search_handle.cc +30 -8
  82. package/deps/lcb/src/search/search_handle.hh +29 -0
  83. package/deps/lcb/src/settings.cc +1 -1
  84. package/deps/lcb/src/ssl/ssl_common.c +6 -7
  85. package/deps/lcb/src/tracing/span.cc +47 -14
  86. package/deps/lcb/src/tracing/tracer.cc +11 -2
  87. package/deps/lcb/src/tracing/tracing-internal.h +105 -93
  88. package/deps/lcb/src/utilities.cc +43 -0
  89. package/deps/lcb/src/utilities.h +53 -0
  90. package/deps/lcb/src/vbucket/vbucket.c +34 -33
  91. package/deps/lcb/src/views/view_handle.cc +13 -5
  92. package/deps/lcb/src/views/view_handle.hh +29 -0
  93. package/deps/lcb/tests/CMakeLists.txt +21 -0
  94. package/deps/lcb/tests/basic/t_ctlcodes.cc +24 -3
  95. package/deps/lcb/tests/basic/t_jsparse.cc +8 -0
  96. package/deps/lcb/tests/basic/t_n1qlstrings.cc +73 -0
  97. package/deps/lcb/tests/iotests/mock-environment.cc +30 -1
  98. package/deps/lcb/tests/iotests/mock-environment.h +49 -0
  99. package/deps/lcb/tests/iotests/mock-unit-test.cc +104 -6
  100. package/deps/lcb/tests/iotests/mock-unit-test.h +34 -0
  101. package/deps/lcb/tests/iotests/t_collections.cc +1 -1
  102. package/deps/lcb/tests/iotests/t_confmon.cc +4 -2
  103. package/deps/lcb/tests/iotests/t_get.cc +109 -7
  104. package/deps/lcb/tests/iotests/t_http.cc +9 -4
  105. package/deps/lcb/tests/iotests/t_lock.cc +18 -0
  106. package/deps/lcb/tests/iotests/t_mutate.cc +157 -63
  107. package/deps/lcb/tests/iotests/t_n1ql.cc +330 -33
  108. package/deps/lcb/tests/iotests/t_views.cc +1 -0
  109. package/deps/lcb/tests/iotests/testutil.cc +168 -0
  110. package/deps/lcb/tests/iotests/testutil.h +116 -0
  111. package/deps/lcb/tests/mocksupport/procutil.c +32 -28
  112. package/deps/lcb/tests/mocksupport/server.c +0 -1
  113. package/deps/lcb/tests/mocksupport/timeout.c +2 -2
  114. package/deps/lcb/tools/cbc.cc +7 -0
  115. package/dist/analyticsindexmanager.js +512 -524
  116. package/dist/binding.d.ts +3 -0
  117. package/dist/bindingutilities.js +4 -0
  118. package/dist/bucket.js +1 -1
  119. package/dist/bucketmanager.d.ts +31 -1
  120. package/dist/bucketmanager.js +194 -186
  121. package/dist/cluster.d.ts +7 -0
  122. package/dist/cluster.js +48 -38
  123. package/dist/collection.js +11 -17
  124. package/dist/collectionmanager.js +181 -197
  125. package/dist/connection.d.ts +3 -1
  126. package/dist/connection.js +27 -16
  127. package/dist/couchbase.d.ts +1 -0
  128. package/dist/couchbase.js +3 -13
  129. package/dist/datastructures.js +239 -310
  130. package/dist/diagnosticsexecutor.js +70 -85
  131. package/dist/errors.d.ts +70 -0
  132. package/dist/errors.js +96 -2
  133. package/dist/eventingfunctionmanager.d.ts +804 -0
  134. package/dist/eventingfunctionmanager.js +993 -0
  135. package/dist/httpexecutor.d.ts +2 -1
  136. package/dist/httpexecutor.js +30 -37
  137. package/dist/queryindexmanager.js +240 -266
  138. package/dist/scope.js +10 -4
  139. package/dist/sdspecs.d.ts +1 -1
  140. package/dist/searchexecutor.js +3 -0
  141. package/dist/searchindexmanager.js +240 -271
  142. package/dist/searchquery.d.ts +17 -0
  143. package/dist/searchquery.js +22 -1
  144. package/dist/searchtypes.d.ts +7 -2
  145. package/dist/searchtypes.js +2 -2
  146. package/dist/usermanager.js +251 -264
  147. package/dist/utilities.d.ts +2 -0
  148. package/dist/utilities.js +7 -2
  149. package/dist/viewexecutor.js +1 -1
  150. package/dist/viewindexmanager.js +131 -150
  151. package/package.json +1 -1
  152. package/src/addondata.cpp +58 -0
  153. package/src/addondata.h +40 -0
  154. package/src/binding.cpp +3 -1
  155. package/src/cas.h +2 -2
  156. package/src/connection.cpp +25 -178
  157. package/src/connection.h +8 -65
  158. package/src/connection_ops.cpp +57 -34
  159. package/src/constants.cpp +3 -0
  160. package/src/instance.cpp +235 -0
  161. package/src/instance.h +102 -0
  162. package/src/{connection_callbacks.cpp → instance_callbacks.cpp} +34 -34
  163. package/src/logger.cpp +11 -1
  164. package/src/logger.h +3 -0
  165. package/src/metrics.cpp +10 -0
  166. package/src/metrics.h +3 -0
  167. package/src/mutationtoken.h +2 -2
  168. package/src/opbuilder.h +13 -15
  169. package/src/respreader.cpp +1 -0
  170. package/src/respreader.h +6 -4
  171. package/src/tracespan.h +11 -11
  172. package/src/tracing.cpp +11 -0
  173. package/src/tracing.h +3 -0
  174. package/src/valueparser.h +5 -0
  175. package/deps/lcb/example/observe/durability.c +0 -110
@@ -19,7 +19,6 @@
19
19
 
20
20
  #include "internal.h"
21
21
  #include "collections.h"
22
- #include "trace.h"
23
22
  #include "defer.h"
24
23
 
25
24
  #include "capi/cmd_get.hh"
@@ -140,6 +139,11 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdgetreplica_key(lcb_CMDGETREPLICA *cmd, const
140
139
  return cmd->key(std::string(key, key_len));
141
140
  }
142
141
 
142
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdgetreplica_on_behalf_of(lcb_CMDGETREPLICA *cmd, const char *data, size_t data_len)
143
+ {
144
+ return cmd->on_behalf_of(std::string(data, data_len));
145
+ }
146
+
143
147
  struct RGetCookie : mc_REQDATAEX {
144
148
  RGetCookie(void *cookie, lcb_INSTANCE *instance, get_replica_mode, int vb);
145
149
  void decref()
@@ -248,7 +252,7 @@ static lcb_STATUS get_replica_validate(lcb_INSTANCE *instance, const lcb_CMDGETR
248
252
 
249
253
  mc_CMDQUEUE *cq = &instance->cmdq;
250
254
  int vbid, ixtmp;
251
- unsigned r0, r1 = 0;
255
+ unsigned r0 = 0, r1 = 0;
252
256
 
253
257
  lcb_KEYBUF keybuf{LCB_KV_COPY, {cmd->key().c_str(), cmd->key().size()}};
254
258
  mcreq_map_key(cq, &keybuf, MCREQ_PKT_BASESIZE, &vbid, &ixtmp);
@@ -299,8 +303,8 @@ static lcb_STATUS get_replica_schedule(lcb_INSTANCE *instance, std::shared_ptr<l
299
303
  */
300
304
  mc_CMDQUEUE *cq = &instance->cmdq;
301
305
  int vbid, ixtmp;
302
- protocol_binary_request_header req;
303
- unsigned r0, r1 = 0;
306
+ protocol_binary_request_header req{};
307
+ unsigned r0 = 0, r1 = 0;
304
308
 
305
309
  lcb_KEYBUF keybuf{LCB_KV_COPY, {cmd->key().c_str(), cmd->key().size()}};
306
310
  mcreq_map_key(cq, &keybuf, MCREQ_PKT_BASESIZE, &vbid, &ixtmp);
@@ -351,14 +355,24 @@ static lcb_STATUS get_replica_schedule(lcb_INSTANCE *instance, std::shared_ptr<l
351
355
  rck->deadline =
352
356
  rck->start + cmd->timeout_or_default_in_nanoseconds(LCB_US2NS(LCBT_SETTING(instance, operation_timeout)));
353
357
 
358
+ std::vector<std::uint8_t> framing_extras;
359
+ if (cmd->want_impersonation()) {
360
+ lcb_STATUS err = lcb::flexible_framing_extras::encode_impersonate_user(cmd->impostor(), framing_extras);
361
+ if (err != LCB_SUCCESS) {
362
+ return err;
363
+ }
364
+ }
365
+
354
366
  /* Initialize the packet */
355
- req.request.magic = PROTOCOL_BINARY_REQ;
367
+ req.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
356
368
  req.request.opcode = PROTOCOL_BINARY_CMD_GET_REPLICA;
357
369
  req.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
358
370
  req.request.vbucket = htons(static_cast<std::uint16_t>(vbid));
359
371
  req.request.cas = 0;
360
372
  req.request.extlen = 0;
361
373
 
374
+ auto ffextlen = static_cast<std::uint8_t>(framing_extras.size());
375
+
362
376
  rck->r_cur = r0;
363
377
  do {
364
378
  int curix;
@@ -380,13 +394,16 @@ static lcb_STATUS get_replica_schedule(lcb_INSTANCE *instance, std::shared_ptr<l
380
394
  pkt->u_rdata.exdata = rck;
381
395
  pkt->flags |= MCREQ_F_REQEXT;
382
396
 
383
- mcreq_reserve_key(pl, pkt, sizeof(req.bytes), &keybuf, cmd->collection().collection_id());
397
+ mcreq_reserve_key(pl, pkt, sizeof(req.bytes) + ffextlen, &keybuf, cmd->collection().collection_id());
384
398
  size_t nkey = pkt->kh_span.size - MCREQ_PKT_BASESIZE + pkt->extlen;
385
399
  req.request.keylen = htons((uint16_t)nkey);
386
400
  req.request.bodylen = htonl((uint32_t)nkey);
387
401
  req.request.opaque = pkt->opaque;
388
402
  rck->remaining++;
389
403
  mcreq_write_hdr(pkt, &req);
404
+ if (!framing_extras.empty()) {
405
+ memcpy(SPAN_BUFFER(&pkt->kh_span) + sizeof(req.bytes), framing_extras.data(), framing_extras.size());
406
+ }
390
407
  mcreq_sched_add(pl, pkt);
391
408
  } while (++r0 < r1);
392
409
 
@@ -394,8 +411,8 @@ static lcb_STATUS get_replica_schedule(lcb_INSTANCE *instance, std::shared_ptr<l
394
411
  req.request.opcode = PROTOCOL_BINARY_CMD_GET;
395
412
  mc_PIPELINE *pl;
396
413
  mc_PACKET *pkt;
397
- lcb_STATUS err = mcreq_basic_packet(cq, &keybuf, cmd->collection().collection_id(), &req, 0, 0, &pkt, &pl,
398
- MCREQ_BASICPACKET_F_FALLBACKOK);
414
+ lcb_STATUS err = mcreq_basic_packet(cq, &keybuf, cmd->collection().collection_id(), &req, 0, ffextlen, &pkt,
415
+ &pl, MCREQ_BASICPACKET_F_FALLBACKOK);
399
416
  if (err != LCB_SUCCESS) {
400
417
  delete rck;
401
418
  return err;
@@ -405,6 +422,9 @@ static lcb_STATUS get_replica_schedule(lcb_INSTANCE *instance, std::shared_ptr<l
405
422
  pkt->flags |= MCREQ_F_REQEXT;
406
423
  rck->remaining++;
407
424
  mcreq_write_hdr(pkt, &req);
425
+ if (!framing_extras.empty()) {
426
+ memcpy(SPAN_BUFFER(&pkt->kh_span) + sizeof(req.bytes), framing_extras.data(), framing_extras.size());
427
+ }
408
428
  mcreq_sched_add(pl, pkt);
409
429
  }
410
430
 
@@ -129,7 +129,7 @@ static void handle_observe_callback(mc_PIPELINE *pl, mc_PACKET *pkt, lcb_CALLBAC
129
129
  opc->remaining--;
130
130
  if (opc->remaining == 0) {
131
131
  TRACE_OBSERVE_END(instance, pkt);
132
- LCBTRACE_KV_FINISH(pl, pkt, resp, 0);
132
+ lcb::trace::finish_kv_span(pl, pkt, nullptr);
133
133
  delete opc;
134
134
  }
135
135
  }
@@ -426,7 +426,7 @@ static void handle_ping(mc_PIPELINE *pipeline, mc_PACKET *req, lcb_CALLBACK_TYPE
426
426
  } else {
427
427
  hh.append(remote.host).append(":").append(remote.port);
428
428
  }
429
- svc.server = strdup(hh.c_str());
429
+ svc.server = lcb_strdup(hh.c_str());
430
430
  }
431
431
  svc.type = LCB_PING_SERVICE_KV;
432
432
  svc.latency = gethrtime() - MCREQ_PKT_RDATA(req)->start;
@@ -445,9 +445,9 @@ static void handle_ping(mc_PIPELINE *pipeline, mc_PACKET *req, lcb_CALLBACK_TYPE
445
445
  lcbio_CTX *ctx = server->connctx;
446
446
  if (ctx) {
447
447
  char id[20] = {0};
448
- svc.local = strdup(ctx->sock->info->ep_local);
448
+ svc.local = lcb_strdup(ctx->sock->info->ep_local_host_and_port);
449
449
  snprintf(id, sizeof(id), "%p", (void *)ctx->sock);
450
- svc.id = strdup(id);
450
+ svc.id = lcb_strdup(id);
451
451
  }
452
452
  svc.scope = server->get_instance()->get_bucketname();
453
453
 
@@ -477,7 +477,7 @@ static void handle_http(lcb_INSTANCE *instance, lcb_PING_SERVICE type, const lcb
477
477
  } else {
478
478
  hh = std::string(htreq->host) + ":" + std::string(htreq->port);
479
479
  }
480
- svc.server = strdup(hh.c_str());
480
+ svc.server = lcb_strdup(hh.c_str());
481
481
  svc.latency = gethrtime() - htreq->start;
482
482
  svc.rc = resp->ctx.rc;
483
483
  switch (resp->ctx.rc) {
@@ -495,8 +495,8 @@ static void handle_http(lcb_INSTANCE *instance, lcb_PING_SERVICE type, const lcb
495
495
  if (ctx) {
496
496
  char id[20] = {0};
497
497
  snprintf(id, sizeof(id), "%p", (void *)ctx->sock);
498
- svc.id = strdup(id);
499
- svc.local = strdup(ctx->sock->info->ep_local);
498
+ svc.id = lcb_strdup(id);
499
+ svc.local = lcb_strdup(ctx->sock->info->ep_local_host_and_port);
500
500
  }
501
501
  ck->responses.push_back(svc);
502
502
  }
@@ -759,7 +759,7 @@ lcb_STATUS lcb_diag(lcb_INSTANCE *instance, void *cookie, const lcb_CMDDIAG *cmd
759
759
  }
760
760
  if (ctx->sock) {
761
761
  if (ctx->sock->info) {
762
- endpoint["local"] = ctx->sock->info->ep_local;
762
+ endpoint["local"] = ctx->sock->info->ep_local_host_and_port;
763
763
  }
764
764
  endpoint["last_activity_us"] =
765
765
  (Json::Value::UInt64)(now > ctx->sock->atime ? now - ctx->sock->atime : 0);
@@ -790,7 +790,7 @@ lcb_STATUS lcb_diag(lcb_INSTANCE *instance, void *cookie, const lcb_CMDDIAG *cmd
790
790
  }
791
791
  if (ctx->sock) {
792
792
  if (ctx->sock->info) {
793
- endpoint["local"] = ctx->sock->info->ep_local;
793
+ endpoint["local"] = ctx->sock->info->ep_local_host_and_port;
794
794
  }
795
795
  endpoint["last_activity_us"] =
796
796
  (Json::Value::UInt64)(now > ctx->sock->atime ? now - ctx->sock->atime : 0);
@@ -66,7 +66,8 @@ lcb_STATUS lcb_pktfwd3(lcb_INSTANCE *instance, const void *cookie, const lcb_CMD
66
66
  /* set the cookie */
67
67
  packet->u_rdata.reqdata.cookie = cookie;
68
68
  packet->u_rdata.reqdata.start = gethrtime();
69
- packet->u_rdata.reqdata.deadline = packet->u_rdata.reqdata.start + LCB_US2NS(LCBT_SETTING(instance, operation_timeout));
69
+ packet->u_rdata.reqdata.deadline =
70
+ packet->u_rdata.reqdata.start + LCB_US2NS(LCBT_SETTING(instance, operation_timeout));
70
71
  return err;
71
72
  }
72
73
 
@@ -112,6 +112,11 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdremove_durability(lcb_CMDREMOVE *cmd, lcb_DUR
112
112
  return cmd->durability_level(level);
113
113
  }
114
114
 
115
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdremove_on_behalf_of(lcb_CMDREMOVE *cmd, const char *data, size_t data_len)
116
+ {
117
+ return cmd->on_behalf_of(std::string(data, data_len));
118
+ }
119
+
115
120
  static lcb_STATUS remove_validate(lcb_INSTANCE *instance, const lcb_CMDREMOVE *cmd)
116
121
  {
117
122
  if (cmd->key().empty()) {
@@ -132,37 +137,45 @@ static lcb_STATUS remove_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
132
137
  mc_CMDQUEUE *cq = &instance->cmdq;
133
138
  mc_PIPELINE *pl;
134
139
  mc_PACKET *pkt;
135
- protocol_binary_request_delete req{};
136
- protocol_binary_request_header *hdr = &req.message.header;
137
140
  int new_durability_supported = LCBT_SUPPORT_SYNCREPLICATION(instance);
138
- lcb_U8 ffextlen = 0;
139
- size_t hsize;
140
141
  lcb_STATUS err;
141
142
 
142
- hdr->request.magic = PROTOCOL_BINARY_REQ;
143
+ protocol_binary_request_header hdr{};
144
+
145
+ std::vector<std::uint8_t> framing_extras;
143
146
  if (new_durability_supported && cmd->has_durability_requirements()) {
144
- hdr->request.magic = PROTOCOL_BINARY_AREQ;
145
- ffextlen = 4;
147
+ auto durability_timeout = htons(lcb_durability_timeout(instance, cmd->timeout_in_microseconds()));
148
+ std::uint8_t frame_id = 0x01;
149
+ std::uint8_t frame_size = durability_timeout > 0 ? 3 : 1;
150
+ framing_extras.emplace_back(frame_id << 4U | frame_size);
151
+ framing_extras.emplace_back(cmd->durability_level());
152
+ if (durability_timeout > 0) {
153
+ framing_extras.emplace_back(durability_timeout >> 8U);
154
+ framing_extras.emplace_back(durability_timeout & 0xff);
155
+ }
156
+ }
157
+ if (cmd->want_impersonation()) {
158
+ err = lcb::flexible_framing_extras::encode_impersonate_user(cmd->impostor(), framing_extras);
159
+ if (err != LCB_SUCCESS) {
160
+ return err;
161
+ }
146
162
  }
147
163
 
164
+ hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
165
+ auto ffextlen = static_cast<std::uint8_t>(framing_extras.size());
166
+
148
167
  lcb_KEYBUF keybuf{LCB_KV_COPY, {cmd->key().c_str(), cmd->key().size()}};
149
- err = mcreq_basic_packet(cq, &keybuf, cmd->collection().collection_id(), hdr, 0, ffextlen, &pkt, &pl,
168
+ err = mcreq_basic_packet(cq, &keybuf, cmd->collection().collection_id(), &hdr, 0, ffextlen, &pkt, &pl,
150
169
  MCREQ_BASICPACKET_F_FALLBACKOK);
151
170
  if (err != LCB_SUCCESS) {
152
171
  return err;
153
172
  }
154
- hsize = hdr->request.extlen + sizeof(*hdr) + ffextlen;
155
173
 
156
- hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES;
157
- hdr->request.opcode = PROTOCOL_BINARY_CMD_DELETE;
158
- hdr->request.cas = lcb_htonll(cmd->cas());
159
- hdr->request.opaque = pkt->opaque;
160
- hdr->request.bodylen = htonl(ffextlen + hdr->request.extlen + mcreq_get_key_size(hdr));
161
- if (new_durability_supported && cmd->has_durability_requirements()) {
162
- req.message.body.alt.meta = (1u << 4u) | 3u;
163
- req.message.body.alt.level = cmd->durability_level();
164
- req.message.body.alt.timeout = htons(lcb_durability_timeout(instance, cmd->timeout_in_microseconds()));
165
- }
174
+ hdr.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
175
+ hdr.request.opcode = PROTOCOL_BINARY_CMD_DELETE;
176
+ hdr.request.cas = lcb_htonll(cmd->cas());
177
+ hdr.request.opaque = pkt->opaque;
178
+ hdr.request.bodylen = htonl(ffextlen + hdr.request.extlen + mcreq_get_key_size(&hdr));
166
179
 
167
180
  pkt->flags |= MCREQ_F_REPLACE_SEMANTICS;
168
181
  pkt->u_rdata.reqdata.cookie = cmd->cookie();
@@ -170,9 +183,13 @@ static lcb_STATUS remove_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
170
183
  pkt->u_rdata.reqdata.deadline =
171
184
  pkt->u_rdata.reqdata.start +
172
185
  cmd->timeout_or_default_in_nanoseconds(LCB_US2NS(LCBT_SETTING(instance, operation_timeout)));
173
- memcpy(SPAN_BUFFER(&pkt->kh_span), hdr->bytes, hsize);
174
- LCBTRACE_KV_START(instance->settings, pkt->opaque, cmd, LCBTRACE_OP_REMOVE, pkt->u_rdata.reqdata.span);
175
- TRACE_REMOVE_BEGIN(instance, hdr, cmd);
186
+ memcpy(SPAN_BUFFER(&pkt->kh_span), &hdr, sizeof(hdr));
187
+ std::size_t offset = sizeof(hdr);
188
+ if (!framing_extras.empty()) {
189
+ memcpy(SPAN_BUFFER(&pkt->kh_span) + offset, framing_extras.data(), framing_extras.size());
190
+ }
191
+ pkt->u_rdata.reqdata.span = lcb::trace::start_kv_span(instance->settings, pkt, cmd);
192
+ TRACE_REMOVE_BEGIN(instance, &hdr, cmd);
176
193
  LCB_SCHED_ADD(instance, pl, pkt)
177
194
  return LCB_SUCCESS;
178
195
  }
@@ -229,6 +229,11 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_durability_observe(lcb_CMDSTORE *cmd, i
229
229
  return cmd->durability_poll(persist_to, replicate_to);
230
230
  }
231
231
 
232
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_on_behalf_of(lcb_CMDSTORE *cmd, const char *data, size_t data_len)
233
+ {
234
+ return cmd->on_behalf_of(std::string(data, data_len));
235
+ }
236
+
232
237
  struct DurStoreCtx : mc_REQDATAEX {
233
238
  lcb_INSTANCE *instance;
234
239
  lcb_U16 persist_to;
@@ -375,19 +380,27 @@ static lcb_STATUS store_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CMD
375
380
 
376
381
  std::vector<std::uint8_t> framing_extras;
377
382
  if (new_durability_supported && cmd->has_sync_durability_requirements()) {
383
+ auto durability_timeout = htons(lcb_durability_timeout(instance, cmd->timeout_in_microseconds()));
378
384
  std::uint8_t frame_id = 0x01;
379
- std::uint8_t frame_size = 0x04;
385
+ std::uint8_t frame_size = durability_timeout > 0 ? 3 : 1;
380
386
  framing_extras.emplace_back(frame_id << 4U | frame_size);
381
387
  framing_extras.emplace_back(cmd->durability_level());
382
- auto durability_timeout = htons(lcb_durability_timeout(instance, cmd->timeout_in_microseconds()));
383
- framing_extras.emplace_back(durability_timeout >> 8U);
384
- framing_extras.emplace_back(durability_timeout & 0xff);
388
+ if (durability_timeout > 0) {
389
+ framing_extras.emplace_back(durability_timeout >> 8U);
390
+ framing_extras.emplace_back(durability_timeout & 0xff);
391
+ }
385
392
  }
386
393
  if (cmd->should_preserve_expiry()) {
387
394
  std::uint8_t frame_id = 0x05;
388
395
  std::uint8_t frame_size = 0x00;
389
396
  framing_extras.emplace_back(frame_id << 4U | frame_size);
390
397
  }
398
+ if (cmd->want_impersonation()) {
399
+ err = lcb::flexible_framing_extras::encode_impersonate_user(cmd->impostor(), framing_extras);
400
+ if (err != LCB_SUCCESS) {
401
+ return err;
402
+ }
403
+ }
391
404
  auto ffextlen = static_cast<std::uint8_t>(framing_extras.size());
392
405
  hdr.request.magic = (ffextlen == 0) ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
393
406
  hdr.request.opcode = cmd->opcode();
@@ -472,7 +485,7 @@ static lcb_STATUS store_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CMD
472
485
  if (cmd->is_replace_semantics()) {
473
486
  packet->flags |= MCREQ_F_REPLACE_SEMANTICS;
474
487
  }
475
- LCBTRACE_KVSTORE_START(instance->settings, packet->opaque, cmd, cmd->operation_name(), rdata->span);
488
+ rdata->span = lcb::trace::start_kv_span_with_durability(instance->settings, packet, cmd);
476
489
  LCB_SCHED_ADD(instance, pipeline, packet)
477
490
 
478
491
  TRACE_STORE_BEGIN(instance, &hdr, cmd);
@@ -404,6 +404,11 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdsubdoc_create_as_deleted(lcb_CMDSUBDOC *cmd,
404
404
  return cmd->create_as_deleted(flag);
405
405
  }
406
406
 
407
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdsubdoc_on_behalf_of(lcb_CMDSUBDOC *cmd, const char *data, size_t data_len)
408
+ {
409
+ return cmd->on_behalf_of(std::string(data, data_len));
410
+ }
411
+
407
412
  namespace SubdocCmdTraits
408
413
  {
409
414
  enum Options {
@@ -772,13 +777,15 @@ static lcb_STATUS subdoc_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
772
777
  hdr.request.opcode = PROTOCOL_BINARY_CMD_SUBDOC_MULTI_MUTATION;
773
778
 
774
779
  if (new_durability_supported && cmd->has_durability_requirements()) {
780
+ auto durability_timeout = htons(lcb_durability_timeout(instance, cmd->timeout_in_microseconds()));
775
781
  std::uint8_t frame_id = 0x01;
776
- std::uint8_t frame_size = 0x04;
782
+ std::uint8_t frame_size = durability_timeout > 0 ? 3 : 1;
777
783
  framing_extras.emplace_back(frame_id << 4U | frame_size);
778
784
  framing_extras.emplace_back(cmd->durability_level());
779
- auto durability_timeout = htons(lcb_durability_timeout(instance, cmd->timeout_in_microseconds()));
780
- framing_extras.emplace_back(durability_timeout >> 8U);
781
- framing_extras.emplace_back(durability_timeout & 0xff);
785
+ if (durability_timeout > 0) {
786
+ framing_extras.emplace_back(durability_timeout >> 8U);
787
+ framing_extras.emplace_back(durability_timeout & 0xff);
788
+ }
782
789
  }
783
790
  if (cmd->should_preserve_expiry()) {
784
791
  std::uint8_t frame_id = 0x05;
@@ -786,6 +793,12 @@ static lcb_STATUS subdoc_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
786
793
  framing_extras.emplace_back(frame_id << 4U | frame_size);
787
794
  }
788
795
  }
796
+ if (cmd->want_impersonation()) {
797
+ rc = lcb::flexible_framing_extras::encode_impersonate_user(cmd->impostor(), framing_extras);
798
+ if (rc != LCB_SUCCESS) {
799
+ return rc;
800
+ }
801
+ }
789
802
  hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
790
803
  auto ffextlen = static_cast<std::uint8_t>(framing_extras.size());
791
804
 
@@ -840,8 +853,7 @@ static lcb_STATUS subdoc_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
840
853
  MCREQ_PKT_RDATA(pkt)->start +
841
854
  cmd->timeout_or_default_in_nanoseconds(LCB_US2NS(LCBT_SETTING(instance, operation_timeout)));
842
855
  MCREQ_PKT_RDATA(pkt)->nsubreq = cmd->specs().specs().size();
843
- LCBTRACE_KV_START(instance->settings, pkt->opaque, cmd,
844
- ctx.is_mutate() ? LCBTRACE_OP_MUTATEIN : LCBTRACE_OP_LOOKUPIN, MCREQ_PKT_RDATA(pkt)->span);
856
+ MCREQ_PKT_RDATA(pkt)->span = lcb::trace::start_kv_span(instance->settings, pkt, cmd);
845
857
  LCB_SCHED_ADD(instance, pl, pkt)
846
858
  return LCB_SUCCESS;
847
859
  }
@@ -112,6 +112,11 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdtouch_durability(lcb_CMDTOUCH * /* cmd */, lc
112
112
  return LCB_ERR_UNSUPPORTED_OPERATION;
113
113
  }
114
114
 
115
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdtouch_on_behalf_of(lcb_CMDTOUCH *cmd, const char *data, size_t data_len)
116
+ {
117
+ return cmd->on_behalf_of(std::string(data, data_len));
118
+ }
119
+
115
120
  static lcb_STATUS touch_validate(lcb_INSTANCE *instance, const lcb_CMDTOUCH *cmd)
116
121
  {
117
122
  if (cmd->key().empty()) {
@@ -126,39 +131,52 @@ static lcb_STATUS touch_validate(lcb_INSTANCE *instance, const lcb_CMDTOUCH *cmd
126
131
 
127
132
  static lcb_STATUS touch_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CMDTOUCH> cmd)
128
133
  {
129
- protocol_binary_request_touch tcmd;
130
- protocol_binary_request_header *hdr = &tcmd.message.header;
134
+ protocol_binary_request_header hdr{};
131
135
  mc_PIPELINE *pl;
132
136
  mc_PACKET *pkt;
133
137
  lcb_STATUS err;
134
- lcb_U8 ffextlen = 0;
135
- size_t hsize;
138
+
139
+ std::vector<std::uint8_t> framing_extras;
140
+ if (cmd->want_impersonation()) {
141
+ err = lcb::flexible_framing_extras::encode_impersonate_user(cmd->impostor(), framing_extras);
142
+ if (err != LCB_SUCCESS) {
143
+ return err;
144
+ }
145
+ }
146
+
147
+ hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
148
+ auto ffextlen = static_cast<std::uint8_t>(framing_extras.size());
136
149
 
137
150
  lcb_KEYBUF keybuf{LCB_KV_COPY, {cmd->key().c_str(), cmd->key().size()}};
138
- err = mcreq_basic_packet(&instance->cmdq, &keybuf, cmd->collection().collection_id(), hdr, 4, ffextlen, &pkt, &pl,
151
+ err = mcreq_basic_packet(&instance->cmdq, &keybuf, cmd->collection().collection_id(), &hdr, 4, ffextlen, &pkt, &pl,
139
152
  MCREQ_BASICPACKET_F_FALLBACKOK);
140
153
  if (err != LCB_SUCCESS) {
141
154
  return err;
142
155
  }
143
- hsize = hdr->request.extlen + sizeof(*hdr) + ffextlen;
144
156
 
145
- hdr->request.magic = PROTOCOL_BINARY_REQ;
146
- hdr->request.opcode = PROTOCOL_BINARY_CMD_TOUCH;
147
- hdr->request.cas = 0;
148
- hdr->request.datatype = PROTOCOL_BINARY_RAW_BYTES;
149
- hdr->request.opaque = pkt->opaque;
150
- hdr->request.bodylen = htonl(4 + ffextlen + ntohs(hdr->request.keylen));
151
- tcmd.message.body.norm.expiration = htonl(cmd->expiry());
157
+ hdr.request.opcode = PROTOCOL_BINARY_CMD_TOUCH;
158
+ hdr.request.cas = 0;
159
+ hdr.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
160
+ hdr.request.opaque = pkt->opaque;
161
+ hdr.request.bodylen = htonl(hdr.request.extlen + ffextlen + mcreq_get_key_size(&hdr));
162
+
163
+ memcpy(SPAN_BUFFER(&pkt->kh_span), &hdr, sizeof(hdr));
164
+ std::size_t offset = sizeof(hdr);
165
+ if (!framing_extras.empty()) {
166
+ memcpy(SPAN_BUFFER(&pkt->kh_span) + offset, framing_extras.data(), framing_extras.size());
167
+ offset += framing_extras.size();
168
+ }
169
+ std::uint32_t expiry = htonl(cmd->expiry());
170
+ memcpy(SPAN_BUFFER(&pkt->kh_span) + offset, &expiry, sizeof(expiry));
152
171
 
153
- memcpy(SPAN_BUFFER(&pkt->kh_span), tcmd.bytes, hsize);
154
172
  pkt->u_rdata.reqdata.cookie = cmd->cookie();
155
173
  pkt->u_rdata.reqdata.start = cmd->start_time_or_default_in_nanoseconds(gethrtime());
156
174
  pkt->u_rdata.reqdata.deadline =
157
175
  pkt->u_rdata.reqdata.start +
158
176
  cmd->timeout_or_default_in_nanoseconds(LCB_US2NS(LCBT_SETTING(instance, operation_timeout)));
159
- LCBTRACE_KV_START(instance->settings, pkt->opaque, cmd, LCBTRACE_OP_TOUCH, pkt->u_rdata.reqdata.span);
177
+ pkt->u_rdata.reqdata.span = lcb::trace::start_kv_span(instance->settings, pkt, cmd);
160
178
  LCB_SCHED_ADD(instance, pl, pkt);
161
- TRACE_TOUCH_BEGIN(instance, hdr, cmd);
179
+ TRACE_TOUCH_BEGIN(instance, &hdr, cmd);
162
180
  return LCB_SUCCESS;
163
181
  }
164
182
 
@@ -101,6 +101,11 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdunlock_cas(lcb_CMDUNLOCK *cmd, uint64_t cas)
101
101
  return cmd->cas(cas);
102
102
  }
103
103
 
104
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdunlock_on_behalf_of(lcb_CMDUNLOCK *cmd, const char *data, size_t data_len)
105
+ {
106
+ return cmd->on_behalf_of(std::string(data, data_len));
107
+ }
108
+
104
109
  static lcb_STATUS unlock_validate(lcb_INSTANCE *instance, const lcb_CMDUNLOCK *cmd)
105
110
  {
106
111
  if (cmd->key().empty()) {
@@ -124,10 +129,21 @@ static lcb_STATUS unlock_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
124
129
  mc_PACKET *pkt;
125
130
  mc_REQDATA *rd;
126
131
  lcb_STATUS err;
127
- protocol_binary_request_header hdr;
132
+ protocol_binary_request_header hdr{};
133
+
134
+ std::vector<std::uint8_t> framing_extras;
135
+ if (cmd->want_impersonation()) {
136
+ err = lcb::flexible_framing_extras::encode_impersonate_user(cmd->impostor(), framing_extras);
137
+ if (err != LCB_SUCCESS) {
138
+ return err;
139
+ }
140
+ }
141
+
142
+ hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
143
+ auto ffextlen = static_cast<std::uint8_t>(framing_extras.size());
128
144
 
129
145
  lcb_KEYBUF keybuf{LCB_KV_COPY, {cmd->key().c_str(), cmd->key().size()}};
130
- err = mcreq_basic_packet(cq, &keybuf, cmd->collection().collection_id(), &hdr, 0, 0, &pkt, &pl,
146
+ err = mcreq_basic_packet(cq, &keybuf, cmd->collection().collection_id(), &hdr, 0, ffextlen, &pkt, &pl,
131
147
  MCREQ_BASICPACKET_F_FALLBACKOK);
132
148
  if (err != LCB_SUCCESS) {
133
149
  return err;
@@ -139,15 +155,18 @@ static lcb_STATUS unlock_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
139
155
  rd->deadline =
140
156
  rd->start + cmd->timeout_or_default_in_nanoseconds(LCB_US2NS(LCBT_SETTING(instance, operation_timeout)));
141
157
 
142
- hdr.request.magic = PROTOCOL_BINARY_REQ;
143
158
  hdr.request.opcode = PROTOCOL_BINARY_CMD_UNLOCK_KEY;
144
159
  hdr.request.datatype = PROTOCOL_BINARY_RAW_BYTES;
145
- hdr.request.bodylen = htonl((lcb_uint32_t)ntohs(hdr.request.keylen));
160
+ hdr.request.bodylen = htonl(mcreq_get_key_size(&hdr));
146
161
  hdr.request.opaque = pkt->opaque;
147
162
  hdr.request.cas = lcb_htonll(cmd->cas());
148
163
 
149
164
  memcpy(SPAN_BUFFER(&pkt->kh_span), hdr.bytes, sizeof(hdr.bytes));
150
- LCBTRACE_KV_START(instance->settings, pkt->opaque, cmd, LCBTRACE_OP_TOUCH, rd->span);
165
+ std::size_t offset = sizeof(hdr);
166
+ if (!framing_extras.empty()) {
167
+ memcpy(SPAN_BUFFER(&pkt->kh_span) + offset, framing_extras.data(), framing_extras.size());
168
+ }
169
+ rd->span = lcb::trace::start_kv_span(instance->settings, pkt, cmd);
151
170
  LCB_SCHED_ADD(instance, pl, pkt);
152
171
  TRACE_UNLOCK_BEGIN(instance, &hdr, cmd);
153
172
  return LCB_SUCCESS;
@@ -23,6 +23,7 @@
23
23
  #include <libcouchbase/couchbase.h>
24
24
  #include <memcached/protocol_binary.h>
25
25
  #include "rdb/rope.h"
26
+ #include "utilities.h"
26
27
 
27
28
  #ifndef __cplusplus
28
29
  typedef struct packet_info_st packet_info;
@@ -315,10 +316,10 @@ class MemcachedResponse
315
316
  }
316
317
  std::string emsg;
317
318
  if (!jerr["ref"].empty()) {
318
- *err_ref = strdup(jerr["ref"].asCString());
319
+ *err_ref = lcb_strdup(jerr["ref"].asCString());
319
320
  }
320
321
  if (!jerr["context"].empty()) {
321
- *err_ctx = strdup(jerr["context"].asCString());
322
+ *err_ctx = lcb_strdup(jerr["context"].asCString());
322
323
  }
323
324
  return LCB_SUCCESS;
324
325
  }
@@ -366,14 +366,33 @@ void RetryQueue::add(mc_EXPACKET *pkt, const lcb_STATUS err, protocol_binary_res
366
366
  if (server == nullptr) {
367
367
  continue;
368
368
  }
369
+
369
370
  /* check pending queue */
370
- SLLIST_ITERFOR(&server->nbmgr.sendq.pending, &iter)
371
371
  {
372
- nb_SNDQELEM *el = SLLIST_ITEM(iter.cur, nb_SNDQELEM, slnode);
373
- if (el->parent == op->pkt) {
374
- sllist_iter_remove(&server->nbmgr.sendq.pending, &iter);
372
+ nb_SENDQ *sq = &server->nbmgr.sendq;
373
+
374
+ /* in the case of completion IO, there is a chunk of the sendq which
375
+ * has already been written to the network and cannot be cancelled,
376
+ * we need to only scan to remove packets which have NOT been sent
377
+ * yet.
378
+ */
379
+ sllist_node *ll;
380
+ if (sq->last_requested) {
381
+ ll = sq->last_requested->slnode.next;
382
+ } else {
383
+ ll = SLLIST_FIRST(&sq->pending);
384
+ }
385
+ if (ll) {
386
+ for (slist_iter_init_at(ll, &iter); !sllist_iter_end(&sq->pending, &iter);
387
+ slist_iter_incr(&sq->pending, &iter)) {
388
+ nb_SNDQELEM *el = SLLIST_ITEM(iter.cur, nb_SNDQELEM, slnode);
389
+ if (el->parent == op->pkt) {
390
+ sllist_iter_remove(&sq->pending, &iter);
391
+ }
392
+ }
375
393
  }
376
394
  }
395
+
377
396
  /* check flush queue */
378
397
  SLLIST_ITERFOR(&server->nbmgr.sendq.pdus, &iter)
379
398
  {
@@ -406,7 +425,7 @@ void RetryQueue::add(mc_EXPACKET *pkt, const lcb_STATUS err, protocol_binary_res
406
425
  uint32_t cid = mcreq_get_cid(get_instance(), &pkt->base);
407
426
  lcb_log(LOGARGS(this, DEBUG),
408
427
  "Adding PKT=%p to retry queue. retries=%u, cid=%u, opaque=%u, now=%" PRIu64 "ms, spent=%" PRIu64
409
- "us, deadline_in=%" PRIu64 "us, , status=0x%02x, rc=%s",
428
+ "us, deadline_in=%" PRIu64 "us, status=0x%02x, rc=%s",
410
429
  (void *)pkt, pkt->base.retries, cid, pkt->base.opaque, LCB_NS2MS(now), LCB_NS2US(now - op->start),
411
430
  LCB_NS2US(op->deadline - now), status, lcb_strerror_short(err));
412
431
  schedule();
@@ -43,6 +43,7 @@ static lcb_STATUS search_execute(lcb_INSTANCE *instance, std::shared_ptr<lcb_CMD
43
43
  auto *req = new lcb_SEARCH_HANDLE_(instance, cmd->cookie(), cmd.get());
44
44
  if (req->has_error()) {
45
45
  lcb_STATUS rc = req->last_error();
46
+ req->clear_callback();
46
47
  delete req;
47
48
  return rc;
48
49
  }