couchbase 3.2.4 → 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.
Files changed (89) hide show
  1. package/binding.gyp +5 -0
  2. package/deps/lcb/CMakeLists.txt +28 -6
  3. package/deps/lcb/README.markdown +5 -9
  4. package/deps/lcb/RELEASE_NOTES.markdown +80 -5
  5. package/deps/lcb/cmake/Modules/GetVersionInfo.cmake +1 -1
  6. package/deps/lcb/doc/Doxyfile +1 -1
  7. package/deps/lcb/doc/cbc.markdown +10 -0
  8. package/deps/lcb/gyp_config/common/libcouchbase/configuration.h +3 -3
  9. package/deps/lcb/include/libcouchbase/couchbase.h +52 -0
  10. package/deps/lcb/include/libcouchbase/error.h +5 -2
  11. package/deps/lcb/libcouchbase.gyp +7 -1
  12. package/deps/lcb/packaging/rpm/libcouchbase.spec.in +1 -1
  13. package/deps/lcb/plugins/io/iocp/iocp_iops.h +1 -1
  14. package/deps/lcb/plugins/io/iocp/iocp_loop.c +3 -3
  15. package/deps/lcb/plugins/io/iocp/iocp_util.c +2 -2
  16. package/deps/lcb/src/bucketconfig/bc_file.cc +29 -15
  17. package/deps/lcb/src/capi/cmd_counter.hh +12 -0
  18. package/deps/lcb/src/capi/cmd_exists.hh +12 -0
  19. package/deps/lcb/src/capi/cmd_get.hh +12 -0
  20. package/deps/lcb/src/capi/cmd_get_replica.hh +14 -1
  21. package/deps/lcb/src/capi/cmd_query.cc +13 -0
  22. package/deps/lcb/src/capi/cmd_query.hh +22 -14
  23. package/deps/lcb/src/capi/cmd_remove.hh +12 -0
  24. package/deps/lcb/src/capi/cmd_store.hh +12 -0
  25. package/deps/lcb/src/capi/cmd_subdoc.hh +12 -0
  26. package/deps/lcb/src/capi/cmd_touch.hh +12 -0
  27. package/deps/lcb/src/capi/cmd_unlock.hh +12 -0
  28. package/deps/lcb/src/capi/collection_qualifier.hh +4 -9
  29. package/deps/lcb/src/instance.cc +19 -0
  30. package/deps/lcb/src/internal.h +2 -1
  31. package/deps/lcb/src/mcserver/negotiate.cc +3 -0
  32. package/deps/lcb/src/n1ql/n1ql.cc +5 -1
  33. package/deps/lcb/src/n1ql/query_handle.cc +55 -30
  34. package/deps/lcb/src/n1ql/query_handle.hh +14 -2
  35. package/deps/lcb/src/operations/counter.cc +12 -0
  36. package/deps/lcb/src/operations/exists.cc +12 -0
  37. package/deps/lcb/src/operations/get.cc +12 -0
  38. package/deps/lcb/src/operations/get_replica.cc +18 -6
  39. package/deps/lcb/src/operations/ping.cc +2 -2
  40. package/deps/lcb/src/operations/remove.cc +12 -0
  41. package/deps/lcb/src/operations/store.cc +12 -0
  42. package/deps/lcb/src/operations/subdoc.cc +12 -0
  43. package/deps/lcb/src/operations/touch.cc +12 -0
  44. package/deps/lcb/src/operations/unlock.cc +12 -0
  45. package/deps/lcb/src/search/search_handle.cc +1 -2
  46. package/deps/lcb/src/settings.cc +1 -0
  47. package/deps/lcb/src/ssl/ssl_common.c +111 -22
  48. package/deps/lcb/src/utilities.cc +21 -0
  49. package/deps/lcb/src/utilities.h +3 -0
  50. package/deps/lcb/src/vbucket/vbucket.c +16 -7
  51. package/deps/lcb/tests/CMakeLists.txt +1 -1
  52. package/deps/lcb/tests/iotests/mock-environment.cc +13 -1
  53. package/deps/lcb/tests/iotests/mock-environment.h +3 -1
  54. package/deps/lcb/tests/iotests/serverparams.h +7 -2
  55. package/deps/lcb/tests/iotests/t_ratelimit.cc +739 -0
  56. package/deps/lcb/tests/iotests/testutil.cc +174 -0
  57. package/deps/lcb/tests/iotests/testutil.h +53 -0
  58. package/deps/lcb/tools/CMakeLists.txt +1 -1
  59. package/deps/lcb/tools/cbc-handlers.h +39 -0
  60. package/deps/lcb/tools/cbc-n1qlback.cc +1 -0
  61. package/deps/lcb/tools/cbc-pillowfight.cc +45 -35
  62. package/deps/lcb/tools/cbc.cc +31 -0
  63. package/deps/lcb/tools/docgen/docgen.h +11 -10
  64. package/dist/analyticsexecutor.js +2 -2
  65. package/dist/analyticsindexmanager.js +3 -3
  66. package/dist/binarycollection.d.ts +17 -0
  67. package/dist/binding.js +1 -1
  68. package/dist/bindingutilities.js +5 -1
  69. package/dist/bucketmanager.d.ts +1 -22
  70. package/dist/bucketmanager.js +5 -5
  71. package/dist/cluster.js +1 -1
  72. package/dist/collection.js +6 -6
  73. package/dist/collectionmanager.js +2 -2
  74. package/dist/connection.js +3 -3
  75. package/dist/connspec.js +5 -1
  76. package/dist/couchbase.js +5 -1
  77. package/dist/httpexecutor.d.ts +1 -0
  78. package/dist/httpexecutor.js +5 -1
  79. package/dist/logging.js +1 -1
  80. package/dist/queryexecutor.js +3 -3
  81. package/dist/searchindexmanager.js +1 -1
  82. package/dist/usermanager.js +2 -2
  83. package/dist/utilities.d.ts +1 -2
  84. package/dist/utilities.js +9 -2
  85. package/dist/viewexecutor.js +1 -1
  86. package/package.json +1 -1
  87. package/src/uv-plugin-all.cpp +1 -0
  88. package/dist/cas.d.ts +0 -0
  89. package/dist/cas.js +0 -1
