couchbase 3.2.5 → 3.2.6

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.
@@ -32,6 +32,26 @@
32
32
  #define LOGARGS(ssl, lvl) ((lcbio_SOCKET *)SSL_get_app_data(ssl))->settings, "SSL", lvl, __FILE__, __LINE__
33
33
  static char *global_event = "dummy event for ssl";
34
34
 
35
+ static const char *capella_ca_cert = "-----BEGIN CERTIFICATE-----\n"
36
+ "MIIDFTCCAf2gAwIBAgIRANLVkgOvtaXiQJi0V6qeNtswDQYJKoZIhvcNAQELBQAw\n"
37
+ "JDESMBAGA1UECgwJQ291Y2hiYXNlMQ4wDAYDVQQLDAVDbG91ZDAeFw0xOTEyMDYy\n"
38
+ "MjEyNTlaFw0yOTEyMDYyMzEyNTlaMCQxEjAQBgNVBAoMCUNvdWNoYmFzZTEOMAwG\n"
39
+ "A1UECwwFQ2xvdWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfvOIi\n"
40
+ "enG4Dp+hJu9asdxEMRmH70hDyMXv5ZjBhbo39a42QwR59y/rC/sahLLQuNwqif85\n"
41
+ "Fod1DkqgO6Ng3vecSAwyYVkj5NKdycQu5tzsZkghlpSDAyI0xlIPSQjoORA/pCOU\n"
42
+ "WOpymA9dOjC1bo6rDyw0yWP2nFAI/KA4Z806XeqLREuB7292UnSsgFs4/5lqeil6\n"
43
+ "rL3ooAw/i0uxr/TQSaxi1l8t4iMt4/gU+W52+8Yol0JbXBTFX6itg62ppb/Eugmn\n"
44
+ "mQRMgL67ccZs7cJ9/A0wlXencX2ohZQOR3mtknfol3FH4+glQFn27Q4xBCzVkY9j\n"
45
+ "KQ20T1LgmGSngBInAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\n"
46
+ "FJQOBPvrkU2In1Sjoxt97Xy8+cKNMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0B\n"
47
+ "AQsFAAOCAQEARgM6XwcXPLSpFdSf0w8PtpNGehmdWijPM3wHb7WZiS47iNen3oq8\n"
48
+ "m2mm6V3Z57wbboPpfI+VEzbhiDcFfVnK1CXMC0tkF3fnOG1BDDvwt4jU95vBiNjY\n"
49
+ "xdzlTP/Z+qr0cnVbGBSZ+fbXstSiRaaAVcqQyv3BRvBadKBkCyPwo+7svQnScQ5P\n"
50
+ "Js7HEHKVms5tZTgKIw1fbmgR2XHleah1AcANB+MAPBCcTgqurqr5G7W2aPSBLLGA\n"
51
+ "fRIiVzm7VFLc7kWbp7ENH39HVG6TZzKnfl9zJYeiklo5vQQhGSMhzBsO70z4RRzi\n"
52
+ "DPFAN/4qZAgD5q3AFNIq2WWADFQGSwVJhg==\n"
53
+ "-----END CERTIFICATE-----\n";
54
+
35
55
  /******************************************************************************
36
56
  ******************************************************************************
37
57
  ** Boilerplate lcbio_TABLE Wrappers **
@@ -221,6 +241,9 @@ static void log_callback(const SSL *ssl, int where, int ret)
221
241
  {
222
242
  int should_log = 0;
223
243
  lcbio_SOCKET *sock = SSL_get_app_data(ssl);
244
+ if (sock == NULL) {
245
+ return;
246
+ }
224
247
  /* Ignore low-level SSL stuff */
225
248
 
226
249
  if (where & SSL_CB_ALERT) {
@@ -298,6 +321,48 @@ static long decode_ssl_protocol(const char *protocol)
298
321
  return disallow;
299
322
  }
300
323
 
