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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +11 -8
  3. data/ext/libcouchbase/CMakeLists.txt +1 -1
  4. data/ext/libcouchbase/README.markdown +38 -6
  5. data/ext/libcouchbase/RELEASE_NOTES.markdown +151 -0
  6. data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -2
  7. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
  8. data/ext/libcouchbase/cmake/source_files.cmake +1 -0
  9. data/ext/libcouchbase/contrib/cJSON/cJSON.c +686 -288
  10. data/ext/libcouchbase/contrib/cJSON/cJSON.h +0 -0
  11. data/ext/libcouchbase/contrib/cbsasl/src/hash.c +17 -17
  12. data/ext/libcouchbase/contrib/cliopts/cliopts.c +76 -0
  13. data/ext/libcouchbase/contrib/cliopts/cliopts.h +66 -15
  14. data/ext/libcouchbase/contrib/genhash/genhash.c +1 -2
  15. data/ext/libcouchbase/contrib/lcb-jsoncpp/lcb-jsoncpp.cpp +4 -3
  16. data/ext/libcouchbase/example/instancepool/main.cc +12 -2
  17. data/ext/libcouchbase/example/libeventdirect/main.c +99 -25
  18. data/ext/libcouchbase/example/minimal/minimal.c +7 -5
  19. data/ext/libcouchbase/example/observe/durability.c +102 -0
  20. data/ext/libcouchbase/example/observe/observe.c +19 -6
  21. data/ext/libcouchbase/example/subdoc/subdoc-xattrs.c +1 -2
  22. data/ext/libcouchbase/include/libcouchbase/cntl-private.h +6 -8
  23. data/ext/libcouchbase/include/libcouchbase/cntl.h +84 -64
  24. data/ext/libcouchbase/include/libcouchbase/couchbase.h +295 -78
  25. data/ext/libcouchbase/include/libcouchbase/deprecated.h +2 -2
  26. data/ext/libcouchbase/include/libcouchbase/error.h +1 -1
  27. data/ext/libcouchbase/include/libcouchbase/iops.h +9 -9
  28. data/ext/libcouchbase/include/libcouchbase/ixmgmt.h +2 -2
  29. data/ext/libcouchbase/include/libcouchbase/n1ql.h +69 -7
  30. data/ext/libcouchbase/include/libcouchbase/vbucket.h +17 -0
  31. data/ext/libcouchbase/include/libcouchbase/views.h +3 -3
  32. data/ext/libcouchbase/include/memcached/protocol_binary.h +62 -1
  33. data/ext/libcouchbase/packaging/deb/control +1 -1
  34. data/ext/libcouchbase/packaging/rpm/libcouchbase.spec.in +37 -36
  35. data/ext/libcouchbase/src/bootstrap.cc +22 -8
  36. data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +1 -1
  37. data/ext/libcouchbase/src/bucketconfig/bc_http.cc +0 -1
  38. data/ext/libcouchbase/src/bucketconfig/confmon.cc +13 -8
  39. data/ext/libcouchbase/src/callbacks.c +2 -0
  40. data/ext/libcouchbase/src/cntl.cc +28 -17
  41. data/ext/libcouchbase/src/dns-srv.cc +1 -2
  42. data/ext/libcouchbase/src/dump.cc +4 -0
  43. data/ext/libcouchbase/src/errmap.h +89 -16
  44. data/ext/libcouchbase/src/handler.cc +28 -11
  45. data/ext/libcouchbase/src/http/http-priv.h +4 -1
  46. data/ext/libcouchbase/src/http/http.cc +3 -0
  47. data/ext/libcouchbase/src/instance.cc +1 -1
  48. data/ext/libcouchbase/src/internal.h +1 -0
  49. data/ext/libcouchbase/src/lcbio/connect.cc +2 -3
  50. data/ext/libcouchbase/src/lcbio/manager.cc +2 -2
  51. data/ext/libcouchbase/src/lcbio/ssl.h +10 -0
  52. data/ext/libcouchbase/src/mc/mcreq.c +8 -0
  53. data/ext/libcouchbase/src/mcserver/mcserver.cc +14 -1
  54. data/ext/libcouchbase/src/n1ql/ixmgmt.cc +0 -3
  55. data/ext/libcouchbase/src/n1ql/n1ql.cc +22 -29
  56. data/ext/libcouchbase/src/n1ql/params.cc +46 -1
  57. data/ext/libcouchbase/src/newconfig.cc +4 -4
  58. data/ext/libcouchbase/src/operations/durability-seqno.cc +4 -0
  59. data/ext/libcouchbase/src/operations/durability.cc +3 -0
  60. data/ext/libcouchbase/src/operations/ping.cc +315 -0
  61. data/ext/libcouchbase/src/operations/stats.cc +10 -0
  62. data/ext/libcouchbase/src/operations/subdoc.cc +13 -1
  63. data/ext/libcouchbase/src/retrychk.cc +1 -0
  64. data/ext/libcouchbase/src/settings.c +2 -0
  65. data/ext/libcouchbase/src/settings.h +13 -7
  66. data/ext/libcouchbase/src/ssl/ssl_c.c +28 -2
  67. data/ext/libcouchbase/src/ssl/ssl_common.c +3 -0
  68. data/ext/libcouchbase/src/ssl/ssl_e.c +15 -1
  69. data/ext/libcouchbase/src/ssl/ssl_iot_common.h +3 -1
  70. data/ext/libcouchbase/src/timings.c +0 -1
  71. data/ext/libcouchbase/src/vbucket/vbucket.c +49 -1
  72. data/ext/libcouchbase/tests/iotests/mock-environment.cc +58 -40
  73. data/ext/libcouchbase/tests/iotests/mock-environment.h +23 -4
  74. data/ext/libcouchbase/tests/iotests/mock-unit-test.h +8 -8
  75. data/ext/libcouchbase/tests/iotests/t_behavior.cc +5 -5
  76. data/ext/libcouchbase/tests/iotests/t_durability.cc +50 -0
  77. data/ext/libcouchbase/tests/iotests/t_eerrs.cc +4 -2
  78. data/ext/libcouchbase/tests/iotests/t_errmap.cc +6 -3
  79. data/ext/libcouchbase/tests/iotests/t_lock.cc +5 -6
  80. data/ext/libcouchbase/tests/iotests/t_misc.cc +44 -0
  81. data/ext/libcouchbase/tests/iotests/t_serverops.cc +1 -0
  82. data/ext/libcouchbase/tests/iotests/t_subdoc.cc +28 -0
  83. data/ext/libcouchbase/tests/iotests/t_views.cc +22 -10
  84. data/ext/libcouchbase/tools/CMakeLists.txt +21 -1
  85. data/ext/libcouchbase/tools/cbc-handlers.h +23 -3
  86. data/ext/libcouchbase/tools/cbc-n1qlback.cc +1 -1
  87. data/ext/libcouchbase/tools/cbc-pillowfight.cc +126 -26
  88. data/ext/libcouchbase/tools/cbc-proxy.cc +403 -0
  89. data/ext/libcouchbase/tools/cbc-subdoc.cc +826 -0
  90. data/ext/libcouchbase/tools/cbc.cc +149 -37
  91. data/ext/libcouchbase/tools/common/options.h +5 -2
  92. data/ext/libcouchbase/tools/linenoise/linenoise.c +15 -15
  93. data/lib/libcouchbase.rb +4 -0
  94. data/lib/libcouchbase/bucket.rb +51 -0
  95. data/lib/libcouchbase/connection.rb +100 -13
  96. data/lib/libcouchbase/ext/libcouchbase.rb +40 -0
  97. data/lib/libcouchbase/ext/libcouchbase/cmdsubdoc.rb +13 -1
  98. data/lib/libcouchbase/ext/libcouchbase/enums.rb +2 -1
  99. data/lib/libcouchbase/ext/libcouchbase/sdspec.rb +5 -0
  100. data/lib/libcouchbase/subdoc_request.rb +129 -0
  101. data/lib/libcouchbase/version.rb +1 -1
  102. data/spec/bucket_spec.rb +15 -1
  103. data/spec/connection_spec.rb +1 -1
  104. data/spec/subdoc_spec.rb +192 -0
  105. metadata +13 -4
  106. data/ext/libcouchbase/.travis.yml +0 -19