@@ -629,3 +629,177 @@ void TestMeter::destroy_lcb_meter()
629
629
  lcbmeter_ = nullptr;
630
630
  }
631
631
  }
632
+
633
+ void enforce_rate_limits(lcb_INSTANCE *instance)
634
+ {
635
+ (void)lcb_install_callback(instance, LCB_CALLBACK_HTTP, (lcb_RESPCALLBACK)http_callback);
636
+
637
+ lcb_CMDHTTP *cmd;
638
+ std::string path = "/internalSettings";
639
+ std::string body = "enforceLimits=true";
640
+
641
+ lcb_cmdhttp_create(&cmd, LCB_HTTP_TYPE_MANAGEMENT);
642
+ lcb_cmdhttp_method(cmd, LCB_HTTP_METHOD_POST);
643
+ lcb_cmdhttp_path(cmd, path.c_str(), path.size());
644
+ lcb_cmdhttp_body(cmd, body.c_str(), body.size());
645
+
646
+ http_result result{};
647
+ ASSERT_STATUS_EQ(LCB_SUCCESS, lcb_http(instance, &result, cmd));
648
+ lcb_cmdhttp_destroy(cmd);
649
+ ASSERT_STATUS_EQ(LCB_SUCCESS, lcb_wait(instance, LCB_WAIT_DEFAULT));
650
+ ASSERT_STATUS_EQ(LCB_SUCCESS, result.rc);
651
+ }
652
+
653
+ void create_rate_limited_user(lcb_INSTANCE *instance, const std::string &username, const rate_limits &limits)
654
+ {
655
+ (void)lcb_install_callback(instance, LCB_CALLBACK_HTTP, (lcb_RESPCALLBACK)http_callback);
656
+
657
+ lcb_CMDHTTP *cmd;
658
+ std::string path = "/settings/rbac/users/local/" + username;
659
+ std::string body = "password=password&roles=admin";
660
+ Json::Value json_limits;
661
+ if (limits.kv_limits.enforce) {
662
+ Json::Value kv_limits;
663
+ if (limits.kv_limits.num_connections > 0) {
664
+ kv_limits["num_connections"] = limits.kv_limits.num_connections;
665
+ }
666
+ if (limits.kv_limits.num_ops_per_min > 0) {
667
+ kv_limits["num_ops_per_min"] = limits.kv_limits.num_ops_per_min;
668
+ }
669
+ if (limits.kv_limits.ingress_mib_per_min > 0) {
670
+ kv_limits["ingress_mib_per_min"] = limits.kv_limits.ingress_mib_per_min;
671
+ }
672
+ if (limits.kv_limits.egress_mib_per_min > 0) {
673
+ kv_limits["egress_mib_per_min"] = limits.kv_limits.egress_mib_per_min;
674
+ }
675
+ json_limits["kv"] = kv_limits;
676
+ }
677
+ if (limits.query_limits.enforce) {
678
+ Json::Value query_limits;
679
+ if (limits.query_limits.num_concurrent_requests > 0) {
680
+ query_limits["num_concurrent_requests"] = limits.query_limits.num_concurrent_requests;
681
+ }
682
+ if (limits.query_limits.num_queries_per_min > 0) {
683
+ query_limits["num_queries_per_min"] = limits.query_limits.num_queries_per_min;
684
+ }
685
+ if (limits.query_limits.ingress_mib_per_min > 0) {
686
+ query_limits["ingress_mib_per_min"] = limits.query_limits.ingress_mib_per_min;
687
+ }
688
+ if (limits.query_limits.egress_mib_per_min > 0) {
689
+ query_limits["egress_mib_per_min"] = limits.query_limits.egress_mib_per_min;
690
+ }
691
+ json_limits["query"] = query_limits;
692
+ }
693
+ if (limits.search_limits.enforce) {
694
+ Json::Value fts_limits;
695
+ if (limits.search_limits.num_concurrent_requests > 0) {
696
+ fts_limits["num_concurrent_requests"] = limits.search_limits.num_concurrent_requests;
697
+ }
698
+ if (limits.search_limits.num_queries_per_min > 0) {
699
+ fts_limits["num_queries_per_min"] = limits.search_limits.num_queries_per_min;
700
+ }
701
+ if (limits.search_limits.ingress_mib_per_min > 0) {
702
+ fts_limits["ingress_mib_per_min"] = limits.search_limits.ingress_mib_per_min;
703
+ }
704
+ if (limits.search_limits.egress_mib_per_min > 0) {
705
+ fts_limits["egress_mib_per_min"] = limits.search_limits.egress_mib_per_min;
706
+ }
707
+ json_limits["fts"] = fts_limits;
708
+ }
709
+ std::string j_limits = Json::FastWriter().write(json_limits);
710
+ body += "&limits=" + j_limits;
711
+ std::string content_type = "application/x-www-form-urlencoded";
712
+
713
+ lcb_cmdhttp_create(&cmd, LCB_HTTP_TYPE_MANAGEMENT);
714
+ lcb_cmdhttp_method(cmd, LCB_HTTP_METHOD_PUT);
715
+ lcb_cmdhttp_path(cmd, path.c_str(), path.size());
716
+ lcb_cmdhttp_body(cmd, body.c_str(), body.size());
717
+ lcb_cmdhttp_content_type(cmd, content_type.c_str(), content_type.size());
718
+
719
+ http_result result{};
720
+ ASSERT_STATUS_EQ(LCB_SUCCESS, lcb_http(instance, &result, cmd));
721
+ lcb_cmdhttp_destroy(cmd);
722
+ ASSERT_STATUS_EQ(LCB_SUCCESS, lcb_wait(instance, LCB_WAIT_DEFAULT));
723
+ ASSERT_STATUS_EQ(LCB_SUCCESS, result.rc);
724
+ }
725
+
726
+ void create_rate_limited_scope(lcb_INSTANCE *instance, const std::string &bucket, std::string &scope,
727
+ const scope_rate_limits &limits)
728
+ {
729
+ (void)lcb_install_callback(instance, LCB_CALLBACK_HTTP, (lcb_RESPCALLBACK)http_callback);
730
+
731
+ lcb_CMDHTTP *cmd;
732
+ std::string path = "/pools/default/buckets/" + bucket + "/scopes";
733
+ std::string body = "name=" + scope;
734
+ Json::Value json_limits;
735
+ if (limits.kv_scope_limits.enforce) {
736
+ Json::Value kv_limits;
737
+ kv_limits["data_size"] = limits.kv_scope_limits.data_size;
738
+ json_limits["kv"] = kv_limits;
739
+ }
740
+ if (limits.index_scope_limits.enforce) {
741
+ Json::Value index_limits;
742
+ index_limits["num_indexes"] = limits.index_scope_limits.num_indexes;
743
+ json_limits["index"] = index_limits;
744
+ }
745
+ std::string j_limits = Json::FastWriter().write(json_limits);
746
+ body += "&limits=" + j_limits;
747
+ std::string content_type = "application/x-www-form-urlencoded";
748
+
749
+ lcb_cmdhttp_create(&cmd, LCB_HTTP_TYPE_MANAGEMENT);
750
+ lcb_cmdhttp_method(cmd, LCB_HTTP_METHOD_POST);
751
+ lcb_cmdhttp_path(cmd, path.c_str(), path.size());
752
+ lcb_cmdhttp_body(cmd, body.c_str(), body.size());
753
+ lcb_cmdhttp_content_type(cmd, content_type.c_str(), content_type.size());
754
+
755
+ http_result result{};
756
+ ASSERT_STATUS_EQ(LCB_SUCCESS, lcb_http(instance, &result, cmd));
757
+ lcb_cmdhttp_destroy(cmd);
758
+ ASSERT_STATUS_EQ(LCB_SUCCESS, lcb_wait(instance, LCB_WAIT_DEFAULT));
759
+ ASSERT_STATUS_EQ(LCB_SUCCESS, result.rc);
760
+ }
761
+
762
+ void drop_user(lcb_INSTANCE *instance, const std::string &username)
763
+ {
764
+ (void)lcb_install_callback(instance, LCB_CALLBACK_HTTP, (lcb_RESPCALLBACK)http_callback);
765
+
766
+ lcb_CMDHTTP *cmd;
767
+ std::string path = "/settings/rbac/users/local/" + username;
768
+
769
+ lcb_cmdhttp_create(&cmd, LCB_HTTP_TYPE_MANAGEMENT);
770
+ lcb_cmdhttp_method(cmd, LCB_HTTP_METHOD_DELETE);
771
+ lcb_cmdhttp_path(cmd, path.c_str(), path.size());
772
+
773
+ http_result result{};
774
+ ASSERT_STATUS_EQ(LCB_SUCCESS, lcb_http(instance, &result, cmd));
775
+ lcb_cmdhttp_destroy(cmd);
776
+ ASSERT_STATUS_EQ(LCB_SUCCESS, lcb_wait(instance, LCB_WAIT_DEFAULT));
777
+ ASSERT_STATUS_EQ(LCB_SUCCESS, result.rc);
778
+ }
779
+
780
+ void create_search_index(lcb_INSTANCE *instance, const std::string &index_name, const std::string &type,
781
+ const std::string &source_type, const std::string &source_name)
782
+ {
783
+ (void)lcb_install_callback(instance, LCB_CALLBACK_HTTP, (lcb_RESPCALLBACK)http_callback);
784
+
785
+ lcb_CMDHTTP *cmd;
786
+ std::string path = "/api/index/" + index_name;
787
+ Json::Value json_body;
788
+ json_body["name"] = index_name;
789
+ json_body["type"] = type;
790
+ json_body["sourceName"] = source_name;
791
+ json_body["sourceType"] = source_type;
792
+
793
+ auto body = Json::FastWriter().write(json_body);
794
+
795
+ lcb_cmdhttp_create(&cmd, LCB_HTTP_TYPE_SEARCH);
796
+ lcb_cmdhttp_method(cmd, LCB_HTTP_METHOD_PUT);
797
+ lcb_cmdhttp_path(cmd, path.c_str(), path.size());
798
+ lcb_cmdhttp_body(cmd, body.c_str(), body.size());
799
+
800
+ http_result result{};
801
+ ASSERT_STATUS_EQ(LCB_SUCCESS, lcb_http(instance, &result, cmd));
802
+ lcb_cmdhttp_destroy(cmd);
803
+ ASSERT_STATUS_EQ(LCB_SUCCESS, lcb_wait(instance, LCB_WAIT_DEFAULT));
804
+ ASSERT_STATUS_EQ(LCB_SUCCESS, result.rc);
805
+ }
@@ -323,4 +323,57 @@ class TestMeter
323
323
  bool enabled_{false};
