libcouchbase 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +2 -2
  3. data/ext/libcouchbase/CMakeLists.txt +51 -25
  4. data/ext/libcouchbase/CONTRIBUTING.md +46 -65
  5. data/ext/libcouchbase/RELEASE_NOTES.markdown +163 -0
  6. data/ext/libcouchbase/cmake/Modules/DownloadLcbDep.cmake +9 -11
  7. data/ext/libcouchbase/cmake/Modules/FindProfiler.cmake +16 -0
  8. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +6 -6
  9. data/ext/libcouchbase/cmake/config-cmake.h.in +2 -0
  10. data/ext/libcouchbase/cmake/configure +16 -0
  11. data/ext/libcouchbase/example/CMakeLists.txt +17 -2
  12. data/ext/libcouchbase/example/analytics/.gitignore +1 -0
  13. data/ext/libcouchbase/example/analytics/analytics.c +158 -0
  14. data/ext/libcouchbase/example/analytics/build-queries.rb +34 -0
  15. data/ext/libcouchbase/example/analytics/cJSON.c +1 -0
  16. data/ext/libcouchbase/example/analytics/cJSON.h +1 -0
  17. data/ext/libcouchbase/example/analytics/queries.h +113 -0
  18. data/ext/libcouchbase/example/analytics/queries/00-show-dataverse.json +5 -0
  19. data/ext/libcouchbase/example/analytics/queries/01-setup-dataset-breweries.json +6 -0
  20. data/ext/libcouchbase/example/analytics/queries/02-setup-dataset-beers.json +6 -0
  21. data/ext/libcouchbase/example/analytics/queries/03-initiate-shadow.json +6 -0
  22. data/ext/libcouchbase/example/analytics/queries/04-list-datasets.json +7 -0
  23. data/ext/libcouchbase/example/analytics/queries/05-count-breweries.json +5 -0
  24. data/ext/libcouchbase/example/analytics/queries/06-first-brewery.json +6 -0
  25. data/ext/libcouchbase/example/analytics/queries/07-key-based-lookup.json +6 -0
  26. data/ext/libcouchbase/example/analytics/queries/08-exact-match-lookup.json +7 -0
  27. data/ext/libcouchbase/example/analytics/queries/09-exact-match-lookup-different-shape.json +6 -0
  28. data/ext/libcouchbase/example/analytics/queries/10-other-query-filters.json +6 -0
  29. data/ext/libcouchbase/example/analytics/queries/11-equijoin.json +9 -0
  30. data/ext/libcouchbase/example/analytics/queries/12-equijoin-select-star.json +10 -0
  31. data/ext/libcouchbase/example/analytics/queries/13-ansi-join.json +8 -0
  32. data/ext/libcouchbase/example/analytics/queries/14-join-select-values.json +8 -0
  33. data/ext/libcouchbase/example/analytics/queries/15-nested-outer-join.json +7 -0
  34. data/ext/libcouchbase/example/analytics/queries/16-theta-join.json +8 -0
  35. data/ext/libcouchbase/example/analytics/queries/17-existential-quantification.json +9 -0
  36. data/ext/libcouchbase/example/analytics/queries/18-universal-quantification.json +7 -0
  37. data/ext/libcouchbase/example/analytics/queries/19-simple-aggregation.json +6 -0
  38. data/ext/libcouchbase/example/analytics/queries/20-simple-aggregation-unwrapped-value.json +6 -0
  39. data/ext/libcouchbase/example/analytics/queries/21-simple-aggregation-explicit.json +6 -0
  40. data/ext/libcouchbase/example/analytics/queries/22-grouping-and-aggregation.json +6 -0
  41. data/ext/libcouchbase/example/analytics/queries/23-grouping-and-aggregation-with-hint.json +7 -0
  42. data/ext/libcouchbase/example/analytics/queries/24-grouping-and-limits.json +7 -0
  43. data/ext/libcouchbase/example/analytics/queries/25-named-parameters.json +7 -0
  44. data/ext/libcouchbase/example/analytics/queries/26-positional-parameters.json +7 -0
  45. data/ext/libcouchbase/example/crypto/common_provider.c +2 -0
  46. data/ext/libcouchbase/example/crypto/common_provider.h +2 -0
  47. data/ext/libcouchbase/example/crypto/openssl_symmetric_decrypt.c +5 -0
  48. data/ext/libcouchbase/example/crypto/openssl_symmetric_encrypt.c +0 -1
  49. data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.c +16 -26
  50. data/ext/libcouchbase/example/db/db.c +10 -6
  51. data/ext/libcouchbase/example/fts/.gitignore +1 -0
  52. data/ext/libcouchbase/example/fts/build-queries.rb +33 -0
  53. data/ext/libcouchbase/example/fts/fts.c +142 -0
  54. data/ext/libcouchbase/example/fts/queries.h +61 -0
  55. data/ext/libcouchbase/example/fts/queries/00-simple-text-query.json +12 -0
  56. data/ext/libcouchbase/example/fts/queries/01-simple-text-query-on-non-default-index.json +9 -0
  57. data/ext/libcouchbase/example/fts/queries/02-simple-text-query-on-stored-field.json +13 -0
  58. data/ext/libcouchbase/example/fts/queries/03-match-query-with-facet.json +19 -0
  59. data/ext/libcouchbase/example/fts/queries/04-docid-query.json +11 -0
  60. data/ext/libcouchbase/example/fts/queries/05-unanalyzed-term-query-with-fuzziness-level-of-0.json +13 -0
  61. data/ext/libcouchbase/example/fts/queries/06-unanalyzed-term-query-with-fuzziness-level-of-2.json +14 -0
  62. data/ext/libcouchbase/example/fts/queries/07-match-phrase-query.json +13 -0
  63. data/ext/libcouchbase/example/fts/queries/08-phrase-query.json +16 -0
  64. data/ext/libcouchbase/example/fts/queries/09-query-string-query.json +9 -0
  65. data/ext/libcouchbase/example/fts/queries/10-conjunction-query.json +21 -0
  66. data/ext/libcouchbase/example/fts/queries/11-wild-card-query.json +13 -0
  67. data/ext/libcouchbase/example/fts/queries/12-numeric-range-query.json +11 -0
  68. data/ext/libcouchbase/example/fts/queries/13-regexp-query.json +13 -0
  69. data/ext/libcouchbase/example/minimal/.gitignore +1 -0
  70. data/ext/libcouchbase/example/minimal/query.c +185 -0
  71. data/ext/libcouchbase/example/subdoc/subdoc-xattrs.c +2 -2
  72. data/ext/libcouchbase/example/tracing/cJSON.c +1 -1
  73. data/ext/libcouchbase/example/tracing/cJSON.h +1 -1
  74. data/ext/libcouchbase/include/libcouchbase/cbft.h +38 -4
  75. data/ext/libcouchbase/include/libcouchbase/cntl-private.h +8 -97
  76. data/ext/libcouchbase/include/libcouchbase/cntl.h +288 -8
  77. data/ext/libcouchbase/include/libcouchbase/couchbase.h +47 -10
  78. data/ext/libcouchbase/include/libcouchbase/crypto.h +214 -48
  79. data/ext/libcouchbase/include/libcouchbase/deprecated.h +12 -0
  80. data/ext/libcouchbase/include/libcouchbase/error.h +33 -2
  81. data/ext/libcouchbase/include/libcouchbase/ixmgmt.h +1 -1
  82. data/ext/libcouchbase/include/libcouchbase/n1ql.h +87 -13
  83. data/ext/libcouchbase/include/libcouchbase/subdoc.h +3 -7
  84. data/ext/libcouchbase/include/libcouchbase/tracing.h +174 -56
  85. data/ext/libcouchbase/include/libcouchbase/vbucket.h +21 -1
  86. data/ext/libcouchbase/include/libcouchbase/views.h +49 -4
  87. data/ext/libcouchbase/packaging/deb/control +2 -3
  88. data/ext/libcouchbase/packaging/parse-git-describe.pl +1 -1
  89. data/ext/libcouchbase/plugins/io/libev/CMakeLists.txt +7 -5
  90. data/ext/libcouchbase/plugins/io/libevent/CMakeLists.txt +7 -5
  91. data/ext/libcouchbase/plugins/io/libuv/CMakeLists.txt +14 -12
  92. data/ext/libcouchbase/plugins/io/libuv/libuv_compat.h +3 -0
  93. data/ext/libcouchbase/plugins/io/libuv/plugin-libuv.c +14 -6
  94. data/ext/libcouchbase/plugins/io/select/CMakeLists.txt +7 -5
  95. data/ext/libcouchbase/src/bootstrap.cc +6 -1
  96. data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +2 -7
  97. data/ext/libcouchbase/src/bucketconfig/bc_file.cc +1 -1
  98. data/ext/libcouchbase/src/bucketconfig/bc_http.cc +4 -11
  99. data/ext/libcouchbase/src/bucketconfig/clconfig.h +29 -36
  100. data/ext/libcouchbase/src/bucketconfig/confmon.cc +4 -2
  101. data/ext/libcouchbase/src/cntl.cc +181 -151
  102. data/ext/libcouchbase/src/config_static.h +1 -1
  103. data/ext/libcouchbase/src/connspec.cc +5 -1
  104. data/ext/libcouchbase/src/connspec.h +3 -1
  105. data/ext/libcouchbase/src/crypto.cc +93 -80
  106. data/ext/libcouchbase/src/dns-srv.cc +1 -1
  107. data/ext/libcouchbase/src/handler.cc +0 -1
  108. data/ext/libcouchbase/src/http/http-priv.h +1 -0
  109. data/ext/libcouchbase/src/http/http.cc +1 -2
  110. data/ext/libcouchbase/src/instance.cc +21 -2
  111. data/ext/libcouchbase/src/internal.h +1 -0
  112. data/ext/libcouchbase/src/lcbio/ctx.c +24 -3
  113. data/ext/libcouchbase/src/lcbio/ioutils.cc +1 -1
  114. data/ext/libcouchbase/src/lcbio/rw-inl.h +22 -1
  115. data/ext/libcouchbase/src/lcbio/ssl.h +2 -0
  116. data/ext/libcouchbase/src/mc/compress.cc +18 -11
  117. data/ext/libcouchbase/src/mc/mcreq.c +2 -0
  118. data/ext/libcouchbase/src/mc/mcreq.h +1 -1
  119. data/ext/libcouchbase/src/mcserver/mcserver.cc +163 -6
  120. data/ext/libcouchbase/src/mcserver/negotiate.cc +17 -7
  121. data/ext/libcouchbase/src/n1ql/n1ql.cc +12 -3
  122. data/ext/libcouchbase/src/newconfig.cc +4 -3
  123. data/ext/libcouchbase/src/nodeinfo.cc +1 -7
  124. data/ext/libcouchbase/src/operations/observe.cc +1 -0
  125. data/ext/libcouchbase/src/operations/ping.cc +5 -3
  126. data/ext/libcouchbase/src/retryq.cc +22 -0
  127. data/ext/libcouchbase/src/retryq.h +2 -1
  128. data/ext/libcouchbase/src/rnd.cc +5 -12
  129. data/ext/libcouchbase/src/settings.c +4 -7
  130. data/ext/libcouchbase/src/settings.h +6 -2
  131. data/ext/libcouchbase/src/strcodecs/base64.c +59 -0
  132. data/ext/libcouchbase/src/strcodecs/strcodecs.h +2 -0
  133. data/ext/libcouchbase/src/trace.h +2 -2
  134. data/ext/libcouchbase/src/tracing/span.cc +177 -45
  135. data/ext/libcouchbase/src/tracing/threshold_logging_tracer.cc +70 -28
  136. data/ext/libcouchbase/src/tracing/tracing-internal.h +33 -48
  137. data/ext/libcouchbase/src/vbucket/vbucket.c +146 -30
  138. data/ext/libcouchbase/src/wait.cc +1 -1
  139. data/ext/libcouchbase/tests/CMakeLists.txt +13 -4
  140. data/ext/libcouchbase/tests/iotests/mock-environment.cc +1 -1
  141. data/ext/libcouchbase/tests/iotests/t_misc.cc +2 -2
  142. data/ext/libcouchbase/tests/iotests/t_views.cc +1 -1
  143. data/ext/libcouchbase/tests/iotests/testutil.cc +3 -2
  144. data/ext/libcouchbase/tests/vbucket/confdata/map_node_present_nodesext_missing_nodes.json +94 -0
  145. data/ext/libcouchbase/tests/vbucket/t_config.cc +15 -0
  146. data/ext/libcouchbase/tools/CMakeLists.txt +11 -6
  147. data/ext/libcouchbase/tools/cbc-handlers.h +9 -0
  148. data/ext/libcouchbase/tools/cbc-proxy.cc +1 -1
  149. data/ext/libcouchbase/tools/cbc.cc +33 -5
  150. data/ext/libcouchbase/tools/common/options.cc +1 -1
  151. data/ext/libcouchbase/tools/extract-packets.rb +110 -0
  152. data/lib/libcouchbase/connection.rb +13 -5
  153. data/lib/libcouchbase/ext/tasks.rb +1 -1
  154. data/lib/libcouchbase/version.rb +1 -1
  155. metadata +62 -7