324
+ static lcb_STATUS add_certificate_authority(const lcb_settings *settings, SSL_CTX *ctx, const char *certificate_value,
325
+ int certificate_length)
326
+ {
327
+ lcb_STATUS rc = LCB_SUCCESS;
328
+ ERR_clear_error();
329
+
330
+ BIO *bio = BIO_new_mem_buf(certificate_value, certificate_length);
331
+ if (bio) {
332
+ X509_STORE *store = SSL_CTX_get_cert_store(ctx);
333
+ if (store) {
334
+ for (int added = 0;; added = 1) {
335
+ X509 *cert = PEM_read_bio_X509(bio, 0, 0, 0);
336
+ if (!cert) {
337
+ unsigned long err = ERR_get_error();
338
+ if (added && ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) {
339
+ break;
340
+ }
341
+ lcb_log(LOGARGS_S(settings, LCB_LOG_ERROR),
342
+ "Unable to load default certificate: lib=%s, func=%s, reason=%s", ERR_lib_error_string(err),
343
+ ERR_func_error_string(err), ERR_reason_error_string(err));
344
+ rc = LCB_ERR_SSL_ERROR;
345
+ goto GT_CLEANUP;
346
+ }
347
+
348
+ int ok = X509_STORE_add_cert(store, cert);
349
+ X509_free(cert);
350
+ if (ok != 1) {
351
+ unsigned long err = ERR_get_error();
352
+ lcb_log(LOGARGS_S(settings, LCB_LOG_ERROR),
353
+ "Unable to add default certificate: lib=%s, func=%s, reason=%s", ERR_lib_error_string(err),
354
+ ERR_func_error_string(err), ERR_reason_error_string(err));
355
+ rc = LCB_ERR_SSL_ERROR;
356
+ goto GT_CLEANUP;
357
+ }
358
+ }
359
+ }
360
+ }
361
+ GT_CLEANUP:
362
+ BIO_free(bio);
363
+ return rc;
364
+ }
365
+
301
366
  lcbio_pSSLCTX lcbio_ssl_new(const char *tsfile, const char *cafile, const char *keyfile, int noverify, lcb_STATUS *errp,
302
367
  lcb_settings *settings)