@@ -184,6 +184,7 @@ handle_bcast(mc_PIPELINE *pipeline, mc_PACKET *req, lcb_error_t err,
184
184
  lcb_RESPVERBOSITY *verbosity;
185
185
  lcb_RESPMCVERSION *version;
186
186
  lcb_RESPFLUSH *flush;
187
+ lcb_RESPNOOP *noop;
187
188
  } u_resp;
188
189
 
189
190
  union {
@@ -191,6 +192,7 @@ handle_bcast(mc_PIPELINE *pipeline, mc_PACKET *req, lcb_error_t err,
191
192
  lcb_RESPVERBOSITY verbosity;
192
193
  lcb_RESPMCVERSION version;
193
194
  lcb_RESPFLUSH flush;
195
+ lcb_RESPNOOP noop;
194
196
  } u_empty;
195
197
 
196
198
  memset(&u_empty, 0, sizeof(u_empty));
@@ -258,6 +260,8 @@ pkt_bcast_simple(lcb_t instance, const void *cookie, lcb_CALLBACKTYPE type)
258
260
  hdr.request.opcode = PROTOCOL_BINARY_CMD_FLUSH;
259
261
  } else if (type == LCB_CALLBACK_VERSIONS) {
260
262
  hdr.request.opcode = PROTOCOL_BINARY_CMD_VERSION;
263
+ } else if (type == LCB_CALLBACK_NOOP) {
264
+ hdr.request.opcode = PROTOCOL_BINARY_CMD_NOOP;
261
265
  } else {
262
266
  fprintf(stderr, "pkt_bcast_simple passed unknown type %u\n", type);
263
267
  assert(0);
@@ -284,6 +288,12 @@ lcb_server_versions3(lcb_t instance, const void *cookie, const lcb_CMDBASE *)
284
288
  return pkt_bcast_simple(instance, cookie, LCB_CALLBACK_VERSIONS);
285
289
  }