324
324
  };
325
325
 
326
+ struct kv_rate_limits {
327
+ uint32_t num_connections{0};
328
+ uint32_t num_ops_per_min{0};
329
+ uint32_t ingress_mib_per_min{0};
330
+ uint32_t egress_mib_per_min{0};
331
+ bool enforce{false};
332
+ };
333
+
334
+ struct query_rate_limits {
335
+ uint32_t ingress_mib_per_min{0};
336
+ uint32_t egress_mib_per_min{0};
337
+ uint32_t num_concurrent_requests{0};
338
+ uint32_t num_queries_per_min{0};
339
+ bool enforce{false};
340
+ };
341
+
342
+ struct search_rate_limits {
343
+ uint32_t ingress_mib_per_min{0};
344
+ uint32_t egress_mib_per_min{0};
345
+ uint32_t num_concurrent_requests{0};
346
+ uint32_t num_queries_per_min{0};
347
+ bool enforce{false};
348
+ };
349
+
350
+ struct rate_limits {
351
+ kv_rate_limits kv_limits{};
352
+ query_rate_limits query_limits{};
353
+ search_rate_limits search_limits{};
354
+ };
355
+
356
+ struct kv_scope_rate_limits {
357
+ uint32_t data_size;
358
+ bool enforce{false};
359
+ };
360
+
361
+ struct index_scope_rate_limits {
362
+ uint32_t num_indexes{0};
363
+ bool enforce{false};
364
+ };
365
+
366
+ struct scope_rate_limits {
367
+ kv_scope_rate_limits kv_scope_limits;
368
+ index_scope_rate_limits index_scope_limits;
369
+ };
370
+
371
+ void enforce_rate_limits(lcb_INSTANCE *instance);
372
+ void create_rate_limited_user(lcb_INSTANCE *instance, const std::string &username, const rate_limits &limits);
373
+ void drop_user(lcb_INSTANCE *instance, const std::string &username);
374
+ void create_rate_limited_scope(lcb_INSTANCE *instance, const std::string &bucket, std::string &scope,
375
+ const scope_rate_limits &limits);
376
+ void create_search_index(lcb_INSTANCE *instance, const std::string &index_name, const std::string &type,
377
+ const std::string &source_type, const std::string &source_name);
378
+
326
379
  #endif
