couchbase 3.2.5 → 3.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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