libcouchbase 1.0.4 → 1.1.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 +11 -8
- data/ext/libcouchbase/CMakeLists.txt +1 -1
- data/ext/libcouchbase/README.markdown +38 -6
- data/ext/libcouchbase/RELEASE_NOTES.markdown +151 -0
- data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -2
- data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
- data/ext/libcouchbase/cmake/source_files.cmake +1 -0
- data/ext/libcouchbase/contrib/cJSON/cJSON.c +686 -288
- data/ext/libcouchbase/contrib/cJSON/cJSON.h +0 -0
- data/ext/libcouchbase/contrib/cbsasl/src/hash.c +17 -17
- data/ext/libcouchbase/contrib/cliopts/cliopts.c +76 -0
- data/ext/libcouchbase/contrib/cliopts/cliopts.h +66 -15
- data/ext/libcouchbase/contrib/genhash/genhash.c +1 -2
- data/ext/libcouchbase/contrib/lcb-jsoncpp/lcb-jsoncpp.cpp +4 -3
- data/ext/libcouchbase/example/instancepool/main.cc +12 -2
- data/ext/libcouchbase/example/libeventdirect/main.c +99 -25
- data/ext/libcouchbase/example/minimal/minimal.c +7 -5
- data/ext/libcouchbase/example/observe/durability.c +102 -0
- data/ext/libcouchbase/example/observe/observe.c +19 -6
- data/ext/libcouchbase/example/subdoc/subdoc-xattrs.c +1 -2
- data/ext/libcouchbase/include/libcouchbase/cntl-private.h +6 -8
- data/ext/libcouchbase/include/libcouchbase/cntl.h +84 -64
- data/ext/libcouchbase/include/libcouchbase/couchbase.h +295 -78
- data/ext/libcouchbase/include/libcouchbase/deprecated.h +2 -2
- data/ext/libcouchbase/include/libcouchbase/error.h +1 -1
- data/ext/libcouchbase/include/libcouchbase/iops.h +9 -9
- data/ext/libcouchbase/include/libcouchbase/ixmgmt.h +2 -2
- data/ext/libcouchbase/include/libcouchbase/n1ql.h +69 -7
- data/ext/libcouchbase/include/libcouchbase/vbucket.h +17 -0
- data/ext/libcouchbase/include/libcouchbase/views.h +3 -3
- data/ext/libcouchbase/include/memcached/protocol_binary.h +62 -1
- data/ext/libcouchbase/packaging/deb/control +1 -1
- data/ext/libcouchbase/packaging/rpm/libcouchbase.spec.in +37 -36
- data/ext/libcouchbase/src/bootstrap.cc +22 -8
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +1 -1
- data/ext/libcouchbase/src/bucketconfig/bc_http.cc +0 -1
- data/ext/libcouchbase/src/bucketconfig/confmon.cc +13 -8
- data/ext/libcouchbase/src/callbacks.c +2 -0
- data/ext/libcouchbase/src/cntl.cc +28 -17
- data/ext/libcouchbase/src/dns-srv.cc +1 -2
- data/ext/libcouchbase/src/dump.cc +4 -0
- data/ext/libcouchbase/src/errmap.h +89 -16
- data/ext/libcouchbase/src/handler.cc +28 -11
- data/ext/libcouchbase/src/http/http-priv.h +4 -1
- data/ext/libcouchbase/src/http/http.cc +3 -0
- data/ext/libcouchbase/src/instance.cc +1 -1
- data/ext/libcouchbase/src/internal.h +1 -0
- data/ext/libcouchbase/src/lcbio/connect.cc +2 -3
- data/ext/libcouchbase/src/lcbio/manager.cc +2 -2
- data/ext/libcouchbase/src/lcbio/ssl.h +10 -0
- data/ext/libcouchbase/src/mc/mcreq.c +8 -0
- data/ext/libcouchbase/src/mcserver/mcserver.cc +14 -1
- data/ext/libcouchbase/src/n1ql/ixmgmt.cc +0 -3
- data/ext/libcouchbase/src/n1ql/n1ql.cc +22 -29
- data/ext/libcouchbase/src/n1ql/params.cc +46 -1
- data/ext/libcouchbase/src/newconfig.cc +4 -4
- data/ext/libcouchbase/src/operations/durability-seqno.cc +4 -0
- data/ext/libcouchbase/src/operations/durability.cc +3 -0
- data/ext/libcouchbase/src/operations/ping.cc +315 -0
- data/ext/libcouchbase/src/operations/stats.cc +10 -0
- data/ext/libcouchbase/src/operations/subdoc.cc +13 -1
- data/ext/libcouchbase/src/retrychk.cc +1 -0
- data/ext/libcouchbase/src/settings.c +2 -0
- data/ext/libcouchbase/src/settings.h +13 -7
- data/ext/libcouchbase/src/ssl/ssl_c.c +28 -2
- data/ext/libcouchbase/src/ssl/ssl_common.c +3 -0
- data/ext/libcouchbase/src/ssl/ssl_e.c +15 -1
- data/ext/libcouchbase/src/ssl/ssl_iot_common.h +3 -1
- data/ext/libcouchbase/src/timings.c +0 -1
- data/ext/libcouchbase/src/vbucket/vbucket.c +49 -1
- data/ext/libcouchbase/tests/iotests/mock-environment.cc +58 -40
- data/ext/libcouchbase/tests/iotests/mock-environment.h +23 -4
- data/ext/libcouchbase/tests/iotests/mock-unit-test.h +8 -8
- data/ext/libcouchbase/tests/iotests/t_behavior.cc +5 -5
- data/ext/libcouchbase/tests/iotests/t_durability.cc +50 -0
- data/ext/libcouchbase/tests/iotests/t_eerrs.cc +4 -2
- data/ext/libcouchbase/tests/iotests/t_errmap.cc +6 -3
- data/ext/libcouchbase/tests/iotests/t_lock.cc +5 -6
- data/ext/libcouchbase/tests/iotests/t_misc.cc +44 -0
- data/ext/libcouchbase/tests/iotests/t_serverops.cc +1 -0
- data/ext/libcouchbase/tests/iotests/t_subdoc.cc +28 -0
- data/ext/libcouchbase/tests/iotests/t_views.cc +22 -10
- data/ext/libcouchbase/tools/CMakeLists.txt +21 -1
- data/ext/libcouchbase/tools/cbc-handlers.h +23 -3
- data/ext/libcouchbase/tools/cbc-n1qlback.cc +1 -1
- data/ext/libcouchbase/tools/cbc-pillowfight.cc +126 -26
- data/ext/libcouchbase/tools/cbc-proxy.cc +403 -0
- data/ext/libcouchbase/tools/cbc-subdoc.cc +826 -0
- data/ext/libcouchbase/tools/cbc.cc +149 -37
- data/ext/libcouchbase/tools/common/options.h +5 -2
- data/ext/libcouchbase/tools/linenoise/linenoise.c +15 -15
- data/lib/libcouchbase.rb +4 -0
- data/lib/libcouchbase/bucket.rb +51 -0
- data/lib/libcouchbase/connection.rb +100 -13
- data/lib/libcouchbase/ext/libcouchbase.rb +40 -0
- data/lib/libcouchbase/ext/libcouchbase/cmdsubdoc.rb +13 -1
- data/lib/libcouchbase/ext/libcouchbase/enums.rb +2 -1
- data/lib/libcouchbase/ext/libcouchbase/sdspec.rb +5 -0
- data/lib/libcouchbase/subdoc_request.rb +129 -0
- data/lib/libcouchbase/version.rb +1 -1
- data/spec/bucket_spec.rb +15 -1
- data/spec/connection_spec.rb +1 -1
- data/spec/subdoc_spec.rb +192 -0
- metadata +13 -4
- data/ext/libcouchbase/.travis.yml +0 -19
|
@@ -78,7 +78,8 @@ struct Request {
|
|
|
78
78
|
bool is_data_request() const {
|
|
79
79
|
return reqtype == LCB_HTTP_TYPE_N1QL ||
|
|
80
80
|
reqtype == LCB_HTTP_TYPE_VIEW ||
|
|
81
|
-
reqtype == LCB_HTTP_TYPE_FTS
|
|
81
|
+
reqtype == LCB_HTTP_TYPE_FTS ||
|
|
82
|
+
reqtype == LCB_HTTP_TYPE_CBAS;
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
/**
|
|
@@ -310,6 +311,8 @@ struct Request {
|
|
|
310
311
|
|
|
311
312
|
/** overrides default timeout if nonzero */
|
|
312
313
|
const uint32_t user_timeout;
|
|
314
|
+
|
|
315
|
+
hrtime_t start; /**< Start time */
|
|
313
316
|
};
|
|
314
317
|
|
|
315
318
|
} // namespace: http
|
|
@@ -368,6 +368,8 @@ httype2svctype(unsigned httype)
|
|
|
368
368
|
return LCBVB_SVCTYPE_N1QL;
|
|
369
369
|
case LCB_HTTP_TYPE_FTS:
|
|
370
370
|
return LCBVB_SVCTYPE_FTS;
|
|
371
|
+
case LCB_HTTP_TYPE_CBAS:
|
|
372
|
+
return LCBVB_SVCTYPE_CBAS;
|
|
371
373
|
default:
|
|
372
374
|
return LCBVB_SVCTYPE__MAX;
|
|
373
375
|
}
|
|
@@ -548,6 +550,7 @@ Request::create(lcb_t instance,
|
|
|
548
550
|
*rc = LCB_CLIENT_ENOMEM;
|
|
549
551
|
return NULL;
|
|
550
552
|
}
|
|
553
|
+
req->start = gethrtime();
|
|
551
554
|
|
|
552
555
|
*rc = req->setup_inputs(cmd);
|
|
553
556
|
if (*rc != LCB_SUCCESS) {
|
|
@@ -129,7 +129,7 @@ lcb_st::process_dns_srv(Connspec& spec)
|
|
|
129
129
|
|
|
130
130
|
const Spechost& host = spec.hosts().front();
|
|
131
131
|
lcb_error_t rc = LCB_ERROR;
|
|
132
|
-
Hostlist* hl = dnssrv_getbslist(host.hostname.c_str(),
|
|
132
|
+
Hostlist* hl = dnssrv_getbslist(host.hostname.c_str(), spec.sslopts() & LCB_SSL_ENABLED, rc);
|
|
133
133
|
|
|
134
134
|
if (hl == NULL) {
|
|
135
135
|
lcb_log(LOGARGS(this, INFO), "DNS SRV lookup failed: %s. Ignore this if not relying on DNS SRV records", lcb_strerror(this, rc));
|
|
@@ -132,6 +132,7 @@ struct lcb_st {
|
|
|
132
132
|
lcb_MUTATION_TOKEN *dcpinfo; /**< Mapping of known vbucket to {uuid,seqno} info */
|
|
133
133
|
lcbio_pTIMER dtor_timer; /**< Asynchronous destruction timer */
|
|
134
134
|
int type; /**< Type of connection */
|
|
135
|
+
lcb_BTYPE btype; /**< Type of the bucket */
|
|
135
136
|
|
|
136
137
|
#ifdef __cplusplus
|
|
137
138
|
lcb_settings* getSettings() { return settings; }
|
|
@@ -302,7 +302,6 @@ E_conncb(lcb_socket_t, short events, void *arg)
|
|
|
302
302
|
goto GT_NEXTSOCK;
|
|
303
303
|
|
|
304
304
|
} else {
|
|
305
|
-
rv = 0;
|
|
306
305
|
ai = cs->ai;
|
|
307
306
|
|
|
308
307
|
GT_CONNECT:
|
|
@@ -434,8 +433,8 @@ lcbio_connect(lcbio_TABLE *iot, lcb_settings *settings, const lcb_host_t *dest,
|
|
|
434
433
|
|
|
435
434
|
Connstart::Connstart(lcbio_TABLE* iot_, lcb_settings* settings_,
|
|
436
435
|
const lcb_host_t *dest, uint32_t timeout,
|
|
437
|
-
lcbio_CONNDONE_cb
|
|
438
|
-
: user_handler(
|
|
436
|
+
lcbio_CONNDONE_cb handler_, void *arg)
|
|
437
|
+
: user_handler(handler_), user_arg(arg), sock(NULL), syserr(0),
|
|
439
438
|
event(NULL), ev_active(false), in_uhandler(false),
|
|
440
439
|
ai_root(NULL), ai(NULL), state(CS_PENDING), last_error(LCB_SUCCESS),
|
|
441
440
|
timer(iot_, this) {
|
|
@@ -289,8 +289,8 @@ void PoolConnInfo::on_connected(lcbio_SOCKET *sock_, lcb_error_t err) {
|
|
|
289
289
|
|
|
290
290
|
if (err != LCB_SUCCESS) {
|
|
291
291
|
/** If the connection failed, fail out all remaining requests */
|
|
292
|
-
lcb_list_t *cur, *
|
|
293
|
-
LCB_LIST_SAFE_FOR(cur,
|
|
292
|
+
lcb_list_t *cur, *nxt;
|
|
293
|
+
LCB_LIST_SAFE_FOR(cur, nxt, (lcb_list_t *)&parent->requests) {
|
|
294
294
|
PoolRequest *req = PoolRequest::from_llnode(cur);
|
|
295
295
|
lcb_clist_delete(&parent->requests, req);
|
|
296
296
|
req->sock = NULL;
|
|
@@ -26,6 +26,16 @@ extern "C" {
|
|
|
26
26
|
* @file
|
|
27
27
|
* @brief SSL Socket Routines
|
|
28
28
|
*/
|
|
29
|
+
#ifndef LCB_NO_SSL
|
|
30
|
+
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
31
|
+
// OpenSSL 1.1 has changed behavior of BIO_get_mem_ptr behavior, so we cannot
|
|
32
|
+
// apply reduce-memory-copy optimization, and fallback to BIO_write
|
|
33
|
+
// Reference: https://github.com/openssl/openssl/commit/9fe9d0461ea
|
|
34
|
+
#define LCB_CAN_OPTIMIZE_SSL_BIO 1
|
|
35
|
+
#else
|
|
36
|
+
#define LCB_CAN_OPTIMIZE_SSL_BIO 0
|
|
37
|
+
#endif
|
|
38
|
+
#endif
|
|
29
39
|
|
|
30
40
|
/**
|
|
31
41
|
* @ingroup lcbio
|
|
@@ -362,6 +362,8 @@ mcreq_renew_packet(const mc_PACKET *src)
|
|
|
362
362
|
assert(vdata == inflated);
|
|
363
363
|
|
|
364
364
|
if (rv != 0) {
|
|
365
|
+
/* TODO: log error details when snappy will be enabled */
|
|
366
|
+
free(edst);
|
|
365
367
|
return NULL;
|
|
366
368
|
}
|
|
367
369
|
nvdata = n_inflated;
|
|
@@ -461,6 +463,9 @@ mcreq_basic_packet(
|
|
|
461
463
|
if (!queue->config) {
|
|
462
464
|
return LCB_CLIENT_ETMPFAIL;
|
|
463
465
|
}
|
|
466
|
+
if (!cmd) {
|
|
467
|
+
return LCB_EINVAL;
|
|
468
|
+
}
|
|
464
469
|
|
|
465
470
|
mcreq_map_key(queue, &cmd->key, &cmd->_hashkey,
|
|
466
471
|
sizeof(*req) + extlen, &vb, &srvix);
|
|
@@ -476,6 +481,9 @@ mcreq_basic_packet(
|
|
|
476
481
|
}
|
|
477
482
|
|
|
478
483
|
*packet = mcreq_allocate_packet(*pipeline);
|
|
484
|
+
if (*packet == NULL) {
|
|
485
|
+
return LCB_CLIENT_ENOMEM;
|
|
486
|
+
}
|
|
479
487
|
|
|
480
488
|
mcreq_reserve_key(*pipeline, *packet, sizeof(*req) + extlen, &cmd->key);
|
|
481
489
|
|
|
@@ -261,6 +261,19 @@ int Server::handle_unknown_error(const mc_PACKET *request,
|
|
|
261
261
|
newerr = LCB_GENERIC_SUBDOCERR;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
/* TODO: remove masking LOCKED in 3.0 release */
|
|
265
|
+
if (err.hasAttribute(errmap::ITEM_LOCKED)) {
|
|
266
|
+
switch (mcresp.opcode()) {
|
|
267
|
+
case PROTOCOL_BINARY_CMD_SET:
|
|
268
|
+
case PROTOCOL_BINARY_CMD_REPLACE:
|
|
269
|
+
case PROTOCOL_BINARY_CMD_DELETE:
|
|
270
|
+
newerr = LCB_KEY_EEXISTS;
|
|
271
|
+
break;
|
|
272
|
+
default:
|
|
273
|
+
newerr = LCB_ETMPFAIL;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
264
277
|
int rv = 0;
|
|
265
278
|
|
|
266
279
|
if (err.hasAttribute(errmap::AUTO_RETRY)) {
|
|
@@ -385,7 +398,7 @@ Server::try_read(lcbio_CTX *ctx, rdb_IOROPE *ior)
|
|
|
385
398
|
/* figure out how many buffers we want to use as an upper limit for the
|
|
386
399
|
* IOV arrays. Currently we'll keep it simple and ensure the entire
|
|
387
400
|
* response is contiguous. */
|
|
388
|
-
lcb_PKTFWDRESP resp = { 0 };
|
|
401
|
+
lcb_PKTFWDRESP resp = { 0 }; /* TODO: next ABI version should include is_last flag */
|
|
389
402
|
rdb_ROPESEG *segs;
|
|
390
403
|
nb_IOV iov;
|
|
391
404
|
|
|
@@ -407,9 +407,6 @@ do_index_list(lcb_t instance, const void *cookie, const lcb_CMDN1XMGMT *cmd,
|
|
|
407
407
|
if (spec.ixtype) {
|
|
408
408
|
const char *s_ixtype = ixtype_2_str(spec.ixtype);
|
|
409
409
|
if (s_ixtype == NULL) {
|
|
410
|
-
if (ctx != NULL) {
|
|
411
|
-
delete ctx;
|
|
412
|
-
}
|
|
413
410
|
return LCB_EINVAL;
|
|
414
411
|
}
|
|
415
412
|
ss.append(" using=\"").append(s_ixtype).append("\" AND");
|
|
@@ -155,9 +155,6 @@ typedef struct lcb_N1QLREQ : lcb::jsparse::Parser::Actions {
|
|
|
155
155
|
// How many rows were received. Used to avoid parsing the meta
|
|
156
156
|
size_t nrows;
|
|
157
157
|
|
|
158
|
-
// Host for CBAS/Analytics query
|
|
159
|
-
std::string cbashost;
|
|
160
|
-
|
|
161
158
|
/** The PREPARE query itself */
|
|
162
159
|
struct lcb_N1QLREQ *prepare_req;
|
|
163
160
|
|
|
@@ -171,6 +168,9 @@ typedef struct lcb_N1QLREQ : lcb::jsparse::Parser::Actions {
|
|
|
171
168
|
/** Whether we're retrying this */
|
|
172
169
|
bool was_retried;
|
|
173
170
|
|
|
171
|
+
/** Is this query to Analytics (CBAS) service */
|
|
172
|
+
bool is_cbas;
|
|
173
|
+
|
|
174
174
|
lcb_N1QLCACHE& cache() { return *instance->n1ql_cache; }
|
|
175
175
|
|
|
176
176
|
/**
|
|
@@ -208,6 +208,11 @@ typedef struct lcb_N1QLREQ : lcb::jsparse::Parser::Actions {
|
|
|
208
208
|
*/
|
|
209
209
|
inline bool maybe_retry();
|
|
210
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Returns true if payload matches retry conditions.
|
|
213
|
+
*/
|
|
214
|
+
inline bool has_retriable_error(const Json::Value& root);
|
|
215
|
+
|
|
211
216
|
/**
|
|
212
217
|
* Did the application request this query to use prepared statements
|
|
213
218
|
* @return true if using prepared statements
|
|
@@ -230,10 +235,6 @@ typedef struct lcb_N1QLREQ : lcb::jsparse::Parser::Actions {
|
|
|
230
235
|
*/
|
|
231
236
|
inline void fail_prepared(const lcb_RESPN1QL *orig, lcb_error_t err);
|
|
232
237
|
|
|
233
|
-
bool is_cbas() const {
|
|
234
|
-
return !cbashost.empty();
|
|
235
|
-
}
|
|
236
|
-
|
|
237
238
|
inline lcb_N1QLREQ(lcb_t obj, const void *user_cookie, const lcb_CMDN1QL *cmd);
|
|
238
239
|
inline ~lcb_N1QLREQ();
|
|
239
240
|
|
|
@@ -298,8 +299,8 @@ static const char *wtf_magic_strings[] = {
|
|
|
298
299
|
NULL
|
|
299
300
|
};
|
|
300
301
|
|
|
301
|
-
|
|
302
|
-
has_retriable_error(const Json::Value& root)
|
|
302
|
+
bool
|
|
303
|
+
N1QLREQ::has_retriable_error(const Json::Value& root)
|
|
303
304
|
{
|
|
304
305
|
if (!root.isObject()) {
|
|
305
306
|
return false;
|
|
@@ -316,9 +317,11 @@ has_retriable_error(const Json::Value& root)
|
|
|
316
317
|
}
|
|
317
318
|
const Json::Value& jmsg = cur["msg"];
|
|
318
319
|
const Json::Value& jcode = cur["code"];
|
|
320
|
+
unsigned code = 0;
|
|
319
321
|
if (jcode.isNumeric()) {
|
|
320
|
-
|
|
322
|
+
code = jcode.asUInt();
|
|
321
323
|
if (code == 4050 || code == 4070) {
|
|
324
|
+
lcb_log(LOGARGS(this, TRACE), LOGFMT "Will retry request. code: %d", LOGID(this), code);
|
|
322
325
|
return true;
|
|
323
326
|
}
|
|
324
327
|
}
|
|
@@ -326,6 +329,7 @@ has_retriable_error(const Json::Value& root)
|
|
|
326
329
|
const char *jmstr = jmsg.asCString();
|
|
327
330
|
for (const char **curs = wtf_magic_strings; *curs; curs++) {
|
|
328
331
|
if (!strstr(jmstr, *curs)) {
|
|
332
|
+
lcb_log(LOGARGS(this, TRACE), LOGFMT "Will retry request. code: %d, msg: %s", LOGID(this), code, jmstr);
|
|
329
333
|
return true;
|
|
330
334
|
}
|
|
331
335
|
}
|
|
@@ -458,8 +462,6 @@ chunk_callback(lcb_t instance, int ign, const lcb_RESPBASE *rb)
|
|
|
458
462
|
req->parser->feed(static_cast<const char*>(rh->body), rh->nbody);
|
|
459
463
|
}
|
|
460
464
|
|
|
461
|
-
#define QUERY_PATH "/query/service"
|
|
462
|
-
|
|
463
465
|
void
|
|
464
466
|
N1QLREQ::fail_prepared(const lcb_RESPN1QL *orig, lcb_error_t err)
|
|
465
467
|
{
|
|
@@ -523,9 +525,8 @@ N1QLREQ::issue_htreq(const std::string& body)
|
|
|
523
525
|
htcmd.content_type = "application/json";
|
|
524
526
|
htcmd.method = LCB_HTTP_METHOD_POST;
|
|
525
527
|
|
|
526
|
-
if (is_cbas
|
|
527
|
-
htcmd.type =
|
|
528
|
-
htcmd.host = cbashost.c_str();
|
|
528
|
+
if (is_cbas) {
|
|
529
|
+
htcmd.type = LCB_HTTP_TYPE_CBAS;
|
|
529
530
|
} else {
|
|
530
531
|
htcmd.type = LCB_HTTP_TYPE_N1QL;
|
|
531
532
|
}
|
|
@@ -607,7 +608,7 @@ lcb_N1QLREQ::lcb_N1QLREQ(lcb_t obj,
|
|
|
607
608
|
parser(new lcb::jsparse::Parser(lcb::jsparse::Parser::MODE_N1QL, this)),
|
|
608
609
|
cookie(user_cookie), callback(cmd->callback), instance(obj),
|
|
609
610
|
lasterr(LCB_SUCCESS), flags(cmd->cmdflags), timeout(0),
|
|
610
|
-
nrows(0), prepare_req(NULL), was_retried(false)
|
|
611
|
+
nrows(0), prepare_req(NULL), was_retried(false), is_cbas(false)
|
|
611
612
|
{
|
|
612
613
|
if (cmd->handle) {
|
|
613
614
|
*cmd->handle = this;
|
|
@@ -621,19 +622,11 @@ lcb_N1QLREQ::lcb_N1QLREQ(lcb_t obj,
|
|
|
621
622
|
}
|
|
622
623
|
|
|
623
624
|
if (flags & LCB_CMDN1QL_F_CBASQUERY) {
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
if (cbashost.empty()) {
|
|
630
|
-
lasterr = LCB_EINVAL;
|
|
631
|
-
return;
|
|
632
|
-
}
|
|
633
|
-
if (flags & LCB_CMDN1QL_F_PREPCACHE) {
|
|
634
|
-
lasterr = LCB_OPTIONS_CONFLICT;
|
|
635
|
-
return;
|
|
636
|
-
}
|
|
625
|
+
is_cbas = true;
|
|
626
|
+
}
|
|
627
|
+
if (is_cbas && (flags & LCB_CMDN1QL_F_PREPCACHE)) {
|
|
628
|
+
lasterr = LCB_OPTIONS_CONFLICT;
|
|
629
|
+
return;
|
|
637
630
|
}
|
|
638
631
|
|
|
639
632
|
const Json::Value& j_statement = json_const()["statement"];
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2015-2017 Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
1
18
|
#include <libcouchbase/couchbase.h>
|
|
2
19
|
#include <libcouchbase/n1ql.h>
|
|
3
20
|
#include <libcouchbase/vbucket.h>
|
|
@@ -84,6 +101,34 @@ lcb_n1p_posparam(lcb_N1QLPARAMS *params, const char *value, size_t nvalue)
|
|
|
84
101
|
return LCB_SUCCESS;
|
|
85
102
|
}
|
|
86
103
|
|
|
104
|
+
lcb_error_t
|
|
105
|
+
lcb_n1p_readonly(lcb_N1QLPARAMS *params, int readonly)
|
|
106
|
+
{
|
|
107
|
+
params->root["readonly"] = readonly ? true : false;
|
|
108
|
+
return LCB_SUCCESS;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
lcb_error_t
|
|
112
|
+
lcb_n1p_scancap(lcb_N1QLPARAMS *params, int scancap)
|
|
113
|
+
{
|
|
114
|
+
params->root["scan_cap"] = Json::valueToString(scancap);
|
|
115
|
+
return LCB_SUCCESS;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
lcb_error_t
|
|
119
|
+
lcb_n1p_pipelinecap(lcb_N1QLPARAMS *params, int pipelinecap)
|
|
120
|
+
{
|
|
121
|
+
params->root["pipeline_cap"] = Json::valueToString(pipelinecap);
|
|
122
|
+
return LCB_SUCCESS;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
lcb_error_t
|
|
126
|
+
lcb_n1p_pipelinebatch(lcb_N1QLPARAMS *params, int pipelinebatch)
|
|
127
|
+
{
|
|
128
|
+
params->root["pipeline_batch"] = Json::valueToString(pipelinebatch);
|
|
129
|
+
return LCB_SUCCESS;
|
|
130
|
+
}
|
|
131
|
+
|
|
87
132
|
static void
|
|
88
133
|
encode_mutation_token(Json::Value& sparse, const lcb_MUTATION_TOKEN *sv)
|
|
89
134
|
{
|
|
@@ -92,7 +137,7 @@ encode_mutation_token(Json::Value& sparse, const lcb_MUTATION_TOKEN *sv)
|
|
|
92
137
|
Json::Value& cur_sv = sparse[buf];
|
|
93
138
|
|
|
94
139
|
cur_sv[0] = static_cast<Json::UInt64>(sv->seqno_);
|
|
95
|
-
sprintf(buf, "%llu", sv->uuid_);
|
|
140
|
+
sprintf(buf, "%llu", (unsigned long long)sv->uuid_);
|
|
96
141
|
cur_sv[1] = buf;
|
|
97
142
|
}
|
|
98
143
|
|
|
@@ -103,12 +103,12 @@ lcb_vbguess_remap(lcb_t instance, int vbid, int bad)
|
|
|
103
103
|
|
|
104
104
|
} else {
|
|
105
105
|
lcb_GUESSVB *guesses = instance->vbguess;
|
|
106
|
-
lcb_GUESSVB *guess = guesses + vbid;
|
|
107
|
-
int newix = lcbvb_nmv_remap_ex(LCBT_VBCONFIG(instance), vbid, bad, 1);
|
|
108
106
|
if (!guesses) {
|
|
109
|
-
guesses = instance->vbguess =
|
|
110
|
-
LCBT_VBCONFIG(instance)->nvb, sizeof
|
|
107
|
+
guesses = instance->vbguess =
|
|
108
|
+
reinterpret_cast< lcb_GUESSVB * >(calloc(LCBT_VBCONFIG(instance)->nvb, sizeof(lcb_GUESSVB)));
|
|
111
109
|
}
|
|
110
|
+
lcb_GUESSVB *guess = guesses + vbid;
|
|
111
|
+
int newix = lcbvb_nmv_remap_ex(LCBT_VBCONFIG(instance), vbid, bad, 1);
|
|
112
112
|
if (newix > -1 && newix != bad) {
|
|
113
113
|
guess->newix = newix;
|
|
114
114
|
guess->oldix = bad;
|
|
@@ -113,6 +113,10 @@ SeqnoDurset::poll_impl()
|
|
|
113
113
|
ent.callback = seqno_callback;
|
|
114
114
|
|
|
115
115
|
size_t nservers = ent.prepare(servers);
|
|
116
|
+
if (nservers == 0) {
|
|
117
|
+
ret_err = LCB_DURABILITY_ETOOMANY;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
116
120
|
for (size_t jj = 0; jj < nservers; jj++) {
|
|
117
121
|
lcb_error_t err;
|
|
118
122
|
cmd.server_index = servers[jj];
|
|
@@ -284,6 +284,9 @@ lcb_error_t
|
|
|
284
284
|
lcb_durability_validate(lcb_t instance,
|
|
285
285
|
lcb_U16 *persist_to, lcb_U16 *replicate_to, int options)
|
|
286
286
|
{
|
|
287
|
+
if (!LCBT_VBCONFIG(instance)) {
|
|
288
|
+
return LCB_CLIENT_ENOCONF;
|
|
289
|
+
}
|
|
287
290
|
int replica_max = std::min(
|
|
288
291
|
LCBT_NREPLICAS(instance),
|
|
289
292
|
LCBT_NDATASERVERS(instance)-1);
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2017 Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#include "internal.h"
|
|
19
|
+
#include <libcouchbase/n1ql.h>
|
|
20
|
+
#include "http/http.h"
|
|
21
|
+
#include "auth-priv.h"
|
|
22
|
+
|
|
23
|
+
static void refcnt_dtor_ping(mc_PACKET *);
|
|
24
|
+
static void handle_ping(mc_PIPELINE *, mc_PACKET *, lcb_error_t, const void *);
|
|
25
|
+
|
|
26
|
+
static mc_REQDATAPROCS ping_procs = {
|
|
27
|
+
handle_ping,
|
|
28
|
+
refcnt_dtor_ping
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
struct PingCookie : mc_REQDATAEX {
|
|
32
|
+
int remaining;
|
|
33
|
+
int options;
|
|
34
|
+
std::list<lcb_PINGSVC> responses;
|
|
35
|
+
|
|
36
|
+
PingCookie(const void *cookie_, int _options)
|
|
37
|
+
: mc_REQDATAEX(cookie_, ping_procs, gethrtime()),
|
|
38
|
+
remaining(0), options(_options) {
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
~PingCookie() {
|
|
42
|
+
for (std::list<lcb_PINGSVC>::iterator it = responses.begin(); it != responses.end(); it++) {
|
|
43
|
+
if (it->server) {
|
|
44
|
+
free(it->server);
|
|
45
|
+
it->server = NULL;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
bool needMetrics() {
|
|
51
|
+
return (options & LCB_PINGOPT_F_NOMETRICS) == 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
bool needJSON() {
|
|
55
|
+
return options & LCB_PINGOPT_F_JSON;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
bool needDetails() {
|
|
59
|
+
return options & LCB_PINGOPT_F_JSONDETAILS;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
bool needPretty() {
|
|
63
|
+
return options & LCB_PINGOPT_F_JSONPRETTY;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
static void
|
|
68
|
+
refcnt_dtor_ping(mc_PACKET *pkt)
|
|
69
|
+
{
|
|
70
|
+
PingCookie *ck = static_cast<PingCookie *>(pkt->u_rdata.exdata);
|
|
71
|
+
if (!--ck->remaining) {
|
|
72
|
+
delete ck;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static std::string latency_to_string(lcb_U64 latency)
|
|
77
|
+
{
|
|
78
|
+
std::stringstream ss;
|
|
79
|
+
ss.precision(3);
|
|
80
|
+
ss.setf(std::ios::fixed);
|
|
81
|
+
if (latency < 1000) {
|
|
82
|
+
ss << latency << "ns";
|
|
83
|
+
} else if (latency < LCB_US2NS(1000)) {
|
|
84
|
+
ss << (latency / (double)LCB_US2NS(1)) << "us";
|
|
85
|
+
} else if (latency < LCB_MS2NS(1000)) {
|
|
86
|
+
ss << (latency / (double)LCB_MS2NS(1)) << "ms";
|
|
87
|
+
} else {
|
|
88
|
+
ss << (latency / (double)LCB_S2NS(1)) << "s";
|
|
89
|
+
}
|
|
90
|
+
return ss.str();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static const char* svc_to_string(lcb_PINGSVCTYPE type)
|
|
94
|
+
{
|
|
95
|
+
switch (type) {
|
|
96
|
+
case LCB_PINGSVC_KV:
|
|
97
|
+
return "kv";
|
|
98
|
+
case LCB_PINGSVC_VIEWS:
|
|
99
|
+
return "views";
|
|
100
|
+
case LCB_PINGSVC_N1QL:
|
|
101
|
+
return "n1ql";
|
|
102
|
+
case LCB_PINGSVC_FTS:
|
|
103
|
+
return "fts";
|
|
104
|
+
default:
|
|
105
|
+
return "unknown";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static void
|
|
110
|
+
build_ping_json(lcb_RESPPING &ping, Json::Value &root, bool details)
|
|
111
|
+
{
|
|
112
|
+
Json::Value services;
|
|
113
|
+
for (size_t ii = 0; ii < ping.nservices; ii++) {
|
|
114
|
+
lcb_PINGSVC &svc = ping.services[ii];
|
|
115
|
+
Json::Value service;
|
|
116
|
+
service["server"] = svc.server;
|
|
117
|
+
service["latency"] = latency_to_string(svc.latency);
|
|
118
|
+
service["status"] = svc.status;
|
|
119
|
+
if (details) {
|
|
120
|
+
service["details"] = lcb_strerror(NULL, svc.status);
|
|
121
|
+
}
|
|
122
|
+
services[svc_to_string(svc.type)].append(service);
|
|
123
|
+
}
|
|
124
|
+
root["services"] = services;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static void
|
|
128
|
+
invoke_ping_callback(lcb_t instance, PingCookie *ck)
|
|
129
|
+
{
|
|
130
|
+
lcb_RESPPING ping;
|
|
131
|
+
std::string json;
|
|
132
|
+
size_t idx = 0;
|
|
133
|
+
memset(&ping, 0, sizeof(ping));
|
|
134
|
+
if (ck->needMetrics()) {
|
|
135
|
+
ping.nservices = ck->responses.size();
|
|
136
|
+
ping.services = new lcb_PINGSVC[ping.nservices];
|
|
137
|
+
for(std::list<lcb_PINGSVC>::const_iterator it = ck->responses.begin(); it != ck->responses.end(); ++it){
|
|
138
|
+
ping.services[idx++] = *it;
|
|
139
|
+
}
|
|
140
|
+
if (ck->needJSON()) {
|
|
141
|
+
Json::Value root;
|
|
142
|
+
build_ping_json(ping, root, ck->needDetails());
|
|
143
|
+
Json::Writer *w;
|
|
144
|
+
if (ck->needPretty()) {
|
|
145
|
+
w = new Json::StyledWriter();
|
|
146
|
+
} else {
|
|
147
|
+
w = new Json::FastWriter();
|
|
148
|
+
}
|
|
149
|
+
json = w->write(root);
|
|
150
|
+
delete w;
|
|
151
|
+
ping.njson = json.size();
|
|
152
|
+
ping.json = json.c_str();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
lcb_RESPCALLBACK callback;
|
|
156
|
+
callback = lcb_find_callback(instance, LCB_CALLBACK_PING);
|
|
157
|
+
ping.cookie = const_cast<void*>(ck->cookie);
|
|
158
|
+
callback(instance, LCB_CALLBACK_PING, (lcb_RESPBASE *)&ping);
|
|
159
|
+
if (ping.services != NULL) {
|
|
160
|
+
delete []ping.services;
|
|
161
|
+
}
|
|
162
|
+
delete ck;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
static void
|
|
166
|
+
handle_ping(mc_PIPELINE *pipeline, mc_PACKET *req, lcb_error_t err, const void *)
|
|
167
|
+
{
|
|
168
|
+
lcb::Server *server = static_cast<lcb::Server*>(pipeline);
|
|
169
|
+
PingCookie *ck = (PingCookie *)req->u_rdata.exdata;
|
|
170
|
+
|
|
171
|
+
if (ck->needMetrics()) {
|
|
172
|
+
std::string hh(server->get_host().host);
|
|
173
|
+
hh.append(":");
|
|
174
|
+
hh.append(server->get_host().port);
|
|
175
|
+
|
|
176
|
+
lcb_PINGSVC svc;
|
|
177
|
+
svc.type = LCB_PINGSVC_KV;
|
|
178
|
+
svc.server = strdup(hh.c_str());
|
|
179
|
+
svc.latency = gethrtime() - MCREQ_PKT_RDATA(req)->start;
|
|
180
|
+
svc.status = err;
|
|
181
|
+
ck->responses.push_back(svc);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (--ck->remaining) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
invoke_ping_callback(server->get_instance(), ck);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
static void handle_http(lcb_t instance, lcb_PINGSVCTYPE type, const lcb_RESPHTTP *resp)
|
|
191
|
+
{
|
|
192
|
+
if ((resp->rflags & LCB_RESP_F_FINAL) == 0) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
PingCookie *ck = (PingCookie *)resp->cookie;
|
|
196
|
+
lcb::http::Request *htreq = reinterpret_cast<lcb::http::Request*>(resp->_htreq);
|
|
197
|
+
|
|
198
|
+
if (ck->needMetrics()) {
|
|
199
|
+
lcb_PINGSVC svc;
|
|
200
|
+
svc.type = type;
|
|
201
|
+
svc.server = strdup((htreq->host + ":" + htreq->port).c_str());
|
|
202
|
+
svc.latency = gethrtime() - htreq->start;
|
|
203
|
+
svc.status = resp->rc;
|
|
204
|
+
ck->responses.push_back(svc);
|
|
205
|
+
}
|
|
206
|
+
if (--ck->remaining) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
invoke_ping_callback(instance, ck);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static void handle_n1ql(lcb_t instance, int, const lcb_RESPBASE *resp)
|
|
213
|
+
{
|
|
214
|
+
handle_http(instance, LCB_PINGSVC_N1QL, (const lcb_RESPHTTP *)resp);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
static void handle_views(lcb_t instance, int, const lcb_RESPBASE *resp)
|
|
218
|
+
{
|
|
219
|
+
handle_http(instance, LCB_PINGSVC_VIEWS, (const lcb_RESPHTTP *)resp);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
static void handle_fts(lcb_t instance, int, const lcb_RESPBASE *resp)
|
|
223
|
+
{
|
|
224
|
+
handle_http(instance, LCB_PINGSVC_FTS, (const lcb_RESPHTTP *)resp);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
LIBCOUCHBASE_API
|
|
228
|
+
lcb_error_t
|
|
229
|
+
lcb_ping3(lcb_t instance, const void *cookie, const lcb_CMDPING *cmd)
|
|
230
|
+
{
|
|
231
|
+
mc_CMDQUEUE *cq = &instance->cmdq;
|
|
232
|
+
unsigned ii;
|
|
233
|
+
|
|
234
|
+
if (!cq->config) {
|
|
235
|
+
return LCB_CLIENT_ETMPFAIL;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
PingCookie *ckwrap = new PingCookie(cookie, cmd->options);
|
|
239
|
+
|
|
240
|
+
if (cmd->services & LCB_PINGSVC_F_KV) {
|
|
241
|
+
for (ii = 0; ii < cq->npipelines; ii++) {
|
|
242
|
+
mc_PIPELINE *pl = cq->pipelines[ii];
|
|
243
|
+
mc_PACKET *pkt = mcreq_allocate_packet(pl);
|
|
244
|
+
protocol_binary_request_header hdr;
|
|
245
|
+
memset(&hdr, 0, sizeof(hdr));
|
|
246
|
+
|
|
247
|
+
if (!pkt) {
|
|
248
|
+
return LCB_CLIENT_ENOMEM;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
pkt->u_rdata.exdata = ckwrap;
|
|
252
|
+
pkt->flags |= MCREQ_F_REQEXT;
|
|
253
|
+
|
|
254
|
+
hdr.request.magic = PROTOCOL_BINARY_REQ;
|
|
255
|
+
hdr.request.opaque = pkt->opaque;
|
|
256
|
+
hdr.request.opcode = PROTOCOL_BINARY_CMD_NOOP;
|
|
257
|
+
|
|
258
|
+
mcreq_reserve_header(pl, pkt, MCREQ_PKT_BASESIZE);
|
|
259
|
+
memcpy(SPAN_BUFFER(&pkt->kh_span), hdr.bytes, sizeof(hdr.bytes));
|
|
260
|
+
mcreq_sched_add(pl, pkt);
|
|
261
|
+
ckwrap->remaining++;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
lcbvb_CONFIG *cfg = LCBT_VBCONFIG(instance);
|
|
266
|
+
const lcbvb_SVCMODE mode = LCBT_SETTING(instance, sslopts) ?
|
|
267
|
+
LCBVB_SVCMODE_SSL : LCBVB_SVCMODE_PLAIN;
|
|
268
|
+
for (int idx = 0; idx < (int)LCBVB_NSERVERS(cfg); idx++) {
|
|
269
|
+
#define PING_HTTP(SVC, QUERY, TMO, CB) \
|
|
270
|
+
do { \
|
|
271
|
+
lcb_error_t rc; \
|
|
272
|
+
struct lcb_http_request_st *htreq; \
|
|
273
|
+
lcb_CMDHTTP htcmd = {0}; \
|
|
274
|
+
htcmd.host = lcbvb_get_resturl(cfg, idx, SVC, mode); \
|
|
275
|
+
if (htcmd.host == NULL) { \
|
|
276
|
+
continue; \
|
|
277
|
+
} \
|
|
278
|
+
htcmd.body = QUERY; \
|
|
279
|
+
htcmd.nbody = strlen(htcmd.body); \
|
|
280
|
+
htcmd.content_type = "application/json"; \
|
|
281
|
+
htcmd.method = LCB_HTTP_METHOD_POST; \
|
|
282
|
+
htcmd.type = LCB_HTTP_TYPE_RAW; \
|
|
283
|
+
htcmd.reqhandle = &htreq; \
|
|
284
|
+
const lcb::Authenticator& auth = *instance->settings->auth; \
|
|
285
|
+
htcmd.username = auth.username_for(LCBT_SETTING(instance, bucket)).c_str(); \
|
|
286
|
+
htcmd.password = auth.password_for(LCBT_SETTING(instance, bucket)).c_str(); \
|
|
287
|
+
htcmd.cmdflags = LCB_CMDHTTP_F_CASTMO; \
|
|
288
|
+
htcmd.cas = LCBT_SETTING(instance, TMO); \
|
|
289
|
+
rc = lcb_http3(instance, ckwrap, &htcmd); \
|
|
290
|
+
if (rc == LCB_SUCCESS) { \
|
|
291
|
+
htreq->set_callback(CB); \
|
|
292
|
+
} \
|
|
293
|
+
ckwrap->remaining++; \
|
|
294
|
+
} while (0);
|
|
295
|
+
|
|
296
|
+
if (cmd->services & LCB_PINGSVC_F_N1QL) {
|
|
297
|
+
PING_HTTP(LCBVB_SVCTYPE_N1QL, "{\"statement\":\"select 1\"}",
|
|
298
|
+
n1ql_timeout, handle_n1ql);
|
|
299
|
+
}
|
|
300
|
+
if (cmd->services & LCB_PINGSVC_F_VIEWS) {
|
|
301
|
+
PING_HTTP(LCBVB_SVCTYPE_VIEWS, "", views_timeout, handle_views);
|
|
302
|
+
}
|
|
303
|
+
if (cmd->services & LCB_PINGSVC_F_FTS) {
|
|
304
|
+
PING_HTTP(LCBVB_SVCTYPE_FTS, "", n1ql_timeout, handle_fts);
|
|
305
|
+
}
|
|
306
|
+
#undef PING_HTTP
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (ckwrap->remaining == 0) {
|
|
310
|
+
delete ckwrap;
|
|
311
|
+
return LCB_NO_MATCHING_SERVER;
|
|
312
|
+
}
|
|
313
|
+
MAYBE_SCHEDLEAVE(instance);
|
|
314
|
+
return LCB_SUCCESS;
|
|
315
|
+
}
|