@@ -290,7 +290,7 @@ SessionRequestImpl::set_chosen_mech(std::string& mechlist,
290
290
  return MECH_UNAVAILABLE;
291
291
  }
292
292
  mechlist.assign(forcemech);
293
- if (memcmp(forcemech, "SCRAM-SHA", sizeof("SCRAM-SHA") - 1) == 0) {
293
+ if (strncmp(forcemech, "SCRAM-SHA", sizeof("SCRAM-SHA") - 1) == 0) {
294
294
  allow_scram_sha = 1;
295
295
  }
296
296
  }
@@ -385,7 +385,7 @@ SessionRequestImpl::check_auth(const lcb::MemcachedResponse& packet)
385
385
  cbsasl_error_t saslerr;
386
386
 
387
387
  saslerr = cbsasl_client_check(sasl_client,
388
- packet.body<const char*>(), packet.bodylen());
388
+ packet.value(), packet.vallen());
389
389
 
390
390
  if (saslerr != SASL_OK) {
391
391
  set_error(LCB_AUTH_ERROR, "Invalid SASL check");
@@ -428,12 +428,17 @@ SessionRequestImpl::send_hello()
428
428
  hdr.sizes(0, agent.size(), (sizeof features[0]) * nfeatures);
429
429
  lcbio_ctx_put(ctx, hdr.data(), hdr.size());
430
430
  lcbio_ctx_put(ctx, agent.c_str(), agent.size());
431
- lcb_log(LOGARGS(this, DEBUG), LOGFMT "HELLO identificator: %.*s", LOGID(this), (int)agent.size(), agent.c_str());
431
+
432
+ std::string fstr;
432
433
  for (size_t ii = 0; ii < nfeatures; ii++) {
434
+ char buf[50] = { 0 };
433
435
  lcb_U16 tmp = htons(features[ii]);
434
436
  lcbio_ctx_put(ctx, &tmp, sizeof tmp);
435
- lcb_log(LOGARGS(this, DEBUG), LOGFMT "Request feature: 0x%x (%s)", LOGID(this), features[ii], protocol_feature_2_text(features[ii]));
437
+ snprintf(buf, sizeof(buf), "%s0x%02x (%s)", ii > 0 ? ", " : "", features[ii], protocol_feature_2_text(features[ii]));
438
+ fstr.append(buf);
436
439
  }
440
+ lcb_log(LOGARGS(this, DEBUG), LOGFMT "HELO identificator: %.*s, features: %s", LOGID(this), (int)agent.size(),
441
+ agent.c_str(), fstr.c_str());
437
442
 
438
443
  lcbio_ctx_rwant(ctx, 24);
439
444
  return true;
@@ -454,13 +459,18 @@ SessionRequestImpl::read_hello(const lcb::MemcachedResponse& resp)
454
459
  const char *cur;
455
460
  const char *payload = resp.value();
456
461
  const char *limit = payload + resp.vallen();
457
- for (cur = payload; cur < limit; cur += 2) {
462
+ size_t ii;
463
+ std::string fstr;
464
+ for (ii = 0, cur = payload; cur < limit; cur += 2, ii++) {
458
465
  lcb_U16 tmp;
466
+ char buf[50] = { 0 };
459
467
  memcpy(&tmp, cur, sizeof(tmp));
460
468
  tmp = ntohs(tmp);
461
- lcb_log(LOGARGS(this, DEBUG), LOGFMT "Server supports feature: 0x%x (%s)", LOGID(this), tmp, protocol_feature_2_text(tmp));
462
469
  info->server_features.push_back(tmp);
470
+ snprintf(buf, sizeof(buf), "%s0x%02x (%s)", ii > 0 ? ", " : "", tmp, protocol_feature_2_text(tmp));
471
+ fstr.append(buf);
463
472
  }
473
+ lcb_log(LOGARGS(this, DEBUG), LOGFMT "Server supports features: %s", LOGID(this), fstr.c_str());
464
474
  return true;
465
475
  }
466
476
 
@@ -633,7 +643,7 @@ SessionRequestImpl::handle_read(lcbio_CTX *ioctx)
633
643
  if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
634
644
  completed = true;
635
645
  } else if (status == PROTOCOL_BINARY_RESPONSE_EACCESS) {
636
- set_error(LCB_AUTH_ERROR, "Provided credentials not allowed for bucket", &resp);
646
+ set_error(LCB_AUTH_ERROR, "Provided credentials not allowed for bucket or bucket does not exist", &resp);
637
647
  } else {
638
648
  lcb_log(LOGARGS(this, ERROR), LOGFMT "Unexpected status 0x%x received for SELECT_BUCKET", LOGID(this), status);
639
649
  set_error(LCB_PROTOCOL_ERROR, "Other auth error", &resp);
@@ -185,7 +185,7 @@ typedef struct lcb_N1QLREQ : lcb::jsparse::Parser::Actions {
185
185
  /** Whether we're retrying this */
186
186
  bool was_retried;
187
187
 
188
- /** Is this query to Analytics (CBAS) service */
188
+ /** Is this query to Analytics for N1QL service */
189
189
  bool is_cbas;
190
190
 
191
191
  #ifdef LCB_TRACING
@@ -341,9 +341,18 @@ N1QLREQ::has_retriable_error(const Json::Value& root)
341
341
  unsigned code = 0;
342
342
  if (jcode.isNumeric()) {
343
343
  code = jcode.asUInt();
344
- if (code == 4050 || code == 4070) {
344
+ switch (code) {
345
+ /* n1ql */
346
+ case 4050:
347
+ case 4070:
348
+ /* analytics */
349
+ case 23000:
350
+ case 23003:
351
+ case 23007:
345
352
  lcb_log(LOGARGS(this, TRACE), LOGFMT "Will retry request. code: %d", LOGID(this), code);
346
353
  return true;
354
+ default:
355
+ break;
347
356
  }
348
357
  }
349
358
  if (jmsg.isString()) {
@@ -666,7 +675,7 @@ lcb_N1QLREQ::lcb_N1QLREQ(lcb_t obj,
666
675
  return;
667
676
  }
668
677
 
669
- if (flags & LCB_CMDN1QL_F_CBASQUERY) {
678
+ if (flags & LCB_CMDN1QL_F_ANALYTICSQUERY) {
670
679
  is_cbas = true;
671
680
  }
672
681
  if (is_cbas && (flags & LCB_CMDN1QL_F_PREPCACHE)) {
@@ -145,8 +145,9 @@ static int
145
145
  find_new_data_index(lcbvb_CONFIG *oldconfig, lcbvb_CONFIG* newconfig,
146
146
  lcb::Server *server)
147
147
  {
148
+ lcbvb_SVCMODE mode = LCBT_SETTING_SVCMODE(server->get_instance());
148
149
  const char *old_datahost = lcbvb_get_hostport(oldconfig,
149
- server->get_index(), LCBVB_SVCTYPE_DATA, LCBVB_SVCMODE_PLAIN);
150
+ server->get_index(), LCBVB_SVCTYPE_DATA, mode);
150
151
 
151
152
  if (!old_datahost) {
152
153
  /* Old server had no data service */
@@ -155,7 +156,7 @@ find_new_data_index(lcbvb_CONFIG *oldconfig, lcbvb_CONFIG* newconfig,
155
156
 
156
157
  for (size_t ii = 0; ii < LCBVB_NSERVERS(newconfig); ii++) {
157
158
  const char *new_datahost = lcbvb_get_hostport(newconfig, ii,
158
- LCBVB_SVCTYPE_DATA, LCBVB_SVCMODE_PLAIN);
159
+ LCBVB_SVCTYPE_DATA, mode);
159
160
  if (new_datahost && strcmp(new_datahost, old_datahost) == 0) {
160
161
  return ii;
161
162
  }
@@ -353,7 +354,7 @@ void lcb_update_vbconfig(lcb_t instance, lcb_pCONFIGINFO config)
353
354
  instance->ht_nodes->clear();
354
355
  for (size_t ii = 0; ii < LCBVB_NSERVERS(config->vbc); ++ii) {
355
356
  const char *hp = lcbvb_get_hostport(config->vbc, ii,
356
- LCBVB_SVCTYPE_MGMT, LCBVB_SVCMODE_PLAIN);
357
+ LCBVB_SVCTYPE_MGMT, LCBT_SETTING_SVCMODE(instance));
357
358
  if (hp) {
358
359
  instance->ht_nodes->add(hp, LCB_CONFIG_HTTP_PORT);
359
360
  }
@@ -59,15 +59,9 @@ LIBCOUCHBASE_API
59
59
  const char *
60
60
  lcb_get_node(lcb_t instance, lcb_GETNODETYPE type, unsigned ix)
61
61
  {
62
- lcbvb_SVCMODE mode;
62
+ lcbvb_SVCMODE mode = LCBT_SETTING_SVCMODE(instance);
63
63
  lcbvb_CONFIG *vbc = LCBT_VBCONFIG(instance);
64
64
 
65
- if (LCBT_SETTING(instance, sslopts) & LCB_SSL_ENABLED) {
66
- mode = LCBVB_SVCMODE_SSL;
67
- } else {
68
- mode = LCBVB_SVCMODE_PLAIN;
69
- }
70
-
71
65
  if (type & LCB_NODE_HTCONFIG) {
72
66
  if (type & LCB_NODE_CONNECTED) {
73
67
  const lcb_host_t *host = lcb::clconfig::http_get_host(instance->confmon);
@@ -133,6 +133,7 @@ static void handle_observe_callback(mc_PIPELINE *pl, mc_PACKET *pkt, lcb_error_t
133
133
  }
134
134
  opc->remaining--;
135
135
  if (opc->remaining == 0) {
136
+ TRACE_OBSERVE_END(instance, pkt);
136
137
  delete opc;
137
138
  }
138
139
  }
@@ -315,8 +315,7 @@ lcb_ping3(lcb_t instance, const void *cookie, const lcb_CMDPING *cmd)
315
315
  }
316
316
 
317
317
  lcbvb_CONFIG *cfg = LCBT_VBCONFIG(instance);
318
- const lcbvb_SVCMODE mode = LCBT_SETTING(instance, sslopts) ?
319
- LCBVB_SVCMODE_SSL : LCBVB_SVCMODE_PLAIN;
318
+ const lcbvb_SVCMODE mode = LCBT_SETTING_SVCMODE(instance);
320
319
  if (cmd->services & LCB_PINGSVC_F_KV) {
321
320
  for (ii = 0; ii < cq->npipelines; ii++) {
322
321
  unsigned port = lcbvb_get_port(cfg, ii, LCBVB_SVCTYPE_DATA, mode);
@@ -362,7 +361,7 @@ lcb_ping3(lcb_t instance, const void *cookie, const lcb_CMDPING *cmd)
362
361
  ipv6 ? "[" : "", srv->hostname, ipv6 ? "]" : "", port, PATH); \
363
362
  htcmd.host = buf; \
364
363
  htcmd.method = LCB_HTTP_METHOD_GET; \
365
- htcmd.type = LCB_HTTP_TYPE_RAW; \
364
+ htcmd.type = LCB_HTTP_TYPE_PING; \
366
365
  htcmd.reqhandle = &htreq; \
367
366
  const lcb::Authenticator& auth = *instance->settings->auth; \
368
367
  htcmd.username = auth.username_for(NULL, NULL, LCBT_SETTING(instance, bucket)).c_str(); \
@@ -385,6 +384,9 @@ lcb_ping3(lcb_t instance, const void *cookie, const lcb_CMDPING *cmd)
385
384
  if (cmd->services & LCB_PINGSVC_F_FTS) {
386
385
  PING_HTTP(LCBVB_SVCTYPE_FTS, "/api/ping", http_timeout, handle_fts);
387
386
  }
387
+ if (cmd->services & LCB_PINGSVC_F_ANALYTICS) {
388
+ PING_HTTP(LCBVB_SVCTYPE_ANALYTICS, "/admin/ping", n1ql_timeout, handle_n1ql);
389
+ }
388
390
  #undef PING_HTTP
389
391
  }
390
392
 
@@ -355,6 +355,28 @@ RetryQueue::add(mc_EXPACKET *pkt, const lcb_error_t err,
355
355
  }
356
356
  }
357
357
 
358
+ bool
359
+ RetryQueue::empty(bool ignore_cfgreq) const
360
+ {
361
+ bool is_empty = LCB_LIST_IS_EMPTY(&schedops);
362
+ if (is_empty) {
363
+ return true;
364
+ }
365
+ if (ignore_cfgreq) {
366
+ lcb_list_t *ll, *llnext;
367
+ LCB_LIST_SAFE_FOR(ll, llnext, &schedops) {
368
+ protocol_binary_request_header hdr = {};
369
+ RetryOp *op = from_schednode(ll);
370
+ mcreq_read_hdr(op->pkt, &hdr);
371
+ if (hdr.request.opcode != PROTOCOL_BINARY_CMD_GET_CLUSTER_CONFIG) {
372
+ return false;
373
+ }
374
+ }
375
+ return true;
376
+ }
377
+ return false;
378
+ }
379
+
358
380
  void
359
381
  RetryQueue::nmvadd(mc_EXPACKET *detchpkt)
360
382
  {
@@ -115,9 +115,10 @@ public:
115
115
 
116
116
  /**
117
117
  * @brief Check if there are operations to retry
118
+ * @param ignore_cfgreq if true, consider queue with single 0xb5 request as empty
118
119
  * @return nonzero if there are pending operations
119
120
  */
120
- bool empty() const { return LCB_LIST_IS_EMPTY(&schedops); }
121
+ bool empty(bool ignore_cfgreq = false) const;
121
122
 
122
123
  /**
123
124
  * @brief Reset all timeouts on the retry queue.
@@ -18,15 +18,10 @@
18
18
  #include "rnd.h"
19
19
  #include "internal.h"
20
20
 
21
- #if !defined(COMPILER_SUPPORTS_CXX11) || (defined(_MSC_VER) && _MSC_VER < 1600)
22
- static volatile int rnd_initialized = 0;
21
+ #if !defined(COMPILER_SUPPORTS_CXX11) || (defined(_MSC_VER) && _MSC_VER < 1600) || defined(__APPLE__)
23
22
  LCB_INTERNAL_API
24
23
  void lcb_rnd_global_init(void)
25
24
  {
26
- if (rnd_initialized) {
27
- return;
28
- }
29
- rnd_initialized = 1;
30
25
  if (lcb_getenv_boolean("LCB_NO_SRAND")) {
31
26
  return;
32
27
  }
@@ -51,18 +46,16 @@ lcb_U64 lcb_next_rand64(void)
51
46
  LCB_INTERNAL_API
52
47
  lcb_U32 lcb_next_rand32(void)
53
48
  {
54
- static std::random_device rd;
55
- static std::mt19937 gen(rd());
56
- static std::uniform_int_distribution< lcb_U32 > dis;
49
+ static thread_local std::mt19937 gen { std::random_device { } () };
50
+ std::uniform_int_distribution< lcb_U32 > dis;
57
51
  return dis(gen);
58
52
  }
59
53
 
60
54
  LCB_INTERNAL_API
61
55
  lcb_U64 lcb_next_rand64(void)
62
56
  {
63
- static std::random_device rd;
64
- static std::mt19937 gen(rd());
65
- static std::uniform_int_distribution< lcb_U64 > dis;
57
+ static thread_local std::mt19937 gen { std::random_device { } () };
58
+ std::uniform_int_distribution< lcb_U64 > dis;
66
59
  return dis(gen);
67
60
  }
68
61
  #endif
@@ -67,7 +67,8 @@ void lcb_default_settings(lcb_settings *settings)
67
67
  settings->use_errmap = 1;
68
68
  settings->use_collections = 0;
69
69
  settings->log_redaction = 0;
70
- settings->use_tracing = 0;
70
+ settings->use_tracing = 1;
71
+ settings->network = NULL;
71
72
  #ifdef LCB_TRACING
72
73
  settings->tracer_orphaned_queue_flush_interval = LCBTRACE_DEFAULT_ORPHANED_QUEUE_FLUSH_INTERVAL;
73
74
  settings->tracer_orphaned_queue_size = LCBTRACE_DEFAULT_ORPHANED_QUEUE_SIZE;
@@ -79,6 +80,7 @@ void lcb_default_settings(lcb_settings *settings)
79
80
  settings->tracer_threshold[LCBTRACE_THRESHOLD_FTS] = LCBTRACE_DEFAULT_THRESHOLD_FTS;
80
81
  settings->tracer_threshold[LCBTRACE_THRESHOLD_ANALYTICS] = LCBTRACE_DEFAULT_THRESHOLD_ANALYTICS;
81
82
  #endif
83
+ settings->wait_for_config = 0;
82
84
  }
83
85
 
84
86
  LCB_INTERNAL_API
@@ -105,6 +107,7 @@ lcb_settings_unref(lcb_settings *settings)
105
107
  free(settings->certpath);
106
108
  free(settings->keypath);
107
109
  free(settings->client_string);
110
+ free(settings->network);
108
111
 
109
112
  lcbauth_unref(settings->auth);
110
113
  lcb_errmap_free(settings->errmap);
@@ -115,12 +118,6 @@ lcb_settings_unref(lcb_settings *settings)
115
118
  if (settings->metrics) {
116
119
  lcb_metrics_destroy(settings->metrics);
117
120
  }
118
- #ifdef LCB_TRACING
119
- if (settings->tracer) {
120
- lcbtrace_destroy(settings->tracer);
121
- settings->tracer = NULL;
122
- }
123
- #endif
124
121
  if (settings->dtorcb) {
125
122
  settings->dtorcb(settings->dtorarg);
126
123
  }
@@ -99,9 +99,9 @@
99
99
  /* 50 ms */
100
100
  #define LCB_CONFIG_POLL_INTERVAL_FLOOR LCB_MS2US(50)
101
101
 
102
- #define LCBTRACE_DEFAULT_ORPHANED_QUEUE_FLUSH_INTERVAL LCB_MS2US(1000)
102
+ #define LCBTRACE_DEFAULT_ORPHANED_QUEUE_FLUSH_INTERVAL LCB_MS2US(10000)
103
103
  #define LCBTRACE_DEFAULT_ORPHANED_QUEUE_SIZE 128
104
- #define LCBTRACE_DEFAULT_THRESHOLD_QUEUE_FLUSH_INTERVAL LCB_MS2US(3000)
104
+ #define LCBTRACE_DEFAULT_THRESHOLD_QUEUE_FLUSH_INTERVAL LCB_MS2US(10000)
105
105
  #define LCBTRACE_DEFAULT_THRESHOLD_QUEUE_SIZE 128
106
106
  #define LCBTRACE_DEFAULT_THRESHOLD_KV LCB_MS2US(500)
107
107
  #define LCBTRACE_DEFAULT_THRESHOLD_N1QL LCB_MS2US(1000)
@@ -192,6 +192,9 @@ typedef struct lcb_settings_st {
192
192
  unsigned use_tracing : 1;
193
193
  /** Do not use remap vbuckets (do not use fast forward map, or any other heuristics) */
194
194
  unsigned vb_noremap : 1;
195
+ /** Do not wait for GET_CLUSTER_CONFIG request to finish in lcb_wait(),
196
+ * when it is the only request in retry queue */
197
+ unsigned wait_for_config : 1;
195
198
 
196
199
  short max_redir;
197
200
  unsigned refcount;
@@ -224,6 +227,7 @@ typedef struct lcb_settings_st {
224
227
  #endif
225
228
  lcb_U32 compress_min_size;
226
229
  float compress_min_ratio;
230
+ char *network; /** network resolution, AKA "Multi Network Configurations" */
227
231
  } lcb_settings;
228
232
 
229
233
  LCB_INTERNAL_API
@@ -136,6 +136,65 @@ int lcb_base64_encode2(const char *src, lcb_SIZE nsrc, char **dst, lcb_SIZE *nds
136
136
  return rc;
137
137
  }
138
138
 
139
+ void lcb_base64_encode_iov(lcb_IOV *iov, unsigned niov, unsigned nb, char **dst, int *ndst)
140
+ {
141
+ lcb_SIZE nsrc = 0;
142
+ lcb_SIZE len;
143
+ char *ptr;
144
+ lcb_SIZE io;
145
+
146
+
147
+ for (io = 0; io < niov; io++) {
148
+ nsrc += iov[io].iov_len;
149
+ }
150
+ if (nb < nsrc) {
151
+ nsrc = nb;
152
+ }
153
+ len = (nsrc / 3 + 1) * 4 + 1;
154
+ ptr = calloc(len, sizeof(char));
155
+
156
+ {
157
+ lcb_SIZE triplets = nsrc / 3;
158
+ lcb_SIZE rest = nsrc % 3;
159
+ lcb_uint8_t *out = (lcb_uint8_t *)ptr;
160
+ lcb_SIZE iop, ii;
161
+ lcb_uint8_t triplet[3];
162
+
163
+ io = 0;
164
+ iop = 0;
165
+
166
+
167
+ for (ii = 0; ii < triplets; ii++) {
168
+ int tt;
169
+
170
+ for (tt = 0; tt < 3; tt++) {
171
+ if (iop >= iov[io].iov_len) {
172
+ io++;
173
+ iop = 0;
174
+ }
175
+ triplet[tt] = ((const lcb_uint8_t *)iov[io].iov_base)[iop++];
176
+ }
177
+ encode_triplet(triplet, out);
178
+ out += 4;
179
+ }
180
+
181
+ if (rest > 0) {
182
+ for (ii = 0; ii < rest; ii++) {
183
+ if (iop >= iov[io].iov_len) {
184
+ io++;
185
+ iop = 0;
186
+ }
187
+ triplet[ii] = ((const lcb_uint8_t *)iov[io].iov_base)[iop++];
188
+ }
189
+ encode_rest(triplet, out, rest);
190
+ }
191
+ *out = '\0';
192
+ }
193
+
194
+ *ndst = strlen(ptr);
195
+ *dst = ptr;
196
+ }
197
+
139
198
  static int code2val(char c)
140
199
  {
141
200
  if (c >= 'A' && c <= 'Z') {
@@ -67,6 +67,8 @@ int lcb_base64_encode2(const char *src, lcb_SIZE len, char **dst, lcb_SIZE *sz);
67
67
  lcb_SSIZE lcb_base64_decode(const char *src, lcb_SIZE nsrc, char *dst, lcb_SIZE ndst);
68
68
  lcb_SSIZE lcb_base64_decode2(const char *src, lcb_SIZE nsrc, char **dst, lcb_SIZE *ndst);
69
69
 
70
+ void lcb_base64_encode_iov(lcb_IOV *iov, unsigned niov, unsigned nb, char **dst, int *ndst);
71
+
70
72
  /**
71
73
  * Encodes a string suitable for being passed as either a key or value in an
72
74
  * "HTTP Form" per application/x-www-form-urlencoded
@@ -96,8 +96,8 @@
96
96
  #define TRACE_OBSERVE_PROGRESS(instance, pkt, mcresp, resp) \
97
97
  TRACE(TRACE_END_COMMON(LIBCOUCHBASE_OBSERVE_PROGRESS, instance, pkt, mcresp, resp, (resp)->cas, (resp)->status, \
98
98
  (resp)->ismaster, (resp)->ttp, (resp)->ttr))
99
- #define TRACE_OBSERVE_END(instance, pkt, mcresp) \
100
- TRACE(LIBCOUCHBASE_OBSERVE_END(instance, mcresp->opaque(), mcresp->opcode(), \
99
+ #define TRACE_OBSERVE_END(instance, pkt) \
100
+ TRACE(LIBCOUCHBASE_OBSERVE_END(instance, pkt->opaque, PROTOCOL_BINARY_CMD_OBSERVE, \
101
101
  MCREQ_PKT_RDATA(pkt)->dispatch - MCREQ_PKT_RDATA(pkt)->start, LCB_SUCCESS))
102
102
 
103
103
  #define TRACE_HTTP_BEGIN(req) \
@@ -16,10 +16,30 @@
16
16
  */
17
17
 
18
18
  #include "internal.h"
19
+ #include "sllist-inl.h"
19
20
  #ifdef HAVE__FTIME64_S
20
21
  #include <sys/timeb.h>
21
22
  #endif
22
23
 
24
+ typedef enum { TAGVAL_STRING, TAGVAL_UINT64, TAGVAL_DOUBLE, TAGVAL_BOOL } tag_type;
25
+ typedef struct tag_value {
26
+ sllist_node slnode;
27
+ struct {
28
+ char *p;
29
+ int need_free;
30
+ } key;
31
+ tag_type t;
32
+ union {
33
+ struct {
34
+ char *p;
35
+ size_t l;
36
+ } s;
37
+ lcb_U64 u64;
38
+ double d;
39
+ int b;
40
+ } v;
41
+ } tag_value;
42
+
23
43
  LIBCOUCHBASE_API
24
44
  uint64_t lcbtrace_now()
25
45
  {
@@ -54,37 +74,37 @@ void lcbtrace_span_finish(lcbtrace_SPAN *span, uint64_t now)
54
74
  LIBCOUCHBASE_API
55
75
  void lcbtrace_span_add_tag_str(lcbtrace_SPAN *span, const char *name, const char *value)
56
76
  {
57
- if (!span) {
77
+ if (!span || name == NULL || value == NULL) {
58
78
  return;
59
79
  }
60
- span->add_tag(name, value);
80
+ span->add_tag(name, 1, value);
61
81
  }
62
82
 
63
83
  LIBCOUCHBASE_API
64
84
  void lcbtrace_span_add_tag_uint64(lcbtrace_SPAN *span, const char *name, uint64_t value)
65
85
  {
66
- if (!span) {
86
+ if (!span || name == NULL) {
67
87
  return;
68
88
  }
69
- span->add_tag(name, (Json::Value::UInt64)value);
89
+ span->add_tag(name, 1, value);
70
90
  }
71
91
 
72
92
  LIBCOUCHBASE_API
73
93
  void lcbtrace_span_add_tag_double(lcbtrace_SPAN *span, const char *name, double value)
74
94
  {
75
- if (!span) {
95
+ if (!span || name == NULL) {
76
96
  return;
77
97
  }
78
- span->add_tag(name, value);
98
+ span->add_tag(name, 1, value);
79
99
  }
80
100
 
81
101
  LIBCOUCHBASE_API
82
102
  void lcbtrace_span_add_tag_bool(lcbtrace_SPAN *span, const char *name, int value)
83
103
  {
84
- if (!span) {
104
+ if (!span || name == NULL) {
85
105
  return;
86
106
  }
87
- span->add_tag(name, value);
107
+ span->add_tag(name, 1, (bool)value);
88
108
  }
89
109
 
90
110
  LCB_INTERNAL_API
@@ -93,15 +113,15 @@ void lcbtrace_span_add_system_tags(lcbtrace_SPAN *span, lcb_settings *settings,
93
113
  if (!span) {
94
114
  return;
95
115
  }
96
- lcbtrace_span_add_tag_str(span, LCBTRACE_TAG_SERVICE, service);
116
+ span->add_tag(LCBTRACE_TAG_SERVICE, 0, service);
97
117
  std::string client_string(LCB_CLIENT_ID);
98
118
  if (settings->client_string) {
99
119
  client_string += " ";
100
120
  client_string += settings->client_string;
101
121
  }
102
- lcbtrace_span_add_tag_str(span, LCBTRACE_TAG_COMPONENT, client_string.c_str());
122
+ span->add_tag(LCBTRACE_TAG_COMPONENT, 0, client_string.c_str(), client_string.size());
103
123
  if (settings->bucket) {
104
- lcbtrace_span_add_tag_str(span, LCBTRACE_TAG_DB_INSTANCE, settings->bucket);
124
+ span->add_tag(LCBTRACE_TAG_DB_INSTANCE, 0, settings->bucket);
105
125
  }
106
126
  }
107
127
 
@@ -189,72 +209,108 @@ uint64_t lcbtrace_span_get_trace_id(lcbtrace_SPAN *span)
189
209
  LIBCOUCHBASE_API
190
210
  lcb_error_t lcbtrace_span_get_tag_str(lcbtrace_SPAN *span, const char *name, char **value, size_t *nvalue)
191
211
  {
192
- if (!span) {
212
+ if (!span || name == NULL || nvalue == NULL || value == NULL) {
193
213
  return LCB_EINVAL;
194
214
  }
195
- Json::Value &val = span->tags[name];
196
- if (val.isString()) {
197
- std::string str = val.asString();
198
- if (*nvalue) {
199
- /* string has been pre-allocated */
200
- if (str.size() < *nvalue) {
201
- *nvalue = str.size();
215
+
216
+ sllist_iterator iter;
217
+ SLLIST_ITERFOR(&span->m_tags, &iter)
218
+ {
219
+ tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
220
+ if (strcmp(name, val->key.p) == 0) {
221
+ if (val->t != TAGVAL_STRING) {
222
+ return LCB_EINVAL;
202
223
  }
203
- } else {
204
- *nvalue = str.size();
205
- *value = (char *)calloc(*nvalue, sizeof(char));
224
+ *value = val->v.s.p;
225
+ *nvalue = val->v.s.l;
226
+ return LCB_SUCCESS;
206
227
  }
207
- str.copy(*value, *nvalue, 0);
208
- return LCB_SUCCESS;
209
228
  }
229
+
210
230
  return LCB_KEY_ENOENT;
211
231
  }
212
232
 
213
233
  LIBCOUCHBASE_API lcb_error_t lcbtrace_span_get_tag_uint64(lcbtrace_SPAN *span, const char *name, uint64_t *value)
214
234
  {
215
- if (!span) {
235
+ if (!span || name == NULL || value == NULL) {
216
236
  return LCB_EINVAL;
217
237
  }
218
- Json::Value &val = span->tags[name];
219
- if (val.isNumeric()) {
220
- *value = val.asUInt64();
221
- return LCB_SUCCESS;
238
+
239
+ sllist_iterator iter;
240
+ SLLIST_ITERFOR(&span->m_tags, &iter)
241
+ {
242
+ tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
243
+ if (strcmp(name, val->key.p) == 0) {
244
+ if (val->t != TAGVAL_UINT64) {
245
+ return LCB_EINVAL;
246
+ }
247
+ *value = val->v.u64;
248
+ return LCB_SUCCESS;
249
+ }
222
250
  }
251
+
223
252
  return LCB_KEY_ENOENT;
224
253
  }
225
254
 
226
255
  LIBCOUCHBASE_API lcb_error_t lcbtrace_span_get_tag_double(lcbtrace_SPAN *span, const char *name, double *value)
227
256
  {
228
- if (!span) {
257
+ if (!span || name == NULL || value == NULL) {
229
258
  return LCB_EINVAL;
230
259
  }
231
- Json::Value &val = span->tags[name];
232
- if (val.isNumeric()) {
233
- *value = val.asDouble();
234
- return LCB_SUCCESS;
260
+
261
+ sllist_iterator iter;
262
+ SLLIST_ITERFOR(&span->m_tags, &iter)
263
+ {
264
+ tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
265
+ if (strcmp(name, val->key.p) == 0) {
266
+ if (val->t != TAGVAL_DOUBLE) {
267
+ return LCB_EINVAL;
268
+ }
269
+ *value = val->v.d;
270
+ return LCB_SUCCESS;
271
+ }
235
272
  }
273
+
236
274
  return LCB_KEY_ENOENT;
237
275
  }
238
276
 
239
277
  LIBCOUCHBASE_API lcb_error_t lcbtrace_span_get_tag_bool(lcbtrace_SPAN *span, const char *name, int *value)
240
278
  {
241
- if (!span) {
279
+ if (!span || name == NULL || value == NULL) {
242
280
  return LCB_EINVAL;
243
281
  }
244
- Json::Value &val = span->tags[name];
245
- if (val.isBool()) {
246
- *value = val.asBool();
247
- return LCB_SUCCESS;
282
+
283
+ sllist_iterator iter;
284
+ SLLIST_ITERFOR(&span->m_tags, &iter)
285
+ {
286
+ tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
287
+ if (strcmp(name, val->key.p) == 0) {
288
+ if (val->t != TAGVAL_BOOL) {
289
+ return LCB_EINVAL;
290
+ }
291
+ *value = val->v.b;
292
+ return LCB_SUCCESS;
293
+ }
248
294
  }
295
+
249
296
  return LCB_KEY_ENOENT;
250
297
  }
251
298
 
252
299
  LIBCOUCHBASE_API int lcbtrace_span_has_tag(lcbtrace_SPAN *span, const char *name)
253
300
  {
254
- if (!span) {
301
+ if (!span || name == NULL) {
255
302
  return 0;
256
303
  }
257
- return span->tags.isMember(name);
304
+
305
+ sllist_iterator iter;
306
+ SLLIST_ITERFOR(&span->m_tags, &iter)
307
+ {
308
+ tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
309
+ if (strcmp(name, val->key.p) == 0) {
310
+ return 1;
311
+ }
312
+ }
313
+ return 0;
258
314
  }
259
315
 
260
316
  using namespace lcb::trace;
@@ -265,8 +321,9 @@ Span::Span(lcbtrace_TRACER *tracer, const char *opname, uint64_t start, lcbtrace
265
321
  m_start = start ? start : lcbtrace_now();
266
322
  m_span_id = lcb_next_rand64();
267
323
  m_orphaned = false;
268
- add_tag(LCBTRACE_TAG_DB_TYPE, "couchbase");
269
- add_tag(LCBTRACE_TAG_SPAN_KIND, "client");
324
+ memset(&m_tags, 0, sizeof(m_tags));
325
+ add_tag(LCBTRACE_TAG_DB_TYPE, 0, "couchbase");
326
+ add_tag(LCBTRACE_TAG_SPAN_KIND, 0, "client");
270
327
 
271
328
  if (other != NULL && ref == LCBTRACE_REF_CHILD_OF) {
272
329
  m_parent = other;
@@ -275,6 +332,23 @@ Span::Span(lcbtrace_TRACER *tracer, const char *opname, uint64_t start, lcbtrace
275
332
  }
276
333
  }
277
334
 
335
+ Span::~Span()
336
+ {
337
+ sllist_iterator iter;
338
+ SLLIST_ITERFOR(&m_tags, &iter)
339
+ {
340
+ tag_value *val = SLLIST_ITEM(iter.cur, tag_value, slnode);
341
+ sllist_iter_remove(&m_tags, &iter);
342
+ if (val->key.need_free) {
343
+ free(val->key.p);
344
+ }
345
+ if (val->t == TAGVAL_STRING) {
346
+ free(val->v.s.p);
347
+ }
348
+ free(val);
349
+ }
350
+ }
351
+
278
352
  void Span::finish(uint64_t now)
279
353
  {
280
354
  m_finish = now ? now : lcbtrace_now();
@@ -283,7 +357,65 @@ void Span::finish(uint64_t now)
283
357
  }
284
358
  }
285
359
 
286
- template < typename T > void Span::add_tag(const char *name, T value)
360
+ void Span::add_tag(const char *name, int copy, const char *value)
361
+ {
362
+ add_tag(name, copy, value, strlen(value));
363
+ }
364
+
365
+ void Span::add_tag(const char *name, int copy, const char *value, size_t value_len)
366
+ {
367
+ tag_value *val = (tag_value *)calloc(1, sizeof(tag_value));
368
+ val->t = TAGVAL_STRING;
369
+ val->key.need_free = copy;
370
+ if (copy) {
371
+ val->key.p = strdup(name);
372
+ } else {
373
+ val->key.p = (char *)name;
374
+ }
375
+ val->v.s.p = (char *)calloc(value_len, sizeof(char));
376
+ val->v.s.l = value_len;
377
+ memcpy(val->v.s.p, value, value_len);
378
+ sllist_append(&m_tags, &val->slnode);
379
+ }
380
+
381
+ void Span::add_tag(const char *name, int copy, uint64_t value)
287
382
  {
288
- tags[name] = value;
383
+ tag_value *val = (tag_value *)calloc(1, sizeof(tag_value));
384
+ val->t = TAGVAL_UINT64;
385
+ val->key.need_free = copy;
386
+ if (copy) {
387
+ val->key.p = strdup(name);
388
+ } else {
389
+ val->key.p = (char *)name;
390
+ }
391
+ val->v.u64 = value;
392
+ sllist_append(&m_tags, &val->slnode);
393
+ }
394
+
395
+ void Span::add_tag(const char *name, int copy, double value)
396
+ {
397
+ tag_value *val = (tag_value *)calloc(1, sizeof(tag_value));
398
+ val->t = TAGVAL_DOUBLE;
399
+ val->key.need_free = copy;
400
+ if (copy) {
401
+ val->key.p = strdup(name);
402
+ } else {
403
+ val->key.p = (char *)name;
404
+ }
405
+ val->v.d = value;
406
+ sllist_append(&m_tags, &val->slnode);
407
+ }
408
+
409
+ void Span::add_tag(const char *name, int copy, bool value)
410
+ {
411
+ tag_value *val = (tag_value *)calloc(1, sizeof(tag_value));
412
+ val->t = TAGVAL_BOOL;
413
+ val->key.need_free = copy;
414
+ if (copy) {
415
+ val->key.p = strdup(name);
416
+ } else {
417
+ val->key.p = (char *)name;
418
+ }
419
+ val->v.b = value;
420
+ sllist_append(&m_tags, &val->slnode);
289
421
  }