libcouchbase 1.2.8 → 1.3.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -4
- data/README.md +16 -8
- data/ext/libcouchbase/CMakeLists.txt +34 -32
- data/ext/libcouchbase/RELEASE_NOTES.markdown +277 -6
- data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +14 -0
- data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibevent.cmake +2 -0
- data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibuv.cmake +2 -1
- data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -0
- data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +8 -1
- data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
- data/ext/libcouchbase/cmake/config-cmake.h.in +14 -0
- data/ext/libcouchbase/cmake/configure +8 -26
- data/ext/libcouchbase/cmake/defs.mk.in +2 -2
- data/ext/libcouchbase/cmake/libcouchbase.stp.in +829 -0
- data/ext/libcouchbase/cmake/source_files.cmake +11 -2
- data/ext/libcouchbase/contrib/cbsasl/CMakeLists.txt +18 -2
- data/ext/libcouchbase/contrib/cbsasl/include/cbsasl/cbsasl.h +44 -2
- data/ext/libcouchbase/contrib/cbsasl/src/client.c +285 -73
- data/ext/libcouchbase/contrib/cbsasl/src/common.c +4 -0
- data/ext/libcouchbase/contrib/cbsasl/src/scram-sha/scram_utils.c +500 -0
- data/ext/libcouchbase/contrib/cbsasl/src/scram-sha/scram_utils.h +99 -0
- data/ext/libcouchbase/contrib/cliopts/CMakeLists.txt +1 -1
- data/ext/libcouchbase/contrib/cliopts/cliopts.h +14 -1
- data/ext/libcouchbase/contrib/snappy/CMakeLists.txt +2 -3
- data/ext/libcouchbase/contrib/snappy/snappy-sinksource.cc +4 -0
- data/ext/libcouchbase/contrib/snappy/snappy-stubs-public.h +7 -5
- data/ext/libcouchbase/contrib/snappy/snappy.cc +7 -2
- data/ext/libcouchbase/example/crypto/.gitignore +2 -0
- data/ext/libcouchbase/example/crypto/Makefile +13 -0
- data/ext/libcouchbase/example/crypto/common_provider.c +24 -0
- data/ext/libcouchbase/example/crypto/common_provider.h +31 -0
- data/ext/libcouchbase/example/crypto/openssl_symmetric_decrypt.c +139 -0
- data/ext/libcouchbase/example/crypto/openssl_symmetric_encrypt.c +147 -0
- data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.c +281 -0
- data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.h +29 -0
- data/ext/libcouchbase/example/tracing/.gitignore +2 -0
- data/ext/libcouchbase/example/tracing/Makefile +8 -0
- data/ext/libcouchbase/example/tracing/cJSON.c +1 -0
- data/ext/libcouchbase/example/tracing/cJSON.h +1 -0
- data/ext/libcouchbase/example/tracing/tracing.c +439 -0
- data/ext/libcouchbase/example/tracing/views.c +444 -0
- data/ext/libcouchbase/include/libcouchbase/auth.h +56 -4
- data/ext/libcouchbase/include/libcouchbase/cbft.h +8 -0
- data/ext/libcouchbase/include/libcouchbase/cntl-private.h +55 -1
- data/ext/libcouchbase/include/libcouchbase/cntl.h +101 -1
- data/ext/libcouchbase/include/libcouchbase/configuration.h.in +6 -0
- data/ext/libcouchbase/include/libcouchbase/couchbase.h +109 -6
- data/ext/libcouchbase/include/libcouchbase/crypto.h +140 -0
- data/ext/libcouchbase/include/libcouchbase/error.h +38 -2
- data/ext/libcouchbase/include/libcouchbase/kvbuf.h +6 -1
- data/ext/libcouchbase/include/libcouchbase/metrics.h +79 -0
- data/ext/libcouchbase/include/libcouchbase/n1ql.h +9 -0
- data/ext/libcouchbase/include/libcouchbase/tracing.h +319 -0
- data/ext/libcouchbase/include/libcouchbase/vbucket.h +1 -1
- data/ext/libcouchbase/include/libcouchbase/views.h +8 -0
- data/ext/libcouchbase/include/memcached/protocol_binary.h +40 -10
- data/ext/libcouchbase/packaging/rpm/libcouchbase.spec.in +6 -14
- data/ext/libcouchbase/plugins/io/libuv/plugin-internal.h +3 -0
- data/ext/libcouchbase/plugins/io/libuv/plugin-libuv.c +1 -0
- data/ext/libcouchbase/plugins/io/select/plugin-select.c +4 -1
- data/ext/libcouchbase/src/auth-priv.h +36 -4
- data/ext/libcouchbase/src/auth.cc +66 -27
- data/ext/libcouchbase/src/bootstrap.cc +1 -1
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +12 -7
- data/ext/libcouchbase/src/bucketconfig/bc_http.cc +26 -17
- data/ext/libcouchbase/src/bucketconfig/bc_http.h +1 -1
- data/ext/libcouchbase/src/bucketconfig/clconfig.h +4 -2
- data/ext/libcouchbase/src/bucketconfig/confmon.cc +6 -3
- data/ext/libcouchbase/src/cbft.cc +48 -0
- data/ext/libcouchbase/src/cntl.cc +138 -2
- data/ext/libcouchbase/src/config_static.h +17 -0
- data/ext/libcouchbase/src/connspec.cc +54 -6
- data/ext/libcouchbase/src/connspec.h +9 -1
- data/ext/libcouchbase/src/crypto.cc +386 -0
- data/ext/libcouchbase/src/ctx-log-inl.h +23 -6
- data/ext/libcouchbase/src/dump.cc +4 -0
- data/ext/libcouchbase/src/getconfig.cc +1 -2
- data/ext/libcouchbase/src/handler.cc +65 -27
- data/ext/libcouchbase/src/hostlist.cc +35 -7
- data/ext/libcouchbase/src/hostlist.h +7 -0
- data/ext/libcouchbase/src/http/http-priv.h +2 -0
- data/ext/libcouchbase/src/http/http.cc +77 -37
- data/ext/libcouchbase/src/http/http_io.cc +19 -2
- data/ext/libcouchbase/src/instance.cc +90 -17
- data/ext/libcouchbase/src/internal.h +5 -0
- data/ext/libcouchbase/src/lcbio/connect.cc +39 -4
- data/ext/libcouchbase/src/lcbio/connect.h +27 -0
- data/ext/libcouchbase/src/lcbio/ctx.c +49 -23
- data/ext/libcouchbase/src/lcbio/ioutils.cc +30 -3
- data/ext/libcouchbase/src/lcbio/ioutils.h +2 -0
- data/ext/libcouchbase/src/lcbio/manager.cc +44 -8
- data/ext/libcouchbase/src/lcbio/manager.h +2 -0
- data/ext/libcouchbase/src/lcbio/rw-inl.h +1 -0
- data/ext/libcouchbase/src/lcbio/ssl.h +3 -5
- data/ext/libcouchbase/src/logging.c +1 -1
- data/ext/libcouchbase/src/logging.h +2 -0
- data/ext/libcouchbase/src/mc/compress.cc +164 -0
- data/ext/libcouchbase/src/mc/compress.h +7 -12
- data/ext/libcouchbase/src/mc/mcreq-flush-inl.h +5 -1
- data/ext/libcouchbase/src/mc/mcreq.c +11 -1
- data/ext/libcouchbase/src/mc/mcreq.h +35 -4
- data/ext/libcouchbase/src/mcserver/mcserver.cc +30 -7
- data/ext/libcouchbase/src/mcserver/mcserver.h +7 -0
- data/ext/libcouchbase/src/mcserver/negotiate.cc +103 -57
- data/ext/libcouchbase/src/mcserver/negotiate.h +2 -2
- data/ext/libcouchbase/src/mctx-helper.h +11 -0
- data/ext/libcouchbase/src/metrics.cc +132 -0
- data/ext/libcouchbase/src/n1ql/ixmgmt.cc +2 -1
- data/ext/libcouchbase/src/n1ql/n1ql.cc +66 -0
- data/ext/libcouchbase/src/newconfig.cc +9 -2
- data/ext/libcouchbase/src/operations/counter.cc +2 -1
- data/ext/libcouchbase/src/operations/durability-cas.cc +11 -0
- data/ext/libcouchbase/src/operations/durability-seqno.cc +3 -0
- data/ext/libcouchbase/src/operations/durability.cc +24 -2
- data/ext/libcouchbase/src/operations/durability_internal.h +19 -0
- data/ext/libcouchbase/src/operations/get.cc +4 -2
- data/ext/libcouchbase/src/operations/observe-seqno.cc +1 -0
- data/ext/libcouchbase/src/operations/observe.cc +113 -62
- data/ext/libcouchbase/src/operations/ping.cc +246 -67
- data/ext/libcouchbase/src/operations/remove.cc +2 -1
- data/ext/libcouchbase/src/operations/store.cc +17 -14
- data/ext/libcouchbase/src/operations/touch.cc +3 -0
- data/ext/libcouchbase/src/packetutils.h +68 -4
- data/ext/libcouchbase/src/probes.d +132 -161
- data/ext/libcouchbase/src/rdb/bigalloc.c +1 -1
- data/ext/libcouchbase/src/retryq.cc +6 -2
- data/ext/libcouchbase/src/rnd.cc +68 -0
- data/ext/libcouchbase/src/rnd.h +39 -0
- data/ext/libcouchbase/src/settings.c +27 -0
- data/ext/libcouchbase/src/settings.h +67 -3
- data/ext/libcouchbase/src/ssl/CMakeLists.txt +0 -12
- data/ext/libcouchbase/src/ssl/ssl_common.c +23 -4
- data/ext/libcouchbase/src/strcodecs/base64.c +141 -16
- data/ext/libcouchbase/src/strcodecs/strcodecs.h +16 -1
- data/ext/libcouchbase/src/trace.h +68 -61
- data/ext/libcouchbase/src/tracing/span.cc +289 -0
- data/ext/libcouchbase/src/tracing/threshold_logging_tracer.cc +171 -0
- data/ext/libcouchbase/src/tracing/tracer.cc +53 -0
- data/ext/libcouchbase/src/tracing/tracing-internal.h +213 -0
- data/ext/libcouchbase/src/utilities.c +5 -0
- data/ext/libcouchbase/src/vbucket/CMakeLists.txt +2 -2
- data/ext/libcouchbase/src/vbucket/vbucket.c +50 -18
- data/ext/libcouchbase/src/views/docreq.cc +26 -1
- data/ext/libcouchbase/src/views/docreq.h +17 -0
- data/ext/libcouchbase/src/views/viewreq.cc +64 -1
- data/ext/libcouchbase/src/views/viewreq.h +21 -0
- data/ext/libcouchbase/tests/CMakeLists.txt +6 -6
- data/ext/libcouchbase/tests/basic/t_base64.cc +34 -6
- data/ext/libcouchbase/tests/basic/t_connstr.cc +14 -0
- data/ext/libcouchbase/tests/basic/t_creds.cc +10 -10
- data/ext/libcouchbase/tests/basic/t_host.cc +22 -2
- data/ext/libcouchbase/tests/basic/t_scram.cc +514 -0
- data/ext/libcouchbase/tests/check-all.cc +6 -2
- data/ext/libcouchbase/tests/iotests/mock-environment.cc +64 -0
- data/ext/libcouchbase/tests/iotests/mock-environment.h +27 -1
- data/ext/libcouchbase/tests/iotests/t_confmon.cc +2 -2
- data/ext/libcouchbase/tests/iotests/t_forward.cc +8 -0
- data/ext/libcouchbase/tests/iotests/t_netfail.cc +124 -0
- data/ext/libcouchbase/tests/iotests/t_smoke.cc +1 -1
- data/ext/libcouchbase/tests/iotests/t_snappy.cc +316 -0
- data/ext/libcouchbase/tests/socktests/socktest.cc +2 -2
- data/ext/libcouchbase/tests/socktests/t_basic.cc +6 -6
- data/ext/libcouchbase/tests/socktests/t_manager.cc +1 -1
- data/ext/libcouchbase/tests/socktests/t_ssl.cc +1 -1
- data/ext/libcouchbase/tools/CMakeLists.txt +1 -1
- data/ext/libcouchbase/tools/cbc-handlers.h +17 -0
- data/ext/libcouchbase/tools/cbc-n1qlback.cc +7 -4
- data/ext/libcouchbase/tools/cbc-pillowfight.cc +408 -100
- data/ext/libcouchbase/tools/cbc-proxy.cc +134 -3
- data/ext/libcouchbase/tools/cbc-subdoc.cc +1 -2
- data/ext/libcouchbase/tools/cbc.cc +113 -8
- data/ext/libcouchbase/tools/common/histogram.cc +1 -0
- data/ext/libcouchbase/tools/common/options.cc +28 -1
- data/ext/libcouchbase/tools/common/options.h +5 -0
- data/ext/libcouchbase/tools/docgen/docgen.h +36 -10
- data/ext/libcouchbase/tools/docgen/loc.h +5 -4
- data/ext/libcouchbase/tools/docgen/seqgen.h +28 -0
- data/lib/libcouchbase/ext/libcouchbase/enums.rb +10 -0
- data/lib/libcouchbase/n1ql.rb +6 -1
- data/lib/libcouchbase/version.rb +1 -1
- data/spec/connection_spec.rb +6 -6
- metadata +38 -5
- data/ext/libcouchbase/cmake/Modules/FindCouchbaseSnappy.cmake +0 -11
- data/ext/libcouchbase/src/mc/compress.c +0 -90
- data/ext/libcouchbase/tools/common/my_inttypes.h +0 -22
|
@@ -206,7 +206,7 @@ Loop::initSockCommon(ESocket *sock)
|
|
|
206
206
|
void
|
|
207
207
|
Loop::connectPooled(ESocket *sock, lcb_host_t *host, unsigned mstmo)
|
|
208
208
|
{
|
|
209
|
-
lcb_host_t tmphost;
|
|
209
|
+
lcb_host_t tmphost = {0};
|
|
210
210
|
sock->parent = this;
|
|
211
211
|
if (!host) {
|
|
212
212
|
populateHost(&tmphost);
|
|
@@ -222,7 +222,7 @@ Loop::connectPooled(ESocket *sock, lcb_host_t *host, unsigned mstmo)
|
|
|
222
222
|
void
|
|
223
223
|
Loop::connect(ESocket *sock, lcb_host_t *host, unsigned mstmo)
|
|
224
224
|
{
|
|
225
|
-
lcb_host_t tmphost;
|
|
225
|
+
lcb_host_t tmphost = {0};
|
|
226
226
|
|
|
227
227
|
if (host == NULL) {
|
|
228
228
|
populateHost(&tmphost);
|
|
@@ -62,7 +62,7 @@ static bool isRefused(lcbio_OSERR err)
|
|
|
62
62
|
TEST_F(SockConnTest, testRefused)
|
|
63
63
|
{
|
|
64
64
|
ESocket sock;
|
|
65
|
-
lcb_host_t host;
|
|
65
|
+
lcb_host_t host = {0};
|
|
66
66
|
strcpy(host.host, "localhost");
|
|
67
67
|
strcpy(host.port, "1");
|
|
68
68
|
loop->connect(&sock, &host, 100000);
|
|
@@ -73,7 +73,7 @@ TEST_F(SockConnTest, testRefused)
|
|
|
73
73
|
TEST_F(SockConnTest, testBadDomain)
|
|
74
74
|
{
|
|
75
75
|
ESocket sock;
|
|
76
|
-
lcb_host_t host;
|
|
76
|
+
lcb_host_t host = {0};
|
|
77
77
|
strcpy(host.host, "domain-should-not-work.nonexist.com");
|
|
78
78
|
strcpy(host.port, "123");
|
|
79
79
|
loop->connect(&sock, &host, 1000);
|
|
@@ -83,7 +83,7 @@ TEST_F(SockConnTest, testBadDomain)
|
|
|
83
83
|
TEST_F(SockConnTest, testInvalidPort)
|
|
84
84
|
{
|
|
85
85
|
ESocket sock;
|
|
86
|
-
lcb_host_t host;
|
|
86
|
+
lcb_host_t host = {0};
|
|
87
87
|
strcpy(host.host, "localhost");
|
|
88
88
|
strcpy(host.port, "111111111");
|
|
89
89
|
loop->connect(&sock, &host, 1000);
|
|
@@ -93,7 +93,7 @@ TEST_F(SockConnTest, testInvalidPort)
|
|
|
93
93
|
TEST_F(SockTest, testEmptyHost)
|
|
94
94
|
{
|
|
95
95
|
ESocket sock;
|
|
96
|
-
lcb_host_t host;
|
|
96
|
+
lcb_host_t host = {0};
|
|
97
97
|
host.host[0] = '\0';
|
|
98
98
|
host.port[0] = '\0';
|
|
99
99
|
loop->connect(&sock, &host, 1000);
|
|
@@ -103,7 +103,7 @@ TEST_F(SockTest, testEmptyHost)
|
|
|
103
103
|
TEST_F(SockConnTest, testCancellation)
|
|
104
104
|
{
|
|
105
105
|
ESocket sock;
|
|
106
|
-
lcb_host_t host;
|
|
106
|
+
lcb_host_t host = {0};
|
|
107
107
|
loop->populateHost(&host);
|
|
108
108
|
sock.creq = lcbio_connect(
|
|
109
109
|
loop->iot, loop->settings, &host, 100000, NULL, NULL);
|
|
@@ -132,7 +132,7 @@ conncb_1(lcbio_SOCKET *sock, void *arg, lcb_error_t err, lcbio_OSERR syserr)
|
|
|
132
132
|
TEST_F(SockConnTest, testImmediateUnref)
|
|
133
133
|
{
|
|
134
134
|
ESocket sock;
|
|
135
|
-
lcb_host_t host;
|
|
135
|
+
lcb_host_t host = {0};
|
|
136
136
|
sock.parent = loop;
|
|
137
137
|
loop->populateHost(&host);
|
|
138
138
|
sock.creq = lcbio_connect(
|
|
@@ -30,7 +30,7 @@ TEST_F(SockMgrTest, testBasic)
|
|
|
30
30
|
|
|
31
31
|
TEST_F(SockMgrTest, testCancellation)
|
|
32
32
|
{
|
|
33
|
-
lcb_host_t host;
|
|
33
|
+
lcb_host_t host = {0};
|
|
34
34
|
loop->populateHost(&host);
|
|
35
35
|
lcb::io::ConnectionRequest *req = loop->sockpool->get(host, LCB_MS2US(1000), NULL, NULL);
|
|
36
36
|
ASSERT_FALSE(req == NULL);
|
|
@@ -16,7 +16,7 @@ protected:
|
|
|
16
16
|
|
|
17
17
|
SockTest::SetUp();
|
|
18
18
|
loop->settings->sslopts = LCB_SSL_ENABLED|LCB_SSL_NOVERIFY;
|
|
19
|
-
loop->settings->ssl_ctx = lcbio_ssl_new(NULL, 1, &errp, loop->settings);
|
|
19
|
+
loop->settings->ssl_ctx = lcbio_ssl_new(NULL, NULL, NULL, 1, &errp, loop->settings);
|
|
20
20
|
loop->server->factory = TestServer::sslSocketFactory;
|
|
21
21
|
EXPECT_FALSE(loop->settings->ssl_ctx == NULL) << lcb_strerror(NULL, errp);
|
|
22
22
|
}
|
|
@@ -62,7 +62,7 @@ IF(NOT WIN32)
|
|
|
62
62
|
cat create observe observe-seqno incr decr mcflush hash lock
|
|
63
63
|
unlock rm stats version verbosity view n1ql admin ping
|
|
64
64
|
bucket-create bucket-delete bucket-flush connstr write-config strerror
|
|
65
|
-
touch role-list user-list user-upsert user-delete)
|
|
65
|
+
touch role-list user-list user-upsert user-delete watch)
|
|
66
66
|
|
|
67
67
|
FOREACH(subcmd IN ITEMS ${CBC_SUBCOMMANDS})
|
|
68
68
|
ADD_CUSTOM_COMMAND(TARGET cbc POST_BUILD
|
|
@@ -194,6 +194,23 @@ private:
|
|
|
194
194
|
cliopts::BoolOption o_keystats;
|
|
195
195
|
};
|
|
196
196
|
|
|
197
|
+
class WatchHandler : public Handler {
|
|
198
|
+
public:
|
|
199
|
+
HANDLER_DESCRIPTION("Aggregate and display server statistics")
|
|
200
|
+
HANDLER_USAGE("[KEYS ....] [OPTIONS ...]")
|
|
201
|
+
WatchHandler() : Handler("watch"), o_interval("interval") {
|
|
202
|
+
o_interval.abbrev('n').description("Update interval in seconds").setDefault(1);
|
|
203
|
+
}
|
|
204
|
+
protected:
|
|
205
|
+
void run();
|
|
206
|
+
void addOptions() {
|
|
207
|
+
Handler::addOptions();
|
|
208
|
+
parser.addOption(o_interval);
|
|
209
|
+
}
|
|
210
|
+
private:
|
|
211
|
+
cliopts::UIntOption o_interval;
|
|
212
|
+
};
|
|
213
|
+
|
|
197
214
|
class VerbosityHandler : public Handler {
|
|
198
215
|
public:
|
|
199
216
|
HANDLER_DESCRIPTION("Modify the memcached logging level")
|
|
@@ -141,9 +141,9 @@ private:
|
|
|
141
141
|
final_suffix = "\n";
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
printf("%sQUERIES/SEC: %lu\n", prefix, (long
|
|
145
|
-
printf("%sROWS/SEC: %lu\n", prefix, (long
|
|
146
|
-
printf("%sERRORS: %lu%s", prefix, n_errors, final_suffix);
|
|
144
|
+
printf("%sQUERIES/SEC: %lu\n", prefix, (unsigned long)(n_queries / duration));
|
|
145
|
+
printf("%sROWS/SEC: %lu\n", prefix, (unsigned long)(n_rows / duration));
|
|
146
|
+
printf("%sERRORS: %lu%s", prefix, (unsigned long)n_errors, final_suffix);
|
|
147
147
|
|
|
148
148
|
if (hg != NULL) {
|
|
149
149
|
hg->write();
|
|
@@ -213,11 +213,14 @@ public:
|
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
string curline;
|
|
216
|
-
while (
|
|
216
|
+
while (ifs.good()) {
|
|
217
|
+
std::getline(ifs, curline);
|
|
217
218
|
if (!curline.empty()) {
|
|
218
219
|
m_queries.push_back(curline);
|
|
219
220
|
}
|
|
220
221
|
}
|
|
222
|
+
std::cerr << "Loaded " << m_queries.size() << " queries "
|
|
223
|
+
<< "from \"" << o_file.const_result() << "\"" << std::endl;
|
|
221
224
|
if (m_params.useTimings()) {
|
|
222
225
|
GlobalMetrics.prepare_timings();
|
|
223
226
|
}
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
#include <signal.h>
|
|
33
33
|
#ifndef WIN32
|
|
34
34
|
#include <pthread.h>
|
|
35
|
+
#include <libcouchbase/metrics.h>
|
|
35
36
|
#else
|
|
36
37
|
#define usleep(n) Sleep(n/1000)
|
|
37
38
|
#endif
|
|
@@ -105,6 +106,7 @@ public:
|
|
|
105
106
|
o_keyPrefix("key-prefix"),
|
|
106
107
|
o_numThreads("num-threads"),
|
|
107
108
|
o_randSeed("random-seed"),
|
|
109
|
+
o_randomBody("random-body"),
|
|
108
110
|
o_setPercent("set-pct"),
|
|
109
111
|
o_minSize("min-size"),
|
|
110
112
|
o_maxSize("max-size"),
|
|
@@ -121,13 +123,19 @@ public:
|
|
|
121
123
|
o_noop("noop"),
|
|
122
124
|
o_sdPathCount("pathcount"),
|
|
123
125
|
o_populateOnly("populate-only"),
|
|
124
|
-
o_exptime("expiry")
|
|
126
|
+
o_exptime("expiry"),
|
|
127
|
+
o_collection("collection"),
|
|
128
|
+
o_separator("separator"),
|
|
129
|
+
o_persist("persist-to"),
|
|
130
|
+
o_replicate("replicate-to"),
|
|
131
|
+
o_lock("lock")
|
|
125
132
|
{
|
|
126
133
|
o_multiSize.setDefault(100).abbrev('B').description("Number of operations to batch");
|
|
127
134
|
o_numItems.setDefault(1000).abbrev('I').description("Number of items to operate on");
|
|
128
135
|
o_keyPrefix.abbrev('p').description("key prefix to use");
|
|
129
136
|
o_numThreads.setDefault(1).abbrev('t').description("The number of threads to use");
|
|
130
137
|
o_randSeed.setDefault(0).abbrev('s').description("Specify random seed").hide();
|
|
138
|
+
o_randomBody.setDefault(false).abbrev('R').description("Randomize document body (otherwise use 'x' and '*' to fill)");
|
|
131
139
|
o_setPercent.setDefault(33).abbrev('r').description("The percentage of operations which should be mutations");
|
|
132
140
|
o_minSize.setDefault(50).abbrev('m').description("Set minimum payload size");
|
|
133
141
|
o_maxSize.setDefault(5120).abbrev('M').description("Set maximum payload size");
|
|
@@ -138,7 +146,7 @@ public:
|
|
|
138
146
|
o_startAt.setDefault(0).description("For sequential access, set the first item");
|
|
139
147
|
o_rateLimit.setDefault(0).description("Set operations per second limit (per thread)");
|
|
140
148
|
o_userdocs.description("User documents to load (overrides --min-size and --max-size");
|
|
141
|
-
o_writeJson.description("Enable writing JSON values (rather than bytes)");
|
|
149
|
+
o_writeJson.abbrev('J').description("Enable writing JSON values (rather than bytes)");
|
|
142
150
|
o_templatePairs.description("Values for templates to be inserted into user documents");
|
|
143
151
|
o_templatePairs.argdesc("FIELD,MIN,MAX[,SEQUENTIAL]").hide();
|
|
144
152
|
o_subdoc.description("Use subdoc instead of fulldoc operations");
|
|
@@ -146,6 +154,12 @@ public:
|
|
|
146
154
|
o_sdPathCount.description("Number of subdoc paths per command").setDefault(1);
|
|
147
155
|
o_populateOnly.description("Exit after documents have been populated");
|
|
148
156
|
o_exptime.description("Set TTL for items").abbrev('e');
|
|
157
|
+
o_collection.description("Allowed collection name (could be specified multiple times)").hide();
|
|
158
|
+
o_separator.setDefault(":").description("Separator for collection prefix in keys").hide();
|
|
159
|
+
o_persist.description("Wait until item is persisted to this number of nodes (-1 for master+replicas)").setDefault(0);
|
|
160
|
+
o_replicate.description("Wait until item is replicated to this number of nodes (-1 for all replicas)").setDefault(0);
|
|
161
|
+
o_lock.description("Lock keys for updates for given time (will not lock when set to zero)").setDefault(0);
|
|
162
|
+
params.getTimings().description("Enable command timings (second time to dump timings automatically)");
|
|
149
163
|
}
|
|
150
164
|
|
|
151
165
|
void processOptions() {
|
|
@@ -153,7 +167,18 @@ public:
|
|
|
153
167
|
prefix = o_keyPrefix.result();
|
|
154
168
|
setprc = o_setPercent.result();
|
|
155
169
|
shouldPopulate = !o_noPopulate.result();
|
|
170
|
+
persistTo = o_persist.result();
|
|
171
|
+
replicateTo = o_replicate.result();
|
|
172
|
+
lockTime = o_lock.result();
|
|
173
|
+
if (lockTime && o_numItems < opsPerCycle * o_numThreads) {
|
|
174
|
+
fprintf(stderr, "The --num-items=%d cannot be smaller than --batch-size=%d multiplied to --num-thread=%d when used with --lock=%d\n",
|
|
175
|
+
(int)o_numItems, (int)opsPerCycle, (int)o_numThreads, (int)lockTime);
|
|
176
|
+
exit(EXIT_FAILURE);
|
|
177
|
+
}
|
|
156
178
|
|
|
179
|
+
if (o_keyPrefix.passed() && o_collection.passed()) {
|
|
180
|
+
throw std::runtime_error("The --collection is not compatible with --key-prefix");
|
|
181
|
+
}
|
|
157
182
|
if (depr.loop.passed()) {
|
|
158
183
|
fprintf(stderr, "The --loop/-l option is deprecated. Use --num-cycles\n");
|
|
159
184
|
maxCycles = -1;
|
|
@@ -211,17 +236,17 @@ public:
|
|
|
211
236
|
|
|
212
237
|
if (specs.empty()) {
|
|
213
238
|
if (o_writeJson.result()) {
|
|
214
|
-
docgen = new JsonDocGenerator(o_minSize.result(), o_maxSize.result());
|
|
239
|
+
docgen = new JsonDocGenerator(o_minSize.result(), o_maxSize.result(), o_randomBody.numSpecified());
|
|
215
240
|
} else if (!userdocs.empty()) {
|
|
216
241
|
docgen = new PresetDocGenerator(userdocs);
|
|
217
242
|
} else {
|
|
218
|
-
docgen = new RawDocGenerator(o_minSize.result(), o_maxSize.result());
|
|
243
|
+
docgen = new RawDocGenerator(o_minSize.result(), o_maxSize.result(), o_randomBody.numSpecified());
|
|
219
244
|
}
|
|
220
245
|
} else {
|
|
221
246
|
if (o_writeJson.result()) {
|
|
222
247
|
if (userdocs.empty()) {
|
|
223
248
|
docgen = new PlaceholderJsonGenerator(
|
|
224
|
-
o_minSize.result(), o_maxSize.result(), specs);
|
|
249
|
+
o_minSize.result(), o_maxSize.result(), specs, o_randomBody.numSpecified());
|
|
225
250
|
} else {
|
|
226
251
|
docgen = new PlaceholderJsonGenerator(userdocs, specs);
|
|
227
252
|
}
|
|
@@ -237,6 +262,17 @@ public:
|
|
|
237
262
|
if (o_sdPathCount.passed()) {
|
|
238
263
|
o_subdoc.setDefault(true);
|
|
239
264
|
}
|
|
265
|
+
|
|
266
|
+
if (o_collection.passed()) {
|
|
267
|
+
string separator = o_separator.result();
|
|
268
|
+
if (separator.empty()) {
|
|
269
|
+
throw std::runtime_error("Collection name separator must not be empty");
|
|
270
|
+
}
|
|
271
|
+
vector<string> names = o_collection.result();
|
|
272
|
+
for (size_t ii = 0; ii < names.size(); ii++) {
|
|
273
|
+
collections.push_back(names[ii] + separator);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
240
276
|
}
|
|
241
277
|
|
|
242
278
|
void addOptions(Parser& parser) {
|
|
@@ -245,6 +281,7 @@ public:
|
|
|
245
281
|
parser.addOption(o_keyPrefix);
|
|
246
282
|
parser.addOption(o_numThreads);
|
|
247
283
|
parser.addOption(o_randSeed);
|
|
284
|
+
parser.addOption(o_randomBody);
|
|
248
285
|
parser.addOption(o_setPercent);
|
|
249
286
|
parser.addOption(o_noPopulate);
|
|
250
287
|
parser.addOption(o_minSize);
|
|
@@ -262,11 +299,16 @@ public:
|
|
|
262
299
|
parser.addOption(o_sdPathCount);
|
|
263
300
|
parser.addOption(o_populateOnly);
|
|
264
301
|
parser.addOption(o_exptime);
|
|
302
|
+
parser.addOption(o_collection);
|
|
303
|
+
parser.addOption(o_separator);
|
|
304
|
+
parser.addOption(o_persist);
|
|
305
|
+
parser.addOption(o_replicate);
|
|
306
|
+
parser.addOption(o_lock);
|
|
265
307
|
params.addToParser(parser);
|
|
266
308
|
depr.addOptions(parser);
|
|
267
309
|
}
|
|
268
310
|
|
|
269
|
-
|
|
311
|
+
int numTimings(void) { return params.numTimings(); }
|
|
270
312
|
|
|
271
313
|
bool isLoopDone(size_t niter) {
|
|
272
314
|
if (maxCycles == -1) {
|
|
@@ -282,6 +324,8 @@ public:
|
|
|
282
324
|
bool sequentialAccess() { return o_sequential; }
|
|
283
325
|
bool isSubdoc() { return o_subdoc; }
|
|
284
326
|
bool isNoop() { return o_noop.result(); }
|
|
327
|
+
bool useCollections() { return o_collection.passed(); }
|
|
328
|
+
bool writeJson() { return o_writeJson.result(); }
|
|
285
329
|
unsigned firstKeyOffset() { return o_startAt; }
|
|
286
330
|
uint32_t getNumItems() { return o_numItems; }
|
|
287
331
|
uint32_t getRateLimit() { return o_rateLimit; }
|
|
@@ -296,6 +340,10 @@ public:
|
|
|
296
340
|
bool hasTemplates;
|
|
297
341
|
ConnParams params;
|
|
298
342
|
const DocGeneratorBase *docgen;
|
|
343
|
+
vector<string> collections;
|
|
344
|
+
int replicateTo;
|
|
345
|
+
int persistTo;
|
|
346
|
+
int lockTime;
|
|
299
347
|
|
|
300
348
|
private:
|
|
301
349
|
UIntOption o_multiSize;
|
|
@@ -303,6 +351,7 @@ private:
|
|
|
303
351
|
StringOption o_keyPrefix;
|
|
304
352
|
UIntOption o_numThreads;
|
|
305
353
|
UIntOption o_randSeed;
|
|
354
|
+
BoolOption o_randomBody;
|
|
306
355
|
UIntOption o_setPercent;
|
|
307
356
|
UIntOption o_minSize;
|
|
308
357
|
UIntOption o_maxSize;
|
|
@@ -331,6 +380,12 @@ private:
|
|
|
331
380
|
|
|
332
381
|
UIntOption o_exptime;
|
|
333
382
|
|
|
383
|
+
ListOption o_collection;
|
|
384
|
+
StringOption o_separator;
|
|
385
|
+
IntOption o_persist;
|
|
386
|
+
IntOption o_replicate;
|
|
387
|
+
|
|
388
|
+
IntOption o_lock;
|
|
334
389
|
DeprecatedOptions depr;
|
|
335
390
|
} config;
|
|
336
391
|
|
|
@@ -341,7 +396,7 @@ void log(const char *format, ...)
|
|
|
341
396
|
|
|
342
397
|
va_start(args, format);
|
|
343
398
|
vsprintf(buffer, format, args);
|
|
344
|
-
if (config.
|
|
399
|
+
if (config.numTimings() > 0) {
|
|
345
400
|
std::cerr << "[" << std::fixed << lcb_nstime() / 1000000000.0 << "] ";
|
|
346
401
|
}
|
|
347
402
|
std::cerr << buffer << std::endl;
|
|
@@ -352,16 +407,24 @@ void log(const char *format, ...)
|
|
|
352
407
|
|
|
353
408
|
extern "C" {
|
|
354
409
|
static void operationCallback(lcb_t, int, const lcb_RESPBASE*);
|
|
410
|
+
static void storeCallback(lcb_t, int, const lcb_RESPBASE *);
|
|
355
411
|
}
|
|
356
412
|
|
|
413
|
+
class ThreadContext;
|
|
414
|
+
|
|
357
415
|
class InstanceCookie {
|
|
358
416
|
public:
|
|
359
417
|
InstanceCookie(lcb_t instance) {
|
|
360
418
|
lcb_set_cookie(instance, this);
|
|
361
419
|
lastPrint = 0;
|
|
362
|
-
if (config.
|
|
420
|
+
if (config.numTimings() > 0) {
|
|
363
421
|
hg.install(instance, stdout);
|
|
364
422
|
}
|
|
423
|
+
stats.total = 0;
|
|
424
|
+
stats.retried = 0;
|
|
425
|
+
stats.etmpfail = 0;
|
|
426
|
+
stats.eexist = 0;
|
|
427
|
+
stats.etimeout = 0;
|
|
365
428
|
}
|
|
366
429
|
|
|
367
430
|
static InstanceCookie* get(lcb_t instance) {
|
|
@@ -369,7 +432,7 @@ public:
|
|
|
369
432
|
}
|
|
370
433
|
|
|
371
434
|
|
|
372
|
-
static void dumpTimings(lcb_t instance, const char *header, bool force=false) {
|
|
435
|
+
static void dumpTimings(lcb_t instance, const char *header = NULL, bool force=false) {
|
|
373
436
|
time_t now = time(NULL);
|
|
374
437
|
InstanceCookie *ic = get(instance);
|
|
375
438
|
|
|
@@ -380,19 +443,37 @@ public:
|
|
|
380
443
|
}
|
|
381
444
|
|
|
382
445
|
Histogram &h = ic->hg;
|
|
383
|
-
|
|
384
|
-
|
|
446
|
+
if (header) {
|
|
447
|
+
printf("[%f %s]\n", lcb_nstime() / 1000000000.0, header);
|
|
448
|
+
}
|
|
449
|
+
printf(" +---------+---------+---------+---------+\n");
|
|
385
450
|
h.write();
|
|
386
|
-
printf("
|
|
451
|
+
printf(" +----------------------------------------\n");
|
|
387
452
|
}
|
|
388
453
|
|
|
454
|
+
void setContext(ThreadContext *context) {
|
|
455
|
+
m_context = context;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
ThreadContext * getContext() {
|
|
459
|
+
return m_context;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
struct {
|
|
463
|
+
size_t total;
|
|
464
|
+
size_t retried;
|
|
465
|
+
size_t etmpfail;
|
|
466
|
+
size_t eexist;
|
|
467
|
+
size_t etimeout;
|
|
468
|
+
} stats;
|
|
389
469
|
private:
|
|
390
470
|
time_t lastPrint;
|
|
391
471
|
Histogram hg;
|
|
472
|
+
ThreadContext *m_context;
|
|
392
473
|
};
|
|
393
474
|
|
|
394
475
|
struct NextOp {
|
|
395
|
-
NextOp() : m_seqno(0), m_mode(GET) {}
|
|
476
|
+
NextOp() : m_seqno(0), m_mode(GET), m_cas(0) {}
|
|
396
477
|
|
|
397
478
|
string m_key;
|
|
398
479
|
uint32_t m_seqno;
|
|
@@ -401,6 +482,7 @@ struct NextOp {
|
|
|
401
482
|
// The mode here is for future use with subdoc
|
|
402
483
|
enum Mode { STORE, GET, SDSTORE, SDGET, NOOP };
|
|
403
484
|
Mode m_mode;
|
|
485
|
+
uint64_t m_cas;
|
|
404
486
|
};
|
|
405
487
|
|
|
406
488
|
class OpGenerator {
|
|
@@ -410,7 +492,9 @@ public:
|
|
|
410
492
|
virtual ~OpGenerator() {};
|
|
411
493
|
virtual void setNextOp(NextOp& op) = 0;
|
|
412
494
|
virtual void setValue(NextOp& op) = 0;
|
|
495
|
+
virtual void populateIov(uint32_t, vector<lcb_IOV>&) = 0;
|
|
413
496
|
virtual bool inPopulation() const = 0;
|
|
497
|
+
virtual void checkin(uint32_t) = 0;
|
|
414
498
|
virtual const char *getStageString() const = 0;
|
|
415
499
|
|
|
416
500
|
protected:
|
|
@@ -427,11 +511,14 @@ public:
|
|
|
427
511
|
}
|
|
428
512
|
|
|
429
513
|
void setValue(NextOp&) {}
|
|
514
|
+
void populateIov(uint32_t, vector<lcb_IOV>&) {}
|
|
430
515
|
|
|
431
516
|
bool inPopulation() const {
|
|
432
517
|
return false;
|
|
433
518
|
}
|
|
434
519
|
|
|
520
|
+
void checkin(uint32_t) {}
|
|
521
|
+
|
|
435
522
|
const char *getStageString() const {
|
|
436
523
|
return "Run";
|
|
437
524
|
}
|
|
@@ -481,6 +568,10 @@ public:
|
|
|
481
568
|
m_local_genstate->populateIov(op.m_seqno, op.m_valuefrags);
|
|
482
569
|
}
|
|
483
570
|
|
|
571
|
+
void populateIov(uint32_t seq, vector<lcb_IOV>& iov_out) {
|
|
572
|
+
m_local_genstate->populateIov(seq, iov_out);
|
|
573
|
+
}
|
|
574
|
+
|
|
484
575
|
void setNextOp(NextOp& op) {
|
|
485
576
|
bool store_override = false;
|
|
486
577
|
|
|
@@ -494,10 +585,10 @@ public:
|
|
|
494
585
|
}
|
|
495
586
|
}
|
|
496
587
|
|
|
497
|
-
if (
|
|
498
|
-
op.m_seqno = m_gensequence->next();
|
|
588
|
+
if (m_in_population || !config.lockTime) {
|
|
589
|
+
op.m_seqno = (m_force_sequential ? m_gensequence : m_genrandom)->next();
|
|
499
590
|
} else {
|
|
500
|
-
op.m_seqno = m_genrandom->
|
|
591
|
+
op.m_seqno = (m_force_sequential ? m_gensequence : m_genrandom)->checkout();
|
|
501
592
|
}
|
|
502
593
|
|
|
503
594
|
if (store_override) {
|
|
@@ -531,6 +622,10 @@ public:
|
|
|
531
622
|
return m_in_population;
|
|
532
623
|
}
|
|
533
624
|
|
|
625
|
+
void checkin(uint32_t seqno) {
|
|
626
|
+
(m_force_sequential ? m_gensequence : m_genrandom)->checkin(seqno);
|
|
627
|
+
}
|
|
628
|
+
|
|
534
629
|
const char *getStageString() const {
|
|
535
630
|
if (m_in_population) {
|
|
536
631
|
return "Populate";
|
|
@@ -554,14 +649,16 @@ private:
|
|
|
554
649
|
uint32_t seqno = op.m_seqno;
|
|
555
650
|
char buffer[21];
|
|
556
651
|
snprintf(buffer, sizeof(buffer), "%020d", seqno);
|
|
557
|
-
|
|
652
|
+
string &prefix = config.useCollections()
|
|
653
|
+
? config.collections[seqno % config.collections.size()]
|
|
654
|
+
: config.getKeyPrefix();
|
|
655
|
+
op.m_key.assign(prefix + buffer);
|
|
558
656
|
}
|
|
559
657
|
|
|
560
658
|
|
|
561
659
|
SeqGenerator *m_genrandom;
|
|
562
660
|
SeqGenerator *m_gensequence;
|
|
563
661
|
size_t m_gencount;
|
|
564
|
-
int m_id;
|
|
565
662
|
|
|
566
663
|
bool m_force_sequential;
|
|
567
664
|
bool m_in_population;
|
|
@@ -571,6 +668,8 @@ private:
|
|
|
571
668
|
SubdocGeneratorState *m_sdgenstate;
|
|
572
669
|
};
|
|
573
670
|
|
|
671
|
+
#define OPFLAGS_LOCKED 0x01
|
|
672
|
+
|
|
574
673
|
class ThreadContext
|
|
575
674
|
{
|
|
576
675
|
public:
|
|
@@ -591,79 +690,52 @@ public:
|
|
|
591
690
|
return gen && (gen->inPopulation() || !retryq.empty());
|
|
592
691
|
}
|
|
593
692
|
|
|
693
|
+
void checkin(uint32_t seqno) {
|
|
694
|
+
if (gen) {
|
|
695
|
+
gen->checkin(seqno);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
594
699
|
void singleLoop() {
|
|
595
700
|
bool hasItems = false;
|
|
596
|
-
NextOp opinfo;
|
|
597
|
-
unsigned exptime = config.getExptime();
|
|
598
701
|
|
|
599
702
|
lcb_sched_enter(instance);
|
|
600
703
|
for (size_t ii = 0; ii < config.opsPerCycle; ++ii) {
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
switch (opinfo.m_mode) {
|
|
604
|
-
case NextOp::STORE: {
|
|
605
|
-
lcb_CMDSTORE scmd = { 0 };
|
|
606
|
-
scmd.operation = LCB_SET;
|
|
607
|
-
scmd.exptime = exptime;
|
|
608
|
-
LCB_CMD_SET_KEY(&scmd, opinfo.m_key.c_str(), opinfo.m_key.size());
|
|
609
|
-
LCB_CMD_SET_VALUEIOV(&scmd, &opinfo.m_valuefrags[0], opinfo.m_valuefrags.size());
|
|
610
|
-
error = lcb_store3(instance, this, &scmd);
|
|
611
|
-
break;
|
|
612
|
-
}
|
|
613
|
-
case NextOp::GET: {
|
|
614
|
-
lcb_CMDGET gcmd = { 0 };
|
|
615
|
-
LCB_CMD_SET_KEY(&gcmd, opinfo.m_key.c_str(), opinfo.m_key.size());
|
|
616
|
-
gcmd.exptime = exptime;
|
|
617
|
-
error = lcb_get3(instance, this, &gcmd);
|
|
618
|
-
break;
|
|
619
|
-
}
|
|
620
|
-
case NextOp::SDSTORE:
|
|
621
|
-
case NextOp::SDGET: {
|
|
622
|
-
lcb_CMDSUBDOC sdcmd = { 0 };
|
|
623
|
-
if (opinfo.m_mode == NextOp::SDSTORE) {
|
|
624
|
-
sdcmd.exptime = exptime;
|
|
625
|
-
}
|
|
626
|
-
LCB_CMD_SET_KEY(&sdcmd, opinfo.m_key.c_str(), opinfo.m_key.size());
|
|
627
|
-
sdcmd.specs = &opinfo.m_specs[0];
|
|
628
|
-
sdcmd.nspecs = opinfo.m_specs.size();
|
|
629
|
-
error = lcb_subdoc3(instance, this, &sdcmd);
|
|
630
|
-
break;
|
|
631
|
-
}
|
|
632
|
-
case NextOp::NOOP: {
|
|
633
|
-
lcb_CMDNOOP ncmd = { 0 };
|
|
634
|
-
error = lcb_noop3(instance, this, &ncmd);
|
|
635
|
-
break;
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
if (error != LCB_SUCCESS) {
|
|
640
|
-
hasItems = false;
|
|
641
|
-
log("Failed to schedule operation: [0x%x] %s", error, lcb_strerror(instance, error));
|
|
642
|
-
} else {
|
|
643
|
-
hasItems = true;
|
|
644
|
-
}
|
|
704
|
+
hasItems = scheduleNextOperation();
|
|
645
705
|
}
|
|
646
706
|
if (hasItems) {
|
|
707
|
+
error = LCB_SUCCESS;
|
|
647
708
|
lcb_sched_leave(instance);
|
|
648
709
|
lcb_wait(instance);
|
|
649
|
-
if (error != LCB_SUCCESS) {
|
|
650
|
-
log("Operation(s) failed: [0x%x] %s", error, lcb_strerror(instance, error));
|
|
651
|
-
}
|
|
652
710
|
} else {
|
|
653
711
|
lcb_sched_fail(instance);
|
|
654
712
|
}
|
|
713
|
+
purgeRetryQueue();
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
void purgeRetryQueue() {
|
|
717
|
+
NextOp opinfo;
|
|
718
|
+
InstanceCookie *cookie = InstanceCookie::get(instance);
|
|
655
719
|
|
|
656
720
|
while (!retryq.empty()) {
|
|
721
|
+
unsigned exptime = config.getExptime();
|
|
657
722
|
lcb_sched_enter(instance);
|
|
658
723
|
while (!retryq.empty()) {
|
|
659
724
|
opinfo = retryq.front();
|
|
660
725
|
retryq.pop();
|
|
661
|
-
|
|
726
|
+
lcb_CMDSTOREDUR scmd = { 0 };
|
|
662
727
|
scmd.operation = LCB_SET;
|
|
663
728
|
scmd.exptime = exptime;
|
|
664
729
|
LCB_CMD_SET_KEY(&scmd, opinfo.m_key.c_str(), opinfo.m_key.size());
|
|
665
730
|
LCB_CMD_SET_VALUEIOV(&scmd, &opinfo.m_valuefrags[0], opinfo.m_valuefrags.size());
|
|
666
|
-
|
|
731
|
+
if (config.persistTo > 0 || config.replicateTo > 0) {
|
|
732
|
+
scmd.persist_to = config.persistTo;
|
|
733
|
+
scmd.replicate_to = config.replicateTo;
|
|
734
|
+
error = lcb_storedur3(instance, NULL, &scmd);
|
|
735
|
+
} else {
|
|
736
|
+
error = lcb_store3(instance, NULL, reinterpret_cast<lcb_CMDSTORE*>(&scmd));
|
|
737
|
+
}
|
|
738
|
+
cookie->stats.retried++;
|
|
667
739
|
}
|
|
668
740
|
lcb_sched_leave(instance);
|
|
669
741
|
lcb_wait(instance);
|
|
@@ -673,11 +745,77 @@ public:
|
|
|
673
745
|
}
|
|
674
746
|
}
|
|
675
747
|
|
|
748
|
+
bool scheduleNextOperation()
|
|
749
|
+
{
|
|
750
|
+
NextOp opinfo;
|
|
751
|
+
unsigned exptime = config.getExptime();
|
|
752
|
+
gen->setNextOp(opinfo);
|
|
753
|
+
|
|
754
|
+
switch (opinfo.m_mode) {
|
|
755
|
+
case NextOp::STORE: {
|
|
756
|
+
if (!gen->inPopulation() && config.lockTime > 0) {
|
|
757
|
+
lcb_CMDGET gcmd = { 0 };
|
|
758
|
+
LCB_CMD_SET_KEY(&gcmd, opinfo.m_key.c_str(), opinfo.m_key.size());
|
|
759
|
+
gcmd.lock = config.lockTime;
|
|
760
|
+
error = lcb_get3(instance, (void *)OPFLAGS_LOCKED, &gcmd);
|
|
761
|
+
} else {
|
|
762
|
+
lcb_CMDSTOREDUR scmd = { 0 };
|
|
763
|
+
scmd.operation = LCB_SET;
|
|
764
|
+
scmd.exptime = exptime;
|
|
765
|
+
if (config.writeJson()) {
|
|
766
|
+
scmd.datatype = LCB_VALUE_F_JSON;
|
|
767
|
+
}
|
|
768
|
+
LCB_CMD_SET_KEY(&scmd, opinfo.m_key.c_str(), opinfo.m_key.size());
|
|
769
|
+
LCB_CMD_SET_VALUEIOV(&scmd, &opinfo.m_valuefrags[0], opinfo.m_valuefrags.size());
|
|
770
|
+
if (config.persistTo > 0 || config.replicateTo > 0) {
|
|
771
|
+
scmd.persist_to = config.persistTo;
|
|
772
|
+
scmd.replicate_to = config.replicateTo;
|
|
773
|
+
error = lcb_storedur3(instance, NULL, &scmd);
|
|
774
|
+
} else {
|
|
775
|
+
error = lcb_store3(instance, NULL, reinterpret_cast<lcb_CMDSTORE*>(&scmd));
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
break;
|
|
779
|
+
}
|
|
780
|
+
case NextOp::GET: {
|
|
781
|
+
lcb_CMDGET gcmd = { 0 };
|
|
782
|
+
LCB_CMD_SET_KEY(&gcmd, opinfo.m_key.c_str(), opinfo.m_key.size());
|
|
783
|
+
gcmd.exptime = exptime;
|
|
784
|
+
error = lcb_get3(instance, this, &gcmd);
|
|
785
|
+
break;
|
|
786
|
+
}
|
|
787
|
+
case NextOp::SDSTORE:
|
|
788
|
+
case NextOp::SDGET: {
|
|
789
|
+
lcb_CMDSUBDOC sdcmd = { 0 };
|
|
790
|
+
if (opinfo.m_mode == NextOp::SDSTORE) {
|
|
791
|
+
sdcmd.exptime = exptime;
|
|
792
|
+
}
|
|
793
|
+
LCB_CMD_SET_KEY(&sdcmd, opinfo.m_key.c_str(), opinfo.m_key.size());
|
|
794
|
+
sdcmd.specs = &opinfo.m_specs[0];
|
|
795
|
+
sdcmd.nspecs = opinfo.m_specs.size();
|
|
796
|
+
error = lcb_subdoc3(instance, NULL, &sdcmd);
|
|
797
|
+
break;
|
|
798
|
+
}
|
|
799
|
+
case NextOp::NOOP: {
|
|
800
|
+
lcb_CMDNOOP ncmd = { 0 };
|
|
801
|
+
error = lcb_noop3(instance, NULL, &ncmd);
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (error != LCB_SUCCESS) {
|
|
807
|
+
log("Failed to schedule operation: [0x%x] %s", error, lcb_strerror(instance, error));
|
|
808
|
+
return false;
|
|
809
|
+
} else {
|
|
810
|
+
return true;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
676
814
|
bool run() {
|
|
677
815
|
do {
|
|
678
816
|
singleLoop();
|
|
679
817
|
|
|
680
|
-
if (config.
|
|
818
|
+
if (config.numTimings() > 1) {
|
|
681
819
|
InstanceCookie::dumpTimings(instance, gen->getStageString());
|
|
682
820
|
}
|
|
683
821
|
if (config.params.shouldDump()) {
|
|
@@ -689,7 +827,7 @@ public:
|
|
|
689
827
|
|
|
690
828
|
} while (!config.isLoopDone(++niter));
|
|
691
829
|
|
|
692
|
-
if (config.
|
|
830
|
+
if (config.numTimings() > 1) {
|
|
693
831
|
InstanceCookie::dumpTimings(instance, gen->getStageString(), true);
|
|
694
832
|
}
|
|
695
833
|
return true;
|
|
@@ -702,13 +840,25 @@ public:
|
|
|
702
840
|
retryq.push(op);
|
|
703
841
|
}
|
|
704
842
|
|
|
843
|
+
void populateIov(uint32_t seq, vector<lcb_IOV>& iov_out)
|
|
844
|
+
{
|
|
845
|
+
gen->populateIov(seq, iov_out);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
|
|
705
849
|
#ifndef WIN32
|
|
706
850
|
pthread_t thr;
|
|
707
851
|
#endif
|
|
708
852
|
|
|
853
|
+
lcb_t getInstance() {
|
|
854
|
+
return instance;
|
|
855
|
+
}
|
|
856
|
+
|
|
709
857
|
protected:
|
|
710
858
|
// the callback methods needs to be able to set the error handler..
|
|
711
859
|
friend void operationCallback(lcb_t, int, const lcb_RESPBASE*);
|
|
860
|
+
friend void storeCallback(lcb_t, int, const lcb_RESPBASE *);
|
|
861
|
+
|
|
712
862
|
Histogram histogram;
|
|
713
863
|
|
|
714
864
|
void setError(lcb_error_t e) { error = e; }
|
|
@@ -743,52 +893,195 @@ private:
|
|
|
743
893
|
std::queue<NextOp> retryq;
|
|
744
894
|
};
|
|
745
895
|
|
|
746
|
-
static void
|
|
896
|
+
static void updateOpsPerSecDisplay()
|
|
747
897
|
{
|
|
748
|
-
ThreadContext *tc;
|
|
749
898
|
|
|
750
|
-
|
|
751
|
-
|
|
899
|
+
static time_t start_time = time(NULL);
|
|
900
|
+
static int is_tty =
|
|
901
|
+
#ifdef WIN32
|
|
902
|
+
0;
|
|
903
|
+
#else
|
|
904
|
+
isatty(STDERR_FILENO);
|
|
905
|
+
#endif
|
|
906
|
+
static volatile unsigned long nops = 0;
|
|
907
|
+
time_t now = time(NULL);
|
|
908
|
+
time_t nsecs = now - start_time;
|
|
909
|
+
if (!nsecs) { nsecs = 1; }
|
|
910
|
+
unsigned long ops_sec = nops / nsecs;
|
|
911
|
+
if (++nops % 10000 == 0) {
|
|
912
|
+
fprintf(stderr, "OPS/SEC: %10lu%c", ops_sec, is_tty ? '\r' : '\n');
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
static void updateStats(InstanceCookie *cookie, lcb_error_t rc)
|
|
917
|
+
{
|
|
918
|
+
cookie->stats.total++;
|
|
919
|
+
switch (rc) {
|
|
920
|
+
case LCB_ETMPFAIL:
|
|
921
|
+
cookie->stats.etmpfail++;
|
|
922
|
+
break;
|
|
923
|
+
case LCB_KEY_EEXISTS:
|
|
924
|
+
cookie->stats.eexist++;
|
|
925
|
+
break;
|
|
926
|
+
case LCB_ETIMEDOUT:
|
|
927
|
+
cookie->stats.etimeout++;
|
|
928
|
+
break;
|
|
929
|
+
default:
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
static void operationCallback(lcb_t instance, int cbtype, const lcb_RESPBASE *resp)
|
|
935
|
+
{
|
|
936
|
+
InstanceCookie *cookie = InstanceCookie::get(instance);
|
|
937
|
+
ThreadContext *tc = cookie->getContext();
|
|
938
|
+
tc->setError(resp->rc);
|
|
939
|
+
updateStats(cookie, resp->rc);
|
|
940
|
+
|
|
941
|
+
uintptr_t flags = 0;
|
|
942
|
+
if (resp->cookie) {
|
|
943
|
+
flags = (uintptr_t)resp->cookie;
|
|
944
|
+
}
|
|
945
|
+
bool done = true;
|
|
946
|
+
string key((const char*)resp->key, resp->nkey);
|
|
947
|
+
uint32_t seqno = atoi(key.c_str());
|
|
948
|
+
if (cbtype == LCB_CALLBACK_GET && (flags & OPFLAGS_LOCKED)) {
|
|
949
|
+
if (resp->rc == LCB_SUCCESS) {
|
|
950
|
+
lcb_CMDSTOREDUR scmd = { 0 };
|
|
951
|
+
vector<lcb_IOV> valuefrags;
|
|
952
|
+
scmd.operation = LCB_SET;
|
|
953
|
+
scmd.exptime = config.getExptime();
|
|
954
|
+
scmd.cas = resp->cas;
|
|
955
|
+
tc->populateIov(seqno, valuefrags);
|
|
956
|
+
LCB_CMD_SET_KEY(&scmd, resp->key, resp->nkey);
|
|
957
|
+
LCB_CMD_SET_VALUEIOV(&scmd, &valuefrags[0], valuefrags.size());
|
|
958
|
+
if (config.persistTo > 0 || config.replicateTo > 0) {
|
|
959
|
+
scmd.persist_to = config.persistTo;
|
|
960
|
+
scmd.replicate_to = config.replicateTo;
|
|
961
|
+
lcb_storedur3(instance, NULL, &scmd);
|
|
962
|
+
} else {
|
|
963
|
+
lcb_store3(instance, NULL, reinterpret_cast<lcb_CMDSTORE*>(&scmd));
|
|
964
|
+
}
|
|
965
|
+
done = false;
|
|
966
|
+
} else if (resp->rc == LCB_ETMPFAIL) {
|
|
967
|
+
NextOp op;
|
|
968
|
+
op.m_mode = NextOp::STORE;
|
|
969
|
+
op.m_key = key;
|
|
970
|
+
op.m_seqno = seqno;
|
|
971
|
+
tc->retry(op);
|
|
972
|
+
done = false;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
if (done) {
|
|
977
|
+
tc->checkin(seqno);
|
|
978
|
+
}
|
|
979
|
+
updateOpsPerSecDisplay();
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
static void storeCallback(lcb_t instance, int, const lcb_RESPBASE *resp)
|
|
983
|
+
{
|
|
984
|
+
InstanceCookie *cookie = InstanceCookie::get(instance);
|
|
985
|
+
ThreadContext *tc = cookie->getContext();
|
|
986
|
+
tc->setError(resp->rc);
|
|
987
|
+
updateStats(cookie, resp->rc);
|
|
988
|
+
|
|
989
|
+
string key((const char*)resp->key, resp->nkey);
|
|
990
|
+
uint32_t seqno = atoi(key.c_str());
|
|
991
|
+
if (resp->rc != LCB_SUCCESS && tc->inPopulation()) {
|
|
752
992
|
NextOp op;
|
|
753
993
|
op.m_mode = NextOp::STORE;
|
|
754
|
-
op.m_key
|
|
755
|
-
op.m_seqno =
|
|
994
|
+
op.m_key = key;
|
|
995
|
+
op.m_seqno = seqno;
|
|
756
996
|
tc->retry(op);
|
|
757
997
|
} else {
|
|
758
|
-
tc->
|
|
998
|
+
tc->checkin(seqno);
|
|
759
999
|
}
|
|
760
1000
|
|
|
761
|
-
|
|
762
|
-
static volatile unsigned long nops = 1;
|
|
763
|
-
static time_t start_time = time(NULL);
|
|
764
|
-
static int is_tty = isatty(STDERR_FILENO);
|
|
765
|
-
if (is_tty) {
|
|
766
|
-
if (++nops % 1000 == 0) {
|
|
767
|
-
time_t now = time(NULL);
|
|
768
|
-
time_t nsecs = now - start_time;
|
|
769
|
-
if (!nsecs) { nsecs = 1; }
|
|
770
|
-
unsigned long ops_sec = nops / nsecs;
|
|
771
|
-
fprintf(stderr, "OPS/SEC: %10lu\r", ops_sec);
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
#endif
|
|
1001
|
+
updateOpsPerSecDisplay();
|
|
775
1002
|
}
|
|
776
1003
|
|
|
777
|
-
|
|
778
1004
|
std::list<ThreadContext *> contexts;
|
|
779
1005
|
|
|
780
1006
|
extern "C" {
|
|
781
|
-
|
|
1007
|
+
typedef void (*handler_t)(int);
|
|
1008
|
+
|
|
1009
|
+
static void dump_metrics(void)
|
|
1010
|
+
{
|
|
1011
|
+
std::list<ThreadContext *>::iterator it;
|
|
1012
|
+
for (it = contexts.begin(); it != contexts.end(); ++it) {
|
|
1013
|
+
lcb_t instance = (*it)->getInstance();
|
|
1014
|
+
lcb_CMDDIAG req = {};
|
|
1015
|
+
req.options = LCB_PINGOPT_F_JSONPRETTY;
|
|
1016
|
+
lcb_diag(instance, NULL, &req);
|
|
1017
|
+
if (config.numTimings() > 0) {
|
|
1018
|
+
InstanceCookie::dumpTimings(instance);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
782
1021
|
}
|
|
783
1022
|
|
|
784
1023
|
#ifndef WIN32
|
|
1024
|
+
static void diag_callback(lcb_t instance, int, const lcb_RESPBASE *rb)
|
|
1025
|
+
{
|
|
1026
|
+
const lcb_RESPDIAG *resp = (const lcb_RESPDIAG *)rb;
|
|
1027
|
+
if (resp->rc != LCB_SUCCESS) {
|
|
1028
|
+
fprintf(stderr, "%p, diag failed: %s\n", (void *)instance, lcb_strerror(NULL, resp->rc));
|
|
1029
|
+
} else {
|
|
1030
|
+
if (resp->njson) {
|
|
1031
|
+
fprintf(stderr, "\n%.*s", (int)resp->njson, resp->json);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
{
|
|
1035
|
+
InstanceCookie *cookie = InstanceCookie::get(instance);
|
|
1036
|
+
lcb_METRICS* metrics;
|
|
1037
|
+
size_t ii;
|
|
1038
|
+
lcb_cntl(instance, LCB_CNTL_GET, LCB_CNTL_METRICS, &metrics);
|
|
1039
|
+
|
|
1040
|
+
fprintf(stderr, "%p: total: %lu, etmpfail: %lu, eexist: %lu, etimeout: %lu, retried: %lu, rq: %lu\n",
|
|
1041
|
+
(void *)instance,
|
|
1042
|
+
(unsigned long)cookie->stats.total,
|
|
1043
|
+
(unsigned long)cookie->stats.etmpfail,
|
|
1044
|
+
(unsigned long)cookie->stats.eexist,
|
|
1045
|
+
(unsigned long)cookie->stats.etimeout,
|
|
1046
|
+
(unsigned long)cookie->stats.retried,
|
|
1047
|
+
(unsigned long)metrics->packets_retried);
|
|
1048
|
+
for (ii = 0; ii < metrics->nservers; ii++) {
|
|
1049
|
+
fprintf(stderr, " [srv-%d] snt: %lu, rcv: %lu, q: %lu, err: %lu, tmo: %lu, nmv: %lu, orph: %lu\n",
|
|
1050
|
+
(int)ii,
|
|
1051
|
+
(unsigned long)metrics->servers[ii]->packets_sent,
|
|
1052
|
+
(unsigned long)metrics->servers[ii]->packets_read,
|
|
1053
|
+
(unsigned long)metrics->servers[ii]->packets_queued,
|
|
1054
|
+
(unsigned long)metrics->servers[ii]->packets_errored,
|
|
1055
|
+
(unsigned long)metrics->servers[ii]->packets_timeout,
|
|
1056
|
+
(unsigned long)metrics->servers[ii]->packets_nmv,
|
|
1057
|
+
(unsigned long)metrics->servers[ii]->packets_ownerless);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
static void sigquit_handler(int)
|
|
1064
|
+
{
|
|
1065
|
+
dump_metrics();
|
|
1066
|
+
signal(SIGQUIT, sigquit_handler); // Reinstall
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
static void setup_sigquit_handler()
|
|
1070
|
+
{
|
|
1071
|
+
struct sigaction action;
|
|
1072
|
+
sigemptyset(&action.sa_mask);
|
|
1073
|
+
action.sa_handler = sigquit_handler;
|
|
1074
|
+
action.sa_flags = 0;
|
|
1075
|
+
sigaction(SIGQUIT, &action, NULL);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
785
1078
|
static void sigint_handler(int)
|
|
786
1079
|
{
|
|
787
1080
|
static int ncalled = 0;
|
|
788
1081
|
ncalled++;
|
|
789
1082
|
|
|
790
1083
|
if (ncalled < 2) {
|
|
791
|
-
log("
|
|
1084
|
+
log("\nTermination requested. Waiting threads to finish. Ctrl-C to force termination.");
|
|
792
1085
|
signal(SIGINT, sigint_handler); // Reinstall
|
|
793
1086
|
config.maxCycles = 0;
|
|
794
1087
|
return;
|
|
@@ -811,9 +1104,7 @@ static void setup_sigint_handler()
|
|
|
811
1104
|
sigaction(SIGINT, &action, NULL);
|
|
812
1105
|
}
|
|
813
1106
|
|
|
814
|
-
extern "C" {
|
|
815
1107
|
static void* thread_worker(void*);
|
|
816
|
-
}
|
|
817
1108
|
|
|
818
1109
|
static void start_worker(ThreadContext *ctx)
|
|
819
1110
|
{
|
|
@@ -837,12 +1128,12 @@ static void join_worker(ThreadContext *ctx)
|
|
|
837
1128
|
}
|
|
838
1129
|
|
|
839
1130
|
#else
|
|
1131
|
+
static void setup_sigquit_handler() {}
|
|
840
1132
|
static void setup_sigint_handler() {}
|
|
841
1133
|
static void start_worker(ThreadContext *ctx) { ctx->run(); }
|
|
842
1134
|
static void join_worker(ThreadContext *ctx) { (void)ctx; }
|
|
843
1135
|
#endif
|
|
844
1136
|
|
|
845
|
-
extern "C" {
|
|
846
1137
|
static void *thread_worker(void *arg)
|
|
847
1138
|
{
|
|
848
1139
|
ThreadContext *ctx = static_cast<ThreadContext *>(arg);
|
|
@@ -855,6 +1146,7 @@ int main(int argc, char **argv)
|
|
|
855
1146
|
{
|
|
856
1147
|
int exit_code = EXIT_SUCCESS;
|
|
857
1148
|
setup_sigint_handler();
|
|
1149
|
+
setup_sigquit_handler();
|
|
858
1150
|
|
|
859
1151
|
Parser parser("cbc-pillowfight");
|
|
860
1152
|
try {
|
|
@@ -890,14 +1182,26 @@ int main(int argc, char **argv)
|
|
|
890
1182
|
log("Failed to create instance: %s", lcb_strerror(NULL, error));
|
|
891
1183
|
exit(EXIT_FAILURE);
|
|
892
1184
|
}
|
|
893
|
-
lcb_install_callback3(instance,
|
|
1185
|
+
lcb_install_callback3(instance, LCB_CALLBACK_STOREDUR, storeCallback);
|
|
1186
|
+
lcb_install_callback3(instance, LCB_CALLBACK_STORE, storeCallback);
|
|
894
1187
|
lcb_install_callback3(instance, LCB_CALLBACK_GET, operationCallback);
|
|
895
1188
|
lcb_install_callback3(instance, LCB_CALLBACK_SDMUTATE, operationCallback);
|
|
896
1189
|
lcb_install_callback3(instance, LCB_CALLBACK_SDLOOKUP, operationCallback);
|
|
897
1190
|
lcb_install_callback3(instance, LCB_CALLBACK_NOOP, operationCallback);
|
|
1191
|
+
#ifndef WIN32
|
|
1192
|
+
lcb_install_callback3(instance, LCB_CALLBACK_DIAG, diag_callback);
|
|
1193
|
+
{
|
|
1194
|
+
int activate = 1;
|
|
1195
|
+
lcb_cntl(instance, LCB_CNTL_SET, LCB_CNTL_METRICS, &activate);
|
|
1196
|
+
}
|
|
1197
|
+
#endif
|
|
898
1198
|
cp.doCtls(instance);
|
|
1199
|
+
if (config.useCollections()) {
|
|
1200
|
+
int use = 1;
|
|
1201
|
+
lcb_cntl(instance, LCB_CNTL_SET, LCB_CNTL_USE_COLLECTIONS, &use);
|
|
1202
|
+
}
|
|
899
1203
|
|
|
900
|
-
new InstanceCookie(instance);
|
|
1204
|
+
InstanceCookie *cookie = new InstanceCookie(instance);
|
|
901
1205
|
|
|
902
1206
|
lcb_connect(instance);
|
|
903
1207
|
lcb_wait(instance);
|
|
@@ -910,6 +1214,7 @@ int main(int argc, char **argv)
|
|
|
910
1214
|
}
|
|
911
1215
|
|
|
912
1216
|
ThreadContext *ctx = new ThreadContext(instance, ii);
|
|
1217
|
+
cookie->setContext(ctx);
|
|
913
1218
|
contexts.push_back(ctx);
|
|
914
1219
|
start_worker(ctx);
|
|
915
1220
|
}
|
|
@@ -918,5 +1223,8 @@ int main(int argc, char **argv)
|
|
|
918
1223
|
it != contexts.end(); ++it) {
|
|
919
1224
|
join_worker(*it);
|
|
920
1225
|
}
|
|
1226
|
+
if (config.numTimings() > 0) {
|
|
1227
|
+
dump_metrics();
|
|
1228
|
+
}
|
|
921
1229
|
return exit_code;
|
|
922
1230
|
}
|