286
290
 
291
+ LIBCOUCHBASE_API
292
+ lcb_error_t
293
+ lcb_noop3(lcb_t instance, const void *cookie, const lcb_CMDNOOP *)
294
+ {
295
+ return pkt_bcast_simple(instance, cookie, LCB_CALLBACK_NOOP);
296
+ }
287
297
 
288
298
  LIBCOUCHBASE_API
289
299
  lcb_error_t
@@ -234,8 +234,20 @@ make_doc_flags(const uint32_t user) {
234
234
  }
235
235
 
236
236
  struct MultiBuilder {
237
+ static unsigned infer_mode(const lcb_CMDSUBDOC *cmd) {
238
+ if (cmd->nspecs == 0) {
239
+ return 0;
240
+ }
241
+ const SubdocCmdTraits::Traits& trait = SubdocCmdTraits::find(cmd->specs[0].sdcmd);
242
+ if (!trait.valid()) {
243
+ return 0;
244
+ }
245
+ return trait.mode();
246
+ }
247
+
237
248
  MultiBuilder(const lcb_CMDSUBDOC *cmd_)
238
- : cmd(cmd_), payload_size(0), mode(0) {
249
+ : cmd(cmd_), payload_size(0) {
250
+ mode = infer_mode(cmd_);
239
251
  size_t ebufsz = is_lookup() ? cmd->nspecs * 4 : cmd->nspecs * 8;
240
252
  extra_body = new char[ebufsz];
241
253
  bodysz = 0;
@@ -35,6 +35,7 @@ lcb_should_retry(const lcb_settings *settings, const mc_PACKET *pkt, lcb_error_t
35
35
  case PROTOCOL_BINARY_CMD_STAT:
36
36
  case PROTOCOL_BINARY_CMD_VERBOSITY:
37
37
  case PROTOCOL_BINARY_CMD_VERSION:
38
+ case PROTOCOL_BINARY_CMD_NOOP:
38
39
  return 0;
39
40
  }
40
41
 
@@ -60,6 +60,8 @@ void lcb_default_settings(lcb_settings *settings)
60
60
  settings->select_bucket = LCB_DEFAULT_SELECT_BUCKET;
61
61
  settings->tcp_keepalive = LCB_DEFAULT_TCP_KEEPALIVE;
62
62
  settings->send_hello = 1;
63
+ settings->config_poll_interval = LCB_DEFAULT_CONFIG_POLL_INTERVAL;
64
+ settings->use_errmap = 1;
63
65
  }
64
66
 
65
67
  LCB_INTERNAL_API
@@ -23,21 +23,23 @@
23
23
  */
24
24
 
25
25
  /** Convert seconds to millis */
26
- #define LCB_S2MS(s) ((lcb_uint32_t)s) * 1000
26
+ #define LCB_S2MS(s) (((lcb_uint32_t)s) * 1000)
27
27
 
28
28
  /** Convert seconds to microseconds */
29
- #define LCB_S2US(s) ((lcb_uint32_t)s) * 1000000
29
+ #define LCB_S2US(s) (((lcb_uint32_t)s) * 1000000)
30
30
 
31
31
  /** Convert seconds to nanoseconds */
32
- #define LCB_S2NS(s) ((hrtime_t)s) * 1000000000
32
+ #define LCB_S2NS(s) (((hrtime_t)s) * 1000000000)
33
33
 
34
34
  /** Convert nanoseconds to microseconds */
35
35
  #define LCB_NS2US(s) (lcb_uint32_t) ((s) / 1000)
36
36
 
37
- #define LCB_MS2US(s) (s) * 1000
37
+ #define LCB_MS2US(s) ((s) * 1000)
38
38
 
39
39
  /** Convert microseconds to nanoseconds */
40
- #define LCB_US2NS(s) ((hrtime_t)s) * 1000
40
+ #define LCB_US2NS(s) (((hrtime_t)s) * 1000)
41
+ /** Convert milliseconds to nanoseconds */
42
+ #define LCB_MS2NS(s) (((hrtime_t)s) * 1000000)
41
43
 
42
44
 
43
45
  #define LCB_DEFAULT_TIMEOUT LCB_MS2US(2500)
@@ -56,8 +58,8 @@
56
58
  #define LCB_DEFAULT_CONFIG_MAXIMUM_REDIRECTS 3
57
59
  #define LCB_DEFAULT_CONFIG_ERRORS_THRESHOLD 100
58
60
 
59
- /* 10 seconds */
60
- #define LCB_DEFAULT_CONFIG_ERRORS_DELAY LCB_MS2US(10000)
61
+ /* 10 milliseconds */
62
+ #define LCB_DEFAULT_CONFIG_ERRORS_DELAY LCB_MS2US(10)
61
63
 
62
64
  /* 1 second */
63
65
  #define LCB_DEFAULT_CLCONFIG_GRACE_CYCLE LCB_MS2US(1000)
@@ -86,6 +88,10 @@
86
88
  #define LCB_DEFAULT_TCP_NODELAY 1
87
89
  #define LCB_DEFAULT_SELECT_BUCKET 1
88
90
  #define LCB_DEFAULT_TCP_KEEPALIVE 1
91
+ /* 2.5 s */
92
+ #define LCB_DEFAULT_CONFIG_POLL_INTERVAL LCB_MS2US(2500)
93
+ /* 50 ms */
94
+ #define LCB_CONFIG_POLL_INTERVAL_FLOOR LCB_MS2US(50)
89
95
 
90
96
  #include "config.h"
91
97
  #include <libcouchbase/couchbase.h>
@@ -189,16 +189,26 @@ appdata_read(lcbio_CSSL *cs)
189
189
  static void
190
190
  read_callback(lcb_sockdata_t *sd, lcb_ssize_t nr, void *arg)
191
191
  {
192
+ #if LCB_CAN_OPTIMIZE_SSL_BIO
192
193
  lcbio_CSSL *cs = arg;
194
+ #else
195
+ my_WBUF *rb = arg;
196
+ lcbio_CSSL *cs = rb->parent;
197
+ #endif
198
+
193
199
  cs->rdactive = 0;
194
200
  cs->entered++;
195
201
 
196
202
  if (nr > 0) {
203
+ #if LCB_CAN_OPTIMIZE_SSL_BIO
197
204
  BUF_MEM *mb;
198
205
 
199
206
  BIO_clear_retry_flags(cs->rbio);
200
207
  BIO_get_mem_ptr(cs->rbio, &mb);
201
208
  mb->length += nr;
209
+ #else
210
+ BIO_write(cs->rbio, rb->buf, nr);
211
+ #endif
202
212
 
203
213
  } else if (nr == 0) {
204
214
  cs->closed = 1;
@@ -208,6 +218,9 @@ read_callback(lcb_sockdata_t *sd, lcb_ssize_t nr, void *arg)
208
218
  cs->error = 1;
209
219
  IOTSSL_ERRNO(cs) = IOT_ERRNO(cs->orig);
210
220
  }
221
+ #if !LCB_CAN_OPTIMIZE_SSL_BIO
222
+ free(rb);
223
+ #endif
211
224
 
212
225
  appdata_encode(cs);
213
226
  appdata_read(cs);
@@ -271,17 +284,30 @@ schedule_wants(lcbio_CSSL *cs)
271
284
 
272
285
  } else if (SSL_want_read(cs->ssl) || (cs->urd_cb && has_appdata == 0)) {
273
286
  /* request more data from the socket */
274
- BUF_MEM *mb;
275
287
  lcb_IOV iov;
288
+ #if LCB_CAN_OPTIMIZE_SSL_BIO
289
+ BUF_MEM *mb;
290
+ #else
291
+ #define BUFSZ 4096
292
+ my_WBUF *rb = malloc(sizeof(*rb) + BUFSZ);
293
+ rb->parent = cs;
294
+ #endif
276
295
 
277
296
  cs->rdactive = 1;
297
+ lcbio_table_ref(&cs->base_);
298
+ #if LCB_CAN_OPTIMIZE_SSL_BIO
278
299
  BIO_get_mem_ptr(cs->rbio, &mb);
279
300
  iotssl_bm_reserve(mb);
280
301
  iov.iov_base = mb->data + mb->length;
281
302
  iov.iov_len = mb->max - mb->length;
282
- lcbio_table_ref(&cs->base_);
283
303
  IOT_V1(cs->orig).read2(
284
304
  IOT_ARG(cs->orig), cs->sd, &iov, 1, cs, read_callback);
305
+ #else
306
+ iov.iov_base = rb->buf;
307
+ iov.iov_len = BUFSZ;
308
+ IOT_V1(cs->orig).read2(
309
+ IOT_ARG(cs->orig), cs->sd, &iov, 1, rb, read_callback);
310
+ #endif
285
311
  }
286
312
 
287
313
  }
@@ -127,6 +127,7 @@ iotssl_destroy_common(lcbio_XSSL *xs)
127
127
  lcbio_table_unref(xs->orig);
128
128
  }