303
368
  {
@@ -351,28 +416,41 @@ lcbio_pSSLCTX lcbio_ssl_new(const char *tsfile, const char *cafile, const char *
351
416
  }
352
417
  #endif
353
418
 
354
- if (cafile || tsfile) {
419
+ if (tsfile) {
355
420
  lcb_log(LOGARGS_S(settings, LCB_LOG_DEBUG), "Load verify locations from \"%s\"", tsfile ? tsfile : cafile);
356
421
  if (!SSL_CTX_load_verify_locations(ret->ctx, tsfile ? tsfile : cafile, NULL)) {
357
422
  *errp = LCB_ERR_SSL_ERROR;
358
423
  goto GT_ERR;
359
424
  }
360
- if (cafile && keyfile) {
361
- lcb_log(LOGARGS_S(settings, LCB_LOG_DEBUG), "Authenticate with key \"%s\", cert \"%s\"", keyfile, cafile);
362
- if (!SSL_CTX_use_certificate_chain_file(ret->ctx, cafile)) {
363
- *errp = LCB_ERR_SSL_ERROR;
364
- goto GT_ERR;
365
- }
366
- if (!SSL_CTX_use_PrivateKey_file(ret->ctx, keyfile, SSL_FILETYPE_PEM)) {
367
- lcb_log(LOGARGS_S(settings, LCB_LOG_ERROR), "Unable to load private key \"%s\"", keyfile);
368
- *errp = LCB_ERR_SSL_ERROR;
369
- goto GT_ERR;
370
- }
371
- if (!SSL_CTX_check_private_key(ret->ctx)) {
372
- lcb_log(LOGARGS_S(settings, LCB_LOG_ERROR), "Unable to verify private key \"%s\"", keyfile);
373
- *errp = LCB_ERR_SSL_ERROR;
374
- goto GT_ERR;
375
- }
425
+ } else {
426
+ lcb_log(LOGARGS_S(settings, LCB_LOG_DEBUG), "Use default CA for TLS verify");
427
+ if (SSL_CTX_set_default_verify_paths(ret->ctx) != 1) {
428
+ unsigned long err = ERR_get_error();
429
+ lcb_log(LOGARGS_S(settings, LCB_LOG_WARN), "Unable to load system certificates: lib=%s, reason=%s",
430
+ ERR_lib_error_string(err), ERR_reason_error_string(err));
431
+ }
432
+ // add the capella Root CA if no other CA was specified.
433
+ *errp = add_certificate_authority(settings, ret->ctx, capella_ca_cert, strlen(capella_ca_cert));
434
+ if (*errp != LCB_SUCCESS) {
435
+ goto GT_ERR;
436
+ }
437
+ }
438
+
439
+ if (cafile && keyfile) {
440
+ lcb_log(LOGARGS_S(settings, LCB_LOG_DEBUG), "Authenticate with key \"%s\", cert \"%s\"", keyfile, cafile);
441
+ if (!SSL_CTX_use_certificate_chain_file(ret->ctx, cafile)) {
442
+ *errp = LCB_ERR_SSL_ERROR;
443
+ goto GT_ERR;
444
+ }
445
+ if (!SSL_CTX_use_PrivateKey_file(ret->ctx, keyfile, SSL_FILETYPE_PEM)) {
446
+ lcb_log(LOGARGS_S(settings, LCB_LOG_ERROR), "Unable to load private key \"%s\"", keyfile);
447
+ *errp = LCB_ERR_SSL_ERROR;
448
+ goto GT_ERR;
449
+ }
450
+ if (!SSL_CTX_check_private_key(ret->ctx)) {
451
+ lcb_log(LOGARGS_S(settings, LCB_LOG_ERROR), "Unable to verify private key \"%s\"", keyfile);
452
+ *errp = LCB_ERR_SSL_ERROR;
453
+ goto GT_ERR;
376
454
  }
377
455
  }
378
456
 
@@ -422,15 +500,25 @@ GT_ERR:
422
500
  return NULL;
423
501
  }
424
502
 
503
+ struct proto_ctx_ssl {
504
+ lcbio_PROTOCTX proto;
505
+ SSL *ssl;
506
+ };
507
+
425
508
  static void noop_dtor(lcbio_PROTOCTX *arg)
426
509
  {
427
- free(arg);
510
+ if (!arg) {
511
+ return;
512
+ }
513
+ struct proto_ctx_ssl *sproto = (struct proto_ctx_ssl *)arg;
514
+ SSL_set_app_data(sproto->ssl, NULL);
515
+ free(sproto);
428
516
  }
429
517
 
430
518
  lcb_STATUS lcbio_ssl_apply(lcbio_SOCKET *sock, lcbio_pSSLCTX sctx)
431
519
  {
432
520
  lcbio_pTABLE old_iot = sock->io, new_iot;
433
- lcbio_PROTOCTX *sproto;
521
+ struct proto_ctx_ssl *sproto;
434
522
 
435
523
  if (old_iot->model == LCB_IOMODEL_EVENT) {
436
524
  new_iot = lcbio_Essl_new(old_iot, sock->u.fd, sctx->ctx);
@@ -440,12 +528,13 @@ lcb_STATUS lcbio_ssl_apply(lcbio_SOCKET *sock, lcbio_pSSLCTX sctx)
440
528
 
441
529
  if (new_iot) {
442
530
  sproto = calloc(1, sizeof(*sproto));
443
- sproto->id = LCBIO_PROTOCTX_SSL;
444
- sproto->dtor = noop_dtor;
445
- lcbio_protoctx_add(sock, sproto);
531
+ sproto->proto.id = LCBIO_PROTOCTX_SSL;
532
+ sproto->proto.dtor = noop_dtor;
533
+ lcbio_protoctx_add(sock, &sproto->proto);
446
534
  lcbio_table_unref(old_iot);
447
535
  sock->io = new_iot;
448
536
  /* just for logging */
537
+ sproto->ssl = ((lcbio_XSSL *)new_iot)->ssl;
449
538
  SSL_set_app_data(((lcbio_XSSL *)new_iot)->ssl, sock);
450
539
  return LCB_SUCCESS;
451
540
 
@@ -932,12 +932,19 @@ char *lcbvb_save_json(lcbvb_CONFIG *cfg)
932
932
  cJSON *tmp = NULL, *nodes = NULL;
933
933
  cJSON *root = cJSON_CreateObject();
934
934
 
935
- if (cfg->dtype == LCBVB_DIST_VBUCKET) {
936
- tmp = cJSON_CreateString("vbucket");
937
- } else {
938
- tmp = cJSON_CreateString("ketama");
935
+ switch (cfg->dtype) {
936
+ case LCBVB_DIST_VBUCKET:
937
+ tmp = cJSON_CreateString("vbucket");
938
+ break;
939
+ case LCBVB_DIST_KETAMA:
940
+ tmp = cJSON_CreateString("ketama");
941
+ break;
942
+ default:
943
+ break;
944
+ }
945
+ if (tmp) {
946
+ cJSON_AddItemToObject(root, "nodeLocator", tmp);
939
947
  }
940
- cJSON_AddItemToObject(root, "nodeLocator", tmp);
941
948
 
942
949
  if (cfg->buuid) {
943
950
  tmp = cJSON_CreateString(cfg->buuid);
@@ -951,8 +958,10 @@ char *lcbvb_save_json(lcbvb_CONFIG *cfg)
951
958
  tmp = cJSON_CreateInt64(cfg->revid);
952
959
  cJSON_AddItemToObject(root, "rev", tmp);
953
960
  }
954
- tmp = cJSON_CreateString(cfg->bname);
955
- cJSON_AddItemToObject(root, "name", tmp);
961
+ if (cfg->bname != NULL) {
962
+ tmp = cJSON_CreateString(cfg->bname);
963
+ cJSON_AddItemToObject(root, "name", tmp);
964
+ }
956
965
 
957
966
  nodes = cJSON_CreateArray();
958
967
  cJSON_AddItemToObject(root, "nodesExt", nodes);
@@ -173,7 +173,7 @@ MACRO(DEFINE_MOCKTEST plugin test)
173
173
  --gtest_filter="ContaminatingUnitTest.*"
174
174
  --gtest_throw_on_failure=1
175
175
  --gtest_print_time=1
176
- --gtest_output=xml:"${PROJECT_BINARY_DIR}/REPORT_${plugin}_${test}.xml")
176
+ --gtest_output=xml:"${PROJECT_BINARY_DIR}/REPORT_${plugin}_${test}_contaminating.xml")
177
177
  SET_TESTS_PROPERTIES(check-contaminating-${plugin}-${test} PROPERTIES LABELS "contaminating" )
178
178
  ENDMACRO()
179
179
 
@@ -430,6 +430,9 @@ static void statsCallback(lcb_INSTANCE *instance, lcb_CALLBACK_TYPE, const lcb_R
430
430
  case 1:
431
431
  version = MockEnvironment::VERSION_71;
432
432
  break;
433
+ case 2:
434
+ version = MockEnvironment::VERSION_72;
435
+ break;
433
436
  default:
434
437
  break;
435
438
  }
@@ -248,6 +248,7 @@ class MockEnvironment : public ::testing::Environment
248
248
  VERSION_66 = 12,
249
249
  VERSION_70 = 13,
250
250
  VERSION_71 = 14,
251
+ VERSION_72 = 15,
251
252
  };
252
253
 
253
254
  void SetUp() override;
@@ -89,6 +89,7 @@ TEST_F(RateLimitTest, testRateLimitsKVNumOps)
89
89
  {
90
90
  SKIP_IF_MOCK()
91
91
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_71)
92
+ SKIP_IF_CLUSTER_VERSION_IS_HIGHER_THAN(MockEnvironment::VERSION_72)
92
93
  HandleWrap hw;
93
94
  lcb_INSTANCE *instance;
94
95
  createConnection(hw, &instance);
@@ -131,6 +132,7 @@ TEST_F(RateLimitTest, testRateLimitsKVIngress)
131
132
  {
132
133
  SKIP_IF_MOCK()
133
134
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_71)
135
+ SKIP_IF_CLUSTER_VERSION_IS_HIGHER_THAN(MockEnvironment::VERSION_72)
134
136
  HandleWrap hw;
135
137
  lcb_INSTANCE *instance;
136
138
  createConnection(hw, &instance);
@@ -162,6 +164,7 @@ TEST_F(RateLimitTest, testRateLimitsKVEgress)
162
164
  {
163
165
  SKIP_IF_MOCK()
164
166
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_71)
167
+ SKIP_IF_CLUSTER_VERSION_IS_HIGHER_THAN(MockEnvironment::VERSION_72)
165
168
  HandleWrap hw;
166
169
  lcb_INSTANCE *instance;
167
170
  createConnection(hw, &instance);
@@ -198,6 +201,7 @@ TEST_F(RateLimitTest, testRateLimitsKVMaxConnections)
198
201
  {
199
202
  SKIP_IF_MOCK()
200
203
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_71)
204
+ SKIP_IF_CLUSTER_VERSION_IS_HIGHER_THAN(MockEnvironment::VERSION_72)
201
205
  HandleWrap hw;
202
206
  lcb_INSTANCE *instance;
203
207
  createConnection(hw, &instance);
@@ -438,6 +442,7 @@ TEST_F(RateLimitTest, testRateLimitsKVScopeDataSize)
438
442
  {
439
443
  SKIP_IF_MOCK()
440
444
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_71)
445
+ SKIP_IF_CLUSTER_VERSION_IS_HIGHER_THAN(MockEnvironment::VERSION_72)
441
446
  HandleWrap hw;
442
447
  lcb_INSTANCE *instance;
443
448
  createConnection(hw, &instance);
@@ -478,6 +483,7 @@ TEST_F(RateLimitTest, testRateLimitsQueryNumIndexes)
478
483
  {
479
484
  SKIP_IF_MOCK()
480
485
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_71)
486
+ SKIP_IF_CLUSTER_VERSION_IS_HIGHER_THAN(MockEnvironment::VERSION_72)
481
487
  HandleWrap hw;
482
488
  lcb_INSTANCE *instance;
483
489
  createConnection(hw, &instance);
@@ -527,6 +533,7 @@ TEST_F(RateLimitTest, testRateLimitsSearchNumQueries)
527
533
  {
528
534
  SKIP_IF_MOCK()
529
535
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_71)
536
+ SKIP_IF_CLUSTER_VERSION_IS_HIGHER_THAN(MockEnvironment::VERSION_72)
530
537
  HandleWrap hw;
531
538
  lcb_INSTANCE *instance;
532
539
  createConnection(hw, &instance);
@@ -576,6 +583,7 @@ TEST_F(RateLimitTest, testRateLimitsSearchEgress)
576
583
  {
577
584
  SKIP_IF_MOCK()
578
585
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_71)
586
+ SKIP_IF_CLUSTER_VERSION_IS_HIGHER_THAN(MockEnvironment::VERSION_72)
579
587
  HandleWrap hw;
580
588
  lcb_INSTANCE *instance;
581
589
  createConnection(hw, &instance);
@@ -631,6 +639,7 @@ TEST_F(RateLimitTest, testRateLimitsSearchIngress)
631
639
  {
632
640
  SKIP_IF_MOCK()
633
641
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_71)
642
+ SKIP_IF_CLUSTER_VERSION_IS_HIGHER_THAN(MockEnvironment::VERSION_72)
634
643
  HandleWrap hw;
635
644
  lcb_INSTANCE *instance;
636
645
  createConnection(hw, &instance);
@@ -684,6 +693,7 @@ TEST_F(RateLimitTest, testRateLimitsSearchConcurrentRequests)
684
693
  {
685
694
  SKIP_IF_MOCK()
686
695
  SKIP_IF_CLUSTER_VERSION_IS_LOWER_THAN(MockEnvironment::VERSION_71)
696
+ SKIP_IF_CLUSTER_VERSION_IS_HIGHER_THAN(MockEnvironment::VERSION_72)
687
697
  HandleWrap hw;
688
698
  lcb_INSTANCE *instance;
689
699
  createConnection(hw, &instance);
@@ -726,4 +736,4 @@ TEST_F(RateLimitTest, testRateLimitsSearchConcurrentRequests)
726
736
  ASSERT_TRUE(found_error);
727
737
 
728
738
  drop_user(instance, username);
729
- }
739
+ }
@@ -75,7 +75,7 @@ IF(NOT WIN32)
75
75
  LIST(APPEND CBC_SUBCOMMANDS
76
76
  cat create observe observe-seqno incr decr hash lock
77
77
  unlock rm stats version verbosity view n1ql admin ping
78
- bucket-create bucket-delete bucket-flush connstr write-config strerror
78
+ bucket-list bucket-create bucket-delete bucket-flush connstr write-config strerror
79
79
  touch role-list user-list user-upsert user-delete watch
80
80
  mcversion keygen collection-manifest collection-id
81
81
  )
@@ -827,6 +827,45 @@ class UserUpsertHandler : public AdminHandler
827
827
  std::string body;
828
828
  };
829
829
 
830
+ class BucketListHandler : public AdminHandler
831
+ {
832
+ public:
833
+ HANDLER_DESCRIPTION("List buckets")
834
+ HANDLER_USAGE("NAME [OPTIONS ...]")
835
+ BucketListHandler() : AdminHandler("bucket-list"), o_raw('r', "raw")
836
+ {
837
+ o_raw.description("Do not reformat output from server (display JSON response)");
838
+ }
839
+
840
+ protected:
841
+ void run() override;
842
+ void format();
843
+
844
+ void addOptions() override
845
+ {
846
+ AdminHandler::addOptions();
847
+ parser.addOption(o_raw);
848
+ }
849
+
850
+ std::string getURI() override
851
+ {
852
+ return "/pools/default/buckets";
853
+ }
854
+
855
+ std::string getContentType() override
856
+ {
857
+ return "application/json";
858
+ }
859
+
860
+ lcb_HTTP_METHOD getMethod() override
861
+ {
862
+ return LCB_HTTP_METHOD_GET;
863
+ }
864
+
865
+ private:
866
+ cliopts::BoolOption o_raw;
867
+ };
868
+
830
869
  class BucketCreateHandler : public AdminHandler
831
870
  {
832
871
  public:
@@ -458,6 +458,7 @@ class ThreadContext
458
458
  lcb_STATUS rc = lcb_query(m_instance, &qctx, m_cmd);
459
459
  if (rc != LCB_SUCCESS) {
460
460
  log_error(rc, query.payload.c_str(), query.payload.size());
461
+ lcb_tick_nowait(m_instance);
461
462
  } else {
462
463
  lcb_wait(m_instance, LCB_WAIT_DEFAULT);
463
464
  m_metrics.lock();
@@ -104,7 +104,7 @@ class Configuration
104
104
  o_startAt("start-at"), o_rateLimit("rate-limit"), o_userdocs("docs"), o_writeJson("json"),
105
105
  o_templatePairs("template"), o_subdoc("subdoc"), o_noop("noop"), o_sdPathCount("pathcount"),
106
106
  o_populateOnly("populate-only"), o_exptime("expiry"), o_collection("collection"), o_durability("durability"),
107
- o_persist("persist-to"), o_replicate("replicate-to"), o_lock("lock")
107
+ o_persist("persist-to"), o_replicate("replicate-to"), o_lock("lock"), o_randSpace("rand-space-per-thread")
108
108
  {
109
109
  o_multiSize.setDefault(100).abbrev('B').description("Number of operations to batch");
110
110
  o_numItems.setDefault(1000).abbrev('I').description("Number of items to operate on");
@@ -138,6 +138,8 @@ class Configuration
138
138
  o_replicate.description("Wait until item is replicated to this number of nodes (-1 for all replicas)")
139
139
  .setDefault(0);
140
140
  o_lock.description("Lock keys for updates for given time (will not lock when set to zero)").setDefault(0);
141
+ o_randSpace.description("When set and --sequential is not set, threads will perform operations on different key"
142
+ " spaces").setDefault(false);
141
143
  params.getTimings().description("Enable command timings (second time to dump timings automatically)");
142
144
  }
143
145
 
@@ -218,25 +220,25 @@ class Configuration
218
220
 
219
221
  if (specs.empty()) {
220
222
  if (o_writeJson.result()) {
221
- docgen = new JsonDocGenerator(o_minSize.result(), o_maxSize.result(), o_randomBody.numSpecified());
223
+ docgen.reset(new JsonDocGenerator(o_minSize.result(), o_maxSize.result(), o_randomBody.numSpecified()));
222
224
  } else if (!userdocs.empty()) {
223
- docgen = new PresetDocGenerator(userdocs);
225
+ docgen.reset(new PresetDocGenerator(userdocs));
224
226
  } else {
225
- docgen = new RawDocGenerator(o_minSize.result(), o_maxSize.result(), o_randomBody.numSpecified());
227
+ docgen.reset(new RawDocGenerator(o_minSize.result(), o_maxSize.result(), o_randomBody.numSpecified()));
226
228
  }
227
229
  } else {
228
230
  if (o_writeJson.result()) {
229
231
  if (userdocs.empty()) {
230
- docgen = new PlaceholderJsonGenerator(o_minSize.result(), o_maxSize.result(), specs,
231
- o_randomBody.numSpecified());
232
+ docgen.reset(new PlaceholderJsonGenerator(o_minSize.result(), o_maxSize.result(), specs,
233
+ o_randomBody.numSpecified()));
232
234
  } else {
233
- docgen = new PlaceholderJsonGenerator(userdocs, specs);
235
+ docgen.reset(new PlaceholderJsonGenerator(userdocs, specs));
234
236
  }
235
237
  } else {
236
238
  if (userdocs.empty()) {
237
239
  throw std::runtime_error("Must provide documents with placeholders!");
238
240
  }
239
- docgen = new PlaceholderDocGenerator(userdocs, specs);
241
+ docgen.reset(new PlaceholderDocGenerator(userdocs, specs));
240
242
  }
241
243
  }
242
244
 
@@ -279,6 +281,7 @@ class Configuration
279
281
  parser.addOption(o_persist);
280
282
  parser.addOption(o_replicate);
281
283
  parser.addOption(o_lock);
284
+ parser.addOption(o_randSpace);
282
285
  params.addToParser(parser);
283
286
  depr.addOptions(parser);
284
287
  }
@@ -357,6 +360,10 @@ class Configuration
357
360
  {
358
361
  return o_exptime;
359
362
  }
363
+ bool useRandSpacePerThread()
364
+ {
365
+ return o_randSpace;
366
+ }
360
367
 
361
368
  uint32_t opsPerCycle{};
362
369
  uint32_t sdOpsPerCmd{};
@@ -365,7 +372,7 @@ class Configuration
365
372
  volatile int maxCycles{};
366
373
  bool shouldPopulate{};
367
374
  ConnParams params;
368
- const DocGeneratorBase *docgen{};
375
+ std::unique_ptr<DocGeneratorBase> docgen;
369
376
  vector<string> collections{};
370
377
  lcb_DURABILITY_LEVEL durabilityLevel{LCB_DURABILITYLEVEL_NONE};
371
378
  int replicateTo{};
@@ -411,6 +418,7 @@ class Configuration
411
418
  IntOption o_replicate;
412
419
 
413
420
  IntOption o_lock;
421
+ BoolOption o_randSpace;
414
422
  DeprecatedOptions depr;
415
423
  } config;
416
424
 
@@ -569,12 +577,14 @@ class KeyGenerator : public OpGenerator
569
577
  explicit KeyGenerator(int ix)
570
578
  : OpGenerator(ix), m_gencount(0), m_force_sequential(false), m_in_population(config.shouldPopulate)
571
579
  {
572
- srand(config.getRandomSeed());
580
+ if(!config.useRandSpacePerThread()) {
581
+ srand(config.getRandomSeed());
582
+ }
573
583
 
574
- m_genrandom = new SeqGenerator(config.firstKeyOffset(), config.getNumItems() + config.firstKeyOffset());
584
+ m_genrandom.reset(new SeqGenerator(config.firstKeyOffset(), config.getNumItems() + config.firstKeyOffset()));
575
585
 
576
- m_gensequence = new SeqGenerator(config.firstKeyOffset(), config.getNumItems() + config.firstKeyOffset(),
577
- config.getNumThreads(), ix);
586
+ m_gensequence.reset(new SeqGenerator(config.firstKeyOffset(), config.getNumItems() + config.firstKeyOffset(),
587
+ config.getNumThreads(), ix));
578
588
 
579
589
  if (m_in_population) {
580
590
  m_force_sequential = true;
@@ -701,16 +711,16 @@ class KeyGenerator : public OpGenerator
701
711
  }
702
712
  }
703
713
 
704
- SeqGenerator *m_genrandom;
705
- SeqGenerator *m_gensequence;
714
+ std::unique_ptr<SeqGenerator> m_genrandom;
715
+ std::unique_ptr<SeqGenerator> m_gensequence;
706
716
  size_t m_gencount;
707
717
 
708
718
  bool m_force_sequential;
709
719
  bool m_in_population;
710
720
  NextOp::Mode m_mode_read;
711
721
  NextOp::Mode m_mode_write;
712
- GeneratorState *m_local_genstate;
713
- SubdocGeneratorState *m_sdgenstate;
722
+ std::unique_ptr<GeneratorState> m_local_genstate;
723
+ std::unique_ptr<SubdocGeneratorState> m_sdgenstate;
714
724
  };