@@ -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
 
@@ -2023,6 +2023,35 @@ void AdminHandler::run()
2023
2023
  printf("%s\n", resbuf.c_str());
2024
2024
  }
2025
2025
 
2026
+ void BucketListHandler::run()
2027
+ {
2028
+ fprintf(stderr, "Requesting %s\n", getURI().c_str());
2029
+ HttpBaseHandler::run();
2030
+ if (o_raw.result()) {
2031
+ printf("%s\n", resbuf.c_str());
2032
+ } else {
2033
+ format();
2034
+ }
2035
+ }
2036
+
2037
+ void BucketListHandler::format()
2038
+ {
2039
+ Json::Value json;
2040
+ if (!Json::Reader().parse(resbuf, json)) {
2041
+ fprintf(stderr, "Failed to parse response as JSON, falling back to raw mode\n");
2042
+ printf("%s\n", resbuf.c_str());
2043
+ }
2044
+
2045
+ printf("%-20s%-10s%s\n", "Name", "Type", "Items");
2046
+
2047
+ for (Json::Value::ArrayIndex i = 0; i < json.size(); ++i) {
2048
+ const char *name = json[i]["name"].asString().c_str();
2049
+ const char *bucketType = json[i]["bucketType"].asString().c_str();
2050
+ const int itemCount = json[i]["basicStats"]["itemCount"].asInt();
2051
+ printf("%-20s%-10s%i\n", name, bucketType, itemCount);
2052
+ }
2053
+ }
2054
+
2026
2055
  void BucketCreateHandler::run()