129
129
 
130
+ #if LCB_CAN_OPTIMIZE_SSL_BIO
130
131
  void
131
132
  iotssl_bm_reserve(BUF_MEM *bm)
132
133
  {
@@ -139,6 +140,7 @@ iotssl_bm_reserve(BUF_MEM *bm)
139
140
  }
140
141
  bm->length = oldlen;
141
142
  }
143
+ #endif
142
144
 
143
145
  void
144
146
  iotssl_log_errors(lcbio_XSSL *xs)
@@ -428,6 +430,7 @@ ossl_init_locks(void)
428
430
  for (ii = 0; ii < nlocks; ii++) {
429
431
  ossl_lock_init(ossl_locks + ii);
430
432
  }
433
+ /* TODO: locking API has been removed in OpenSSL 1.1 */
431
434
  CRYPTO_set_locking_callback(ossl_lockfn);
432
435
  }
433
436
 
@@ -112,24 +112,38 @@ schedule_pending(lcbio_ESSL *es)
112
112
  static int
113
113
  read_ssl_data(lcbio_ESSL *es)
114
114
  {
115
- BUF_MEM *rmb;
116
115
  int nr;
117
116
  lcbio_pTABLE iot = es->orig;
118
117
 
118
+ #if LCB_CAN_OPTIMIZE_SSL_BIO
119
+ BUF_MEM *rmb;
120
+
119
121
  /* This block is an optimization over BIO_write to avoid copying the memory
120
122
  * to a temporary buffer and _then_ copying it into the BIO */
121
123
 
122
124
  BIO_get_mem_ptr(es->rbio, &rmb);
125
+ #endif
126
+
123
127
  while (1) {
128
+ #if LCB_CAN_OPTIMIZE_SSL_BIO
124
129
  /* I don't know why this is here, but it's found inside BIO_write */
125
130
  BIO_clear_retry_flags(es->rbio);
126
131
  iotssl_bm_reserve(rmb);
127
132
  nr = IOT_V0IO(iot).recv(IOT_ARG(iot), es->fd,
128
133
  rmb->data + rmb->length, rmb->max - rmb->length, 0);
134
+ #else
135
+ #define BUFSZ 4096
136
+ char buf[BUFSZ];
137
+ nr = IOT_V0IO(iot).recv(IOT_ARG(iot), es->fd, buf, BUFSZ, 0);
138
+ #endif
129
139
 
130
140
  if (nr > 0) {
141
+ #if LCB_CAN_OPTIMIZE_SSL_BIO
131
142
  /* Extend the BIO used length */
132
143
  rmb->length += nr;
144
+ #else
145
+ BIO_write(es->rbio, buf, nr);
146
+ #endif
133
147
  } else if (nr == 0) {
134
148
  es->closed = 1;
135
149
  return -1;
@@ -31,7 +31,7 @@
31
31
  lcbio_pTABLE orig; /**< Table pointer we are wrapping */ \
32
32
  SSL *ssl; /**< SSL object */ \
33
33
  BIO *wbio; /**< BIO used for writing data to network */ \
34
- BIO *rbio; /**<< BIO used for reading data from network */\
34
+ BIO *rbio; /**< BIO used for reading data from network */\
35
35
  lcb_io_opt_t iops_dummy_; /**< Dummy IOPS structure which is exposed to LCB */ \
36
36
  int error; /**< Internal error flag set once a fatal error is detect */\
37
37
  lcb_error_t errcode; /**< The error, converted into libcouchbase */
@@ -113,6 +113,7 @@ iotssl_init_common(lcbio_XSSL *xs, lcbio_TABLE *orig, SSL_CTX *ctx);
113
113
  void
114
114
  iotssl_destroy_common(lcbio_XSSL *xs);
115
115
 
116
+ #if LCB_CAN_OPTIMIZE_SSL_BIO
116
117
  /**
117
118
  * Reserve a specified amount of bytes for reading into a `BUF_MEM*` structure.
118
119
  * Currently the amount reserved is hard coded.
@@ -132,6 +133,7 @@ iotssl_destroy_common(lcbio_XSSL *xs);
132
133
  */
133
134
  void
134
135
  iotssl_bm_reserve(BUF_MEM *bm);
136
+ #endif
135
137
 
136
138
  /**
137
139
  * Prepare the SSL structure so that a subsequent call to SSL_pending will
@@ -111,7 +111,6 @@ lcb_histogram_read(const lcb_HISTOGRAM *hg,
111
111
  start = end + 1;
112
112
  }
113
113
 
114
- start = 1000;
115
114
  for (ii = 1; ii < 9; ++ii) {
116
115
  start = ii * 1000;
117
116
  end = ((ii + 1) * 1000) - 1;
@@ -329,6 +329,7 @@ extract_services(lcbvb_CONFIG *cfg, cJSON *jsvc, lcbvb_SERVICES *svc, int is_ssl
329
329
  EXTRACT_SERVICE("fts", fts);
330
330
  EXTRACT_SERVICE("indexAdmin", ixadmin);
331
331
  EXTRACT_SERVICE("indexScan", ixquery);
332
+ EXTRACT_SERVICE("cbas", cbas);
332
333
 
333
334
  #undef EXTRACT_SERVICE
334
335
 
@@ -360,6 +361,9 @@ build_server_strings(lcbvb_CONFIG *cfg, lcbvb_SERVER *server)
360
361
  if (server->ftspath == NULL && server->svc.fts) {
361
362
  server->ftspath = strdup("/");
362
363
  }
364
+ if (server->cbaspath == NULL && server->svc.cbas) {
365
+ server->cbaspath = strdup("/query/service");
366
+ }
363
367
  return 1;
364
368
  }
365
369
 
@@ -538,6 +542,36 @@ lcbvb_load_json(lcbvb_CONFIG *cfg, const char *data)
538
542
  cfg->revid = -1;
539
543
  }
540
544
 
545
+ cfg->caps = 0;
546
+ {
547
+ cJSON *jcaps = NULL;
548
+ if (get_jarray(cj, "bucketCapabilities", &jcaps)) {
549
+ unsigned ncaps = cJSON_GetArraySize(jcaps);
550
+ for (ii = 0; ii < ncaps; ii++) {
551
+ cJSON *jcap = cJSON_GetArrayItem(jcaps, ii);
552
+ if (jcap || jcap->type == cJSON_String) {
553
+ if (strcmp(jcap->valuestring, "xattr") == 0) {
554
+ cfg->caps |= LCBVB_CAP_XATTR;
555
+ } else if (strcmp(jcap->valuestring, "dcp") == 0) {
556
+ cfg->caps |= LCBVB_CAP_DCP;
557
+ } else if (strcmp(jcap->valuestring, "cbhello") == 0) {
558
+ cfg->caps |= LCBVB_CAP_CBHELLO;
559
+ } else if (strcmp(jcap->valuestring, "touch") == 0) {
560
+ cfg->caps |= LCBVB_CAP_TOUCH;
561
+ } else if (strcmp(jcap->valuestring, "couchapi") == 0) {
562
+ cfg->caps |= LCBVB_CAP_COUCHAPI;
563
+ } else if (strcmp(jcap->valuestring, "cccp") == 0) {
564
+ cfg->caps |= LCBVB_CAP_CCCP;
565
+ } else if (strcmp(jcap->valuestring, "xdcrCheckpointing") == 0) {
566
+ cfg->caps |= LCBVB_CAP_XDCR_CHECKPOINTING;
567
+ } else if (strcmp(jcap->valuestring, "nodesExt") == 0) {
568
+ cfg->caps |= LCBVB_CAP_NODES_EXT;
569
+ }
570
+ }
571
+ }
572
+ }
573
+ }
574
+
541
575
  /** Get the number of nodes. This traverses the list. Yuck */
542
576
  cfg->nsrv = cJSON_GetArraySize(jnodes);
543
577
 
@@ -680,6 +714,7 @@ free_service_strs(lcbvb_SERVICES *svc)
680
714
  free(svc->views_base_);
681
715
  free(svc->query_base_);
682
716
  free(svc->fts_base_);
717
+ free(svc->cbas_base_);
683
718
  }
684
719
 
685
720
  void
@@ -692,6 +727,7 @@ lcbvb_destroy(lcbvb_CONFIG *conf)
692
727
  free(srv->viewpath);
693
728
  free(srv->querypath);
694
729
  free(srv->ftspath);
730
+ free(srv->cbaspath);
695
731
  free_service_strs(&srv->svc);
696
732
  free_service_strs(&srv->svc_ssl);
697
733
  }
@@ -1115,6 +1151,8 @@ lcbvb_get_port(lcbvb_CONFIG *cfg,
1115
1151
  return svc->n1ql;
1116
1152
  } else if (type == LCBVB_SVCTYPE_FTS) {
1117
1153
  return svc->fts;
1154
+ } else if (type == LCBVB_SVCTYPE_CBAS) {
1155
+ return svc->cbas;
1118
1156
  } else {
1119
1157
  return 0;
1120
1158
  }
@@ -1190,7 +1228,8 @@ lcbvb_get_randhost_ex(const lcbvb_CONFIG *cfg,
1190
1228
  (type == LCBVB_SVCTYPE_MGMT && svcs->mgmt) ||
1191
1229
  (type == LCBVB_SVCTYPE_N1QL && svcs->n1ql) ||
1192
1230
  (type == LCBVB_SVCTYPE_FTS && svcs->fts) ||
1193
- (type == LCBVB_SVCTYPE_VIEWS && svcs->views);
1231
+ (type == LCBVB_SVCTYPE_VIEWS && svcs->views) ||
1232
+ (type == LCBVB_SVCTYPE_CBAS && svcs->cbas);
1194
1233
 
1195
1234
  if (has_svc) {
1196
1235
  cfg->randbuf[oix++] = (int)nn;
@@ -1251,6 +1290,9 @@ lcbvb_get_resturl(lcbvb_CONFIG *cfg, unsigned ix,
1251
1290
  } else if (svc == LCBVB_SVCTYPE_FTS) {
1252
1291
  path = srv->ftspath;
1253
1292
  strp = &svcs->fts_base_;
1293
+ } else if (svc == LCBVB_SVCTYPE_CBAS) {
1294
+ path = srv->cbaspath;
1295
+ strp = &svcs->cbas_base_;
1254
1296
  } else {
1255
1297
  /* Unknown service! */
1256
1298
  return NULL;
@@ -1310,6 +1352,9 @@ copy_service(const char *hostname,
1310
1352
  if (src->fts_base_) {
1311
1353
  dst->fts_base_ = strdup(src->fts_base_);
1312
1354
  }
1355
+ if (src->cbas_base_) {
1356
+ dst->cbas_base_ = strdup(src->cbas_base_);
1357
+ }
1313
1358
  if (dst->data) {
1314
1359
  sprintf(buf, "%s:%d", hostname, dst->data);
1315
1360
  dst->hoststrs[LCBVB_SVCTYPE_DATA] = strdup(buf);
@@ -1401,6 +1446,9 @@ lcbvb_genconfig_ex(lcbvb_CONFIG *vb,
1401
1446
  if (src->ftspath) {
1402
1447
  dst->ftspath = strdup(src->ftspath);
1403
1448
  }
1449
+ if (src->cbaspath) {
1450
+ dst->cbaspath = strdup(src->cbaspath);
1451
+ }
1404
1452
 
1405
1453
  copy_service(src->hostname, &src->svc, &dst->svc);
1406
1454
  copy_service(src->hostname, &src->svc_ssl, &dst->svc_ssl);
@@ -21,6 +21,9 @@
21
21
  #include <mocksupport/server.h>
22
22
  #include "mock-environment.h"
23
23
  #include <sstream>
24
+ #include "internal.h" /* settings from lcb_t for logging */
25
+
26
+ #define LOGARGS(instance, lvl) instance->settings, "tests-ENV", LCB_LOG_##lvl, __FILE__, __LINE__
24
27
 
25
28
  MockEnvironment *MockEnvironment::instance;
26
29
 
@@ -66,9 +69,10 @@ MockEnvironment::MockEnvironment(const char **args, std::string bucketname)
66
69
  SetUp();
67
70
  }
68
71
 
69
- void MockEnvironment::failoverNode(int index, std::string bucket)
72
+ void MockEnvironment::failoverNode(int index, std::string bucket, bool rebalance)
70
73
  {
71
74
  MockBucketCommand bCmd(MockCommand::FAILOVER, index, bucket);
75
+ bCmd.set("rebalance", rebalance);
72
76
  sendCommand(bCmd);
73
77
  getResponse();
74
78
  }
@@ -250,44 +254,61 @@ void MockEnvironment::createConnection(lcb_t &instance)
250
254
 
251
255
  }
252
256
 
253
- #define STAT_EP_VERSION "ep_version"
257
+ #define STAT_VERSION "version"
254
258
 
255
259
  extern "C" {
256
- static void statsCallback(lcb_t, const void *cookie,
257
- lcb_error_t err,
258
- const lcb_server_stat_resp_t *resp)
259
- {
260
- MockEnvironment *me = (MockEnvironment *)cookie;
261
- ASSERT_EQ(LCB_SUCCESS, err);
262
-
263
- if (resp->v.v0.server_endpoint == NULL) {
264
- return;
265
- }
266
-
267
- if (!resp->v.v0.nkey) {
268
- return;
269
- }
260
+ static void statsCallback(lcb_t instance, const void *cookie, lcb_error_t err, const lcb_server_stat_resp_t *resp)
261
+ {
262
+ MockEnvironment *me = (MockEnvironment *)cookie;
263
+ ASSERT_EQ(LCB_SUCCESS, err);
270
264
 
271
- if (resp->v.v0.nkey != sizeof(STAT_EP_VERSION) - 1 ||
272
- memcmp(resp->v.v0.key, STAT_EP_VERSION,
273
- sizeof(STAT_EP_VERSION) - 1) != 0) {
274
- return;
275
- }
276
- int version = ((const char *)resp->v.v0.bytes)[0] - '0';
277
- if (version == 1) {
278
- me->setServerVersion(MockEnvironment::VERSION_10);
279
- } else if (version == 2) {
280
- me->setServerVersion(MockEnvironment::VERSION_20);
265
+ if (resp->v.v0.server_endpoint == NULL) {
266
+ return;
267
+ }
281
268
 
282
- } else {
283
- std::cerr << "Unable to determine version from string '";
284
- std::cerr.write((const char *)resp->v.v0.bytes,
285
- resp->v.v0.nbytes);
286
- std::cerr << "' assuming 1.x" << std::endl;
269
+ if (!resp->v.v0.nkey) {
270
+ return;
271
+ }
287
272
 
288
- me->setServerVersion(MockEnvironment::VERSION_10);
273
+ if (resp->v.v0.nkey != sizeof(STAT_VERSION) - 1 ||
274
+ memcmp(resp->v.v0.key, STAT_VERSION, sizeof(STAT_VERSION) - 1) != 0) {
275
+ return;
276
+ }
277
+ MockEnvironment::ServerVersion version = MockEnvironment::VERSION_UNKNOWN;
278
+ if (resp->v.v0.nbytes > 2) {
279
+ int major = ((const char *)resp->v.v0.bytes)[0] - '0';
280
+ int minor = ((const char *)resp->v.v0.bytes)[2] - '0';
281
+ switch (major) {
282
+ case 4:
283
+ switch (minor) {
284
+ case 0:
285
+ version = MockEnvironment::VERSION_40;
286
+ break;
287
+ case 1:
288
+ version = MockEnvironment::VERSION_41;
289
+ break;
290
+ case 5:
291
+ version = MockEnvironment::VERSION_45;
292
+ break;
293
+ case 6:
294
+ version = MockEnvironment::VERSION_46;
295
+ break;
296
+ }
297
+ break;
298
+ case 5:
299
+ version = MockEnvironment::VERSION_50;
300
+ break;
289
301
  }
290
302
  }
303
+ if (version == MockEnvironment::VERSION_UNKNOWN) {
304
+ lcb_log(LOGARGS(instance, ERROR), "Unable to determine version from string '%.*s', assuming 4.0",
305
+ (int)resp->v.v0.nbytes, (const char *)resp->v.v0.bytes);
306
+ version = MockEnvironment::VERSION_40;
307
+ }
308
+ me->setServerVersion(version);
309
+ lcb_log(LOGARGS(instance, INFO), "Using real cluster version %.*s (id=%d)", (int)resp->v.v0.nbytes,
310
+ (const char *)resp->v.v0.bytes, version);
311
+ }
291
312
  }
292
313
 
293
314
  void MockEnvironment::bootstrapRealCluster()
@@ -318,14 +339,11 @@ void MockEnvironment::bootstrapRealCluster()
318
339
  // no body
319
340
  }
320
341
 
321
- if (serverVersion == VERSION_20) {
322
- // Couchbase 2.0.x
323
- featureRegistry.insert("observe");
324
- featureRegistry.insert("views");
325
- featureRegistry.insert("http");
326
- featureRegistry.insert("replica_read");
327
- featureRegistry.insert("lock");
328
- }
342
+ featureRegistry.insert("observe");
343
+ featureRegistry.insert("views");
344
+ featureRegistry.insert("http");
345
+ featureRegistry.insert("replica_read");
346
+ featureRegistry.insert("lock");
329
347
 
330
348
  numNodes = ii;
331
349
  lcb_destroy(tmphandle);