715
725
 
716
726
  #define OPFLAGS_LOCKED 0x01
@@ -721,16 +731,15 @@ class ThreadContext
721
731
  ThreadContext(lcb_INSTANCE *handle, int ix) : niter(0), instance(handle)
722
732
  {
723
733
  if (config.isNoop()) {
724
- gen = new NoopGenerator(ix);
734
+ gen.reset(new NoopGenerator(ix));
725
735
  } else {
726
- gen = new KeyGenerator(ix);
736
+ gen.reset(new KeyGenerator(ix));
727
737
  }
728
738
  }
729
739
 
730
740
  ~ThreadContext()
731
741
  {
732
- delete gen;
733
- gen = nullptr;
742
+ lcb_destroy(instance);
734
743
  }
735
744
 
736
745
  bool inPopulation()
@@ -993,7 +1002,7 @@ class ThreadContext
993
1002
  previous_time = now;
994
1003
  }
995
1004
 
996
- OpGenerator *gen;
1005
+ std::unique_ptr<OpGenerator> gen;
997
1006
  size_t niter;
998
1007
  lcb_STATUS error{LCB_SUCCESS};
999
1008
  lcb_INSTANCE *instance{nullptr};
@@ -1197,7 +1206,8 @@ static void storeCallback(lcb_INSTANCE *instance, int, const lcb_RESPSTORE *resp
1197
1206
  updateOpsPerSecDisplay();
1198
1207
  }