2027
2056
  {
2028
2057
  const string &name = getRequiredArg();
@@ -2278,6 +2307,7 @@ static const char *optionsOrder[] = {"help",
2278
2307
  "analytics",
2279
2308
  "search",
2280
2309
  "admin",
2310
+ "bucket-list",
2281
2311
  "bucket-create",
2282
2312
  "bucket-delete",
2283
2313
  "bucket-flush",
@@ -2369,6 +2399,7 @@ static void setupHandlers()
2369
2399
  handlers_s["incr"] = new IncrHandler();
2370
2400
  handlers_s["decr"] = new DecrHandler();
2371
2401
  handlers_s["admin"] = new AdminHandler();
2402
+ handlers_s["bucket-list"] = new BucketListHandler();
2372
2403
  handlers_s["bucket-create"] = new BucketCreateHandler();
2373
2404
  handlers_s["bucket-delete"] = new BucketDeleteHandler();
2374
2405
  handlers_s["bucket-flush"] = new BucketFlushHandler();
@@ -18,6 +18,7 @@
18
18
  #include "contrib/lcb-jsoncpp/lcb-jsoncpp.h"
19
19
  #include "placeholders.h"
20
20
  #include <algorithm>
21
+ #include <memory>
21
22
  #include <stdexcept>
22
23
 
23
24
  namespace Pillowfight
@@ -78,8 +79,8 @@ class DocGeneratorBase
78
79
  * @param cur_gen The index of the current generator thread
79
80
  * @return An opaque state object. This should be deleted by the caller
80
81
  */
81
- virtual GeneratorState *createState(int total_gens, int cur_gen) const = 0;
82
- virtual SubdocGeneratorState *createSubdocState(int, int) const
82
+ virtual std::unique_ptr<GeneratorState> createState(int total_gens, int cur_gen) const = 0;
83
+ virtual std::unique_ptr<SubdocGeneratorState> createSubdocState(int, int) const
83
84
  {
84
85
  return NULL;
85
86
  }
@@ -164,9 +165,9 @@ class RawDocGenerator : public DocGeneratorBase
164
165
  }
165
166
  };
