libcouchbase 1.2.8 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|