1199
1208
 
1200
- std::list<ThreadContext *> contexts;
1209
+ std::list<InstanceCookie> cookies;
1210
+ std::list<ThreadContext> contexts;
1201
1211
 
1202
1212
  extern "C" {
1203
1213
  typedef void (*handler_t)(int);
@@ -1205,8 +1215,8 @@ typedef void (*handler_t)(int);
1205
1215
  static void dump_metrics()
1206
1216
  {
1207
1217
  std::list<ThreadContext *>::iterator it;
1208
- for (it = contexts.begin(); it != contexts.end(); ++it) {
1209
- lcb_INSTANCE *instance = (*it)->getInstance();
1218
+ for (auto& context : contexts) {
1219
+ lcb_INSTANCE *instance = context.getInstance();
1210
1220
  lcb_CMDDIAG *req;
1211
1221
  lcb_cmddiag_create(&req);
1212
1222
  lcb_cmddiag_prettify(req, true);
@@ -1284,10 +1294,6 @@ static void sigint_handler(int)
1284
1294
  return;
1285
1295
  }
1286
1296
 
1287
- std::list<ThreadContext *>::iterator it;
1288
- for (it = contexts.begin(); it != contexts.end(); ++it) {
1289
- delete *it;
1290
- }
1291
1297
  contexts.clear();
1292
1298
  exit(EXIT_FAILURE);
1293
1299
  }
@@ -1315,10 +1321,10 @@ static void start_worker(ThreadContext *ctx)
1315
1321
  exit(EXIT_FAILURE);
1316
1322
  }
1317
1323
  }