166
167
 
167
- GeneratorState *createState(int, int) const
168
+ std::unique_ptr<GeneratorState> createState(int, int) const
168
169
  {
169
- return new MyState(this);
170
+ return std::unique_ptr<GeneratorState>(new MyState(this));
170
171
  }
171
172
 
172
173
  private:
@@ -207,9 +208,9 @@ class PresetDocGenerator : public DocGeneratorBase
207
208
  const PresetDocGenerator *m_parent;
208
209
  };
209
210
 
210
- GeneratorState *createState(int, int) const
211
+ std::unique_ptr<GeneratorState> createState(int, int) const
211
212
  {
212
- return new MyState(this);
213
+ return std::unique_ptr<GeneratorState>(new MyState(this));
213
214
  }
214
215
 
215
216
  protected:
@@ -371,9 +372,9 @@ class JsonDocGenerator : public PresetDocGenerator
371
372
  };
372
373
 
373
374
  public:
374
- virtual SubdocGeneratorState *createSubdocState(int, int) const
375
+ virtual std::unique_ptr<SubdocGeneratorState> createSubdocState(int, int) const
375
376
  {
376
- return new SDGenstate(m_docs);
377
+ return std::unique_ptr<SubdocGeneratorState>(new SDGenstate(m_docs));
377
378
  }
378
379
  };
379
380
 
@@ -424,9 +425,9 @@ class PlaceholderDocGenerator : public DocGeneratorBase
424
425
  }
425
426
 
426
427
  public:
427
- GeneratorState *createState(int total, int cur) const
428
+ std::unique_ptr<GeneratorState> createState(int total, int cur) const
428
429
  {
429
- return new MyState(this, total, cur);
430
+ return std::unique_ptr<GeneratorState>(new MyState(this, total, cur));
430
431
  }
431
432
 
432
433
  private:
@@ -82,8 +82,8 @@ class AnalyticsExecutor {
82
82
  }
83
83
  const metricsData = metaData.metrics || {};
84
84
  const metrics = new analyticstypes_1.AnalyticsMetrics({
85
- elapsedTime: utilities_1.goDurationStrToMs(metricsData.elapsedTime) || 0,
86
- executionTime: utilities_1.goDurationStrToMs(metricsData.executionTime) || 0,
85
+ elapsedTime: (0, utilities_1.goDurationStrToMs)(metricsData.elapsedTime) || 0,
86
+ executionTime: (0, utilities_1.goDurationStrToMs)(metricsData.executionTime) || 0,
87
87
  resultCount: metricsData.resultCount || 0,
88
88
  resultSize: metricsData.resultSize || 0,
89
89
  errorCount: metricsData.errorCount || 0,