1318
- static void join_worker(ThreadContext *ctx)
1324
+ static void join_worker(ThreadContext& ctx)
1319
1325
  {
1320
1326
  void *arg = nullptr;
1321
- int rc = pthread_join(ctx->thr, &arg);
1327
+ int rc = pthread_join(ctx.thr, &arg);
1322
1328
  if (rc != 0) {
1323
1329
  log("Couldn't join thread (%d)", errno);
1324
1330
  exit(EXIT_FAILURE);
@@ -1332,7 +1338,7 @@ static void start_worker(ThreadContext *ctx)
1332
1338
  {
1333
1339
  ctx->run();
1334
1340
  }
1335
- static void join_worker(ThreadContext *ctx)
1341
+ static void join_worker(ThreadContext& ctx)
1336
1342
  {
1337
1343
  (void)ctx;
1338
1344
  }
@@ -1373,6 +1379,9 @@ int main(int argc, char **argv)
1373
1379
  nthreads = 1;
1374
1380
  }
1375
1381
  #endif
1382
+ if(config.useRandSpacePerThread()) {
1383
+ srand(config.getRandomSeed());
1384
+ }
1376
1385
 
1377
1386
  lcb_CREATEOPTS *options = nullptr;
1378
1387
  ConnParams &cp = config.params;
@@ -1406,7 +1415,8 @@ int main(int argc, char **argv)
1406
1415
  lcb_cntl(instance, LCB_CNTL_SET, LCB_CNTL_ENABLE_COLLECTIONS, &use);
1407
1416
  }
1408
1417
 
1409
- auto *cookie = new InstanceCookie(instance);
1418
+ cookies.emplace_back(instance);
1419
+ auto* cookie = &cookies.back();
1410
1420
 
1411
1421
  lcb_connect(instance);
1412
1422
  lcb_wait(instance, LCB_WAIT_DEFAULT);
@@ -1418,9 +1428,9 @@ int main(int argc, char **argv)
1418
1428
  exit(EXIT_FAILURE);
1419
1429
  }
1420
1430
 
1421
- auto *ctx = new ThreadContext(instance, ii);
1431
+ contexts.emplace_back(instance, ii);
1432
+ auto* ctx = &contexts.back();
1422
1433
  cookie->setContext(ctx);
1423
- contexts.push_back(ctx);
1424
1434
  start_worker(ctx);
1425
1435
  }
1426
1436