libcouchbase 0.0.7 → 0.0.8

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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/ext/libcouchbase/.gitignore +2 -0
  3. data/ext/libcouchbase/CMakeLists.txt +5 -7
  4. data/ext/libcouchbase/README.markdown +2 -2
  5. data/ext/libcouchbase/RELEASE_NOTES.markdown +49 -0
  6. data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +11 -0
  7. data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -0
  8. data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +2 -1
  9. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
  10. data/ext/libcouchbase/cmake/config-cmake.h.in +2 -0
  11. data/ext/libcouchbase/cmake/defs.mk.in +0 -2
  12. data/ext/libcouchbase/cmake/source_files.cmake +34 -14
  13. data/ext/libcouchbase/configure.pl +1 -1
  14. data/ext/libcouchbase/contrib/genhash/genhash.h +6 -0
  15. data/ext/libcouchbase/include/libcouchbase/auth.h +10 -0
  16. data/ext/libcouchbase/include/libcouchbase/couchbase.h +10 -0
  17. data/ext/libcouchbase/include/libcouchbase/error.h +7 -0
  18. data/ext/libcouchbase/include/libcouchbase/n1ql.h +13 -1
  19. data/ext/libcouchbase/include/libcouchbase/plugins/io/bsdio-inl.c +1 -1
  20. data/ext/libcouchbase/include/libcouchbase/subdoc.h +9 -0
  21. data/ext/libcouchbase/include/libcouchbase/views.h +7 -1
  22. data/ext/libcouchbase/include/libcouchbase/visibility.h +1 -0
  23. data/ext/libcouchbase/include/memcached/protocol_binary.h +21 -1132
  24. data/ext/libcouchbase/packaging/parse-git-describe.pl +1 -1
  25. data/ext/libcouchbase/plugins/io/libev/libev_io_opts.h +3 -2
  26. data/ext/libcouchbase/src/README.md +0 -2
  27. data/ext/libcouchbase/src/auth-priv.h +1 -0
  28. data/ext/libcouchbase/src/auth.cc +10 -0
  29. data/ext/libcouchbase/src/bootstrap.cc +216 -0
  30. data/ext/libcouchbase/src/bootstrap.h +50 -39
  31. data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +455 -0
  32. data/ext/libcouchbase/src/bucketconfig/bc_file.cc +281 -0
  33. data/ext/libcouchbase/src/bucketconfig/bc_http.cc +528 -0
  34. data/ext/libcouchbase/src/bucketconfig/bc_http.h +50 -25
  35. data/ext/libcouchbase/src/bucketconfig/bc_mcraw.cc +115 -0
  36. data/ext/libcouchbase/src/bucketconfig/clconfig.h +407 -386
  37. data/ext/libcouchbase/src/bucketconfig/confmon.cc +378 -0
  38. data/ext/libcouchbase/src/cbft.cc +22 -27
  39. data/ext/libcouchbase/src/cntl.cc +24 -24
  40. data/ext/libcouchbase/src/connspec.cc +30 -1
  41. data/ext/libcouchbase/src/connspec.h +17 -0
  42. data/ext/libcouchbase/src/dns-srv.cc +143 -0
  43. data/ext/libcouchbase/src/{dump.c → dump.cc} +8 -11
  44. data/ext/libcouchbase/src/getconfig.cc +73 -0
  45. data/ext/libcouchbase/src/handler.cc +84 -85
  46. data/ext/libcouchbase/src/hostlist.cc +0 -1
  47. data/ext/libcouchbase/src/hostlist.h +6 -1
  48. data/ext/libcouchbase/src/http/http-priv.h +125 -112
  49. data/ext/libcouchbase/src/http/http.cc +9 -29
  50. data/ext/libcouchbase/src/http/http.h +1 -34
  51. data/ext/libcouchbase/src/http/http_io.cc +22 -26
  52. data/ext/libcouchbase/src/instance.cc +102 -28
  53. data/ext/libcouchbase/src/internal.h +47 -29
  54. data/ext/libcouchbase/src/jsparse/parser.cc +146 -202
  55. data/ext/libcouchbase/src/jsparse/parser.h +91 -98
  56. data/ext/libcouchbase/src/lcbht/lcbht.cc +177 -0
  57. data/ext/libcouchbase/src/lcbht/lcbht.h +174 -163
  58. data/ext/libcouchbase/src/lcbio/connect.cc +562 -0
  59. data/ext/libcouchbase/src/lcbio/connect.h +9 -2
  60. data/ext/libcouchbase/src/lcbio/ctx.c +1 -1
  61. data/ext/libcouchbase/src/lcbio/iotable.h +61 -16
  62. data/ext/libcouchbase/src/lcbio/ioutils.h +1 -1
  63. data/ext/libcouchbase/src/lcbio/manager.c +2 -2
  64. data/ext/libcouchbase/src/lcbio/timer-cxx.h +87 -0
  65. data/ext/libcouchbase/src/mc/mcreq.h +9 -2
  66. data/ext/libcouchbase/src/mcserver/mcserver.cc +723 -0
  67. data/ext/libcouchbase/src/mcserver/mcserver.h +160 -70
  68. data/ext/libcouchbase/src/mcserver/negotiate.cc +118 -152
  69. data/ext/libcouchbase/src/mcserver/negotiate.h +85 -74
  70. data/ext/libcouchbase/src/mctx-helper.h +51 -0
  71. data/ext/libcouchbase/src/n1ql/ixmgmt.cc +1 -2
  72. data/ext/libcouchbase/src/n1ql/n1ql.cc +56 -32
  73. data/ext/libcouchbase/src/{newconfig.c → newconfig.cc} +42 -70
  74. data/ext/libcouchbase/src/nodeinfo.cc +4 -8
  75. data/ext/libcouchbase/src/operations/{cbflush.c → cbflush.cc} +7 -15
  76. data/ext/libcouchbase/src/operations/{counter.c → counter.cc} +0 -0
  77. data/ext/libcouchbase/src/operations/{durability-cas.c → durability-cas.cc} +92 -76
  78. data/ext/libcouchbase/src/operations/{durability-seqno.c → durability-seqno.cc} +55 -49
  79. data/ext/libcouchbase/src/operations/durability.cc +643 -0
  80. data/ext/libcouchbase/src/operations/durability_internal.h +212 -124
  81. data/ext/libcouchbase/src/operations/{get.c → get.cc} +24 -26
  82. data/ext/libcouchbase/src/operations/{observe-seqno.c → observe-seqno.cc} +5 -8
  83. data/ext/libcouchbase/src/operations/{observe.c → observe.cc} +69 -94
  84. data/ext/libcouchbase/src/operations/{pktfwd.c → pktfwd.cc} +0 -0
  85. data/ext/libcouchbase/src/operations/{remove.c → remove.cc} +0 -0
  86. data/ext/libcouchbase/src/operations/{stats.c → stats.cc} +66 -78
  87. data/ext/libcouchbase/src/operations/{store.c → store.cc} +27 -32
  88. data/ext/libcouchbase/src/operations/subdoc.cc +38 -18
  89. data/ext/libcouchbase/src/operations/{touch.c → touch.cc} +0 -0
  90. data/ext/libcouchbase/src/packetutils.h +200 -137
  91. data/ext/libcouchbase/src/probes.d +1 -1
  92. data/ext/libcouchbase/src/{retrychk.c → retrychk.cc} +3 -4
  93. data/ext/libcouchbase/src/retryq.cc +394 -0
  94. data/ext/libcouchbase/src/retryq.h +116 -104
  95. data/ext/libcouchbase/src/settings.h +2 -1
  96. data/ext/libcouchbase/src/ssl/ssl_c.c +1 -0
  97. data/ext/libcouchbase/src/ssl/ssl_e.c +0 -1
  98. data/ext/libcouchbase/src/trace.h +8 -8
  99. data/ext/libcouchbase/src/vbucket/vbucket.c +0 -1
  100. data/ext/libcouchbase/src/views/{docreq.c → docreq.cc} +48 -54
  101. data/ext/libcouchbase/src/views/docreq.h +24 -30
  102. data/ext/libcouchbase/src/views/viewreq.cc +318 -0
  103. data/ext/libcouchbase/src/views/viewreq.h +43 -13
  104. data/ext/libcouchbase/src/{wait.c → wait.cc} +12 -17
  105. data/ext/libcouchbase/tests/basic/t_connstr.cc +89 -50
  106. data/ext/libcouchbase/tests/basic/t_jsparse.cc +27 -78
  107. data/ext/libcouchbase/tests/basic/t_packet.cc +35 -42
  108. data/ext/libcouchbase/tests/htparse/t_basic.cc +58 -78
  109. data/ext/libcouchbase/tests/iotests/t_confmon.cc +94 -111
  110. data/ext/libcouchbase/tests/iotests/t_sched.cc +1 -2
  111. data/ext/libcouchbase/tests/mc/t_alloc.cc +9 -9
  112. data/ext/libcouchbase/tools/cbc-pillowfight.cc +1 -1
  113. data/lib/libcouchbase/version.rb +1 -1
  114. metadata +36 -39
  115. data/ext/libcouchbase/include/memcached/vbucket.h +0 -42
  116. data/ext/libcouchbase/src/bootstrap.c +0 -269
  117. data/ext/libcouchbase/src/bucketconfig/bc_cccp.c +0 -495
  118. data/ext/libcouchbase/src/bucketconfig/bc_file.c +0 -347
  119. data/ext/libcouchbase/src/bucketconfig/bc_http.c +0 -630
  120. data/ext/libcouchbase/src/bucketconfig/bc_mcraw.c +0 -150
  121. data/ext/libcouchbase/src/bucketconfig/confmon.c +0 -474
  122. data/ext/libcouchbase/src/getconfig.c +0 -100
  123. data/ext/libcouchbase/src/lcbht/lcbht.c +0 -282
  124. data/ext/libcouchbase/src/lcbio/connect.c +0 -557
  125. data/ext/libcouchbase/src/mcserver/mcserver.c +0 -784
  126. data/ext/libcouchbase/src/operations/durability.c +0 -668
  127. data/ext/libcouchbase/src/packetutils.c +0 -60
  128. data/ext/libcouchbase/src/retryq.c +0 -424
  129. data/ext/libcouchbase/src/simplestring.c +0 -211
  130. data/ext/libcouchbase/src/simplestring.h +0 -228
  131. data/ext/libcouchbase/src/ssobuf.h +0 -82
  132. data/ext/libcouchbase/src/views/viewreq.c +0 -358
  133. data/ext/libcouchbase/tests/basic/t_string.cc +0 -112
@@ -1,4 +1,4 @@
1
- #!/usr/bin/perl
1
+ #!/usr/bin/env perl
2
2
 
3
3
  use strict;
4
4
  use warnings;
@@ -48,11 +48,12 @@ extern "C" {
48
48
  * Create an instance of an event handler that utilize libev for
49
49
  * event notification.
50
50
  *
51
- * @param version the API version to use
51
+ * @param version Set this to 0. This may be used in the future to allow
52
+ * variation on the third argument (`void*` currently).
53
+ * @param[out] io a pointer to a newly created and initialized event handler
52
54
  * @param loop the event loop (struct ev_loop *) to hook use (please
53
55
  * note that you shouldn't reference the event loop from
54
56
  * multiple threads)
55
- * @param io a pointer to a newly created and initialized event handler
56
57
  * @return status of the operation
57
58
  */
58
59
  LIBCOUCHBASE_API
@@ -43,8 +43,6 @@ listing of the various subcomponents and what they do:
43
43
 
44
44
  * `sllist.h, sllist-inl.h` contain the implementation for a single-linked list
45
45
 
46
- * `simplestring.{c,h}` contains the implementation for a dynamically sized string
47
-
48
46
  * `logging.{c,h}` contains the implementation for the library's logging mechanism
49
47
 
50
48
  * `hostlist.{c,h}` defines a list of hosts, with features for de-duping and converting
@@ -14,6 +14,7 @@ public:
14
14
  const std::string& password() const { return m_password; }
15
15
  const Map& buckets() const { return m_buckets; }
16
16
  Authenticator() : m_refcount(1) {}
17
+ Authenticator(const Authenticator&);
17
18
 
18
19
  size_t refcount() const { return m_refcount; }
19
20
  void incref() { ++m_refcount; }
@@ -97,3 +97,13 @@ Authenticator::init(const std::string& username_, const std::string& bucket,
97
97
  m_buckets[bucket] = m_password;
98
98
  return LCB_SUCCESS;
99
99
  }
100
+
101
+ Authenticator::Authenticator(const Authenticator& other)
102
+ : m_buckets(other.m_buckets), m_username(other.m_username),
103
+ m_password(other.m_password), m_refcount(1) {
104
+ }
105
+
106
+ lcb_AUTHENTICATOR *
107
+ lcbauth_clone(const lcb_AUTHENTICATOR *src) {
108
+ return new Authenticator(*src);
109
+ }
@@ -0,0 +1,216 @@
1
+ /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2014 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
+ #define LCB_BOOTSTRAP_DEFINE_STRUCT 1
19
+ #include "internal.h"
20
+
21
+
22
+ #define LOGARGS(instance, lvl) instance->settings, "bootstrap", LCB_LOG_##lvl, __FILE__, __LINE__
23
+
24
+ using lcb::clconfig::EventType;
25
+ using lcb::clconfig::ConfigInfo;
26
+ using namespace lcb;
27
+
28
+ /**
29
+ * This function is where the configuration actually takes place. We ensure
30
+ * in other functions that this is only ever called directly from an event
31
+ * loop stack frame (or one of the small mini functions here) so that we
32
+ * don't accidentally end up destroying resources underneath us.
33
+ */
34
+ void Bootstrap::config_callback(EventType event, ConfigInfo *info) {
35
+ using namespace lcb::clconfig;
36
+ lcb_t instance = parent;
37
+
38
+ if (event != CLCONFIG_EVENT_GOT_NEW_CONFIG) {
39
+ if (event == CLCONFIG_EVENT_PROVIDERS_CYCLED) {
40
+ if (!LCBT_VBCONFIG(instance)) {
41
+ initial_error(LCB_ERROR, "No more bootstrap providers remain");
42
+ }
43
+ }
44
+ return;
45
+ }
46
+
47
+ instance->last_error = LCB_SUCCESS;
48
+
49
+ /** Ensure we're not called directly twice again */
50
+ if (state < S_INITIAL_TRIGGERED) {
51
+ state = S_INITIAL_TRIGGERED;
52
+ }
53
+
54
+ tm.cancel();
55
+
56
+ lcb_log(LOGARGS(instance, DEBUG), "Instance configured!");
57
+
58
+ if (info->get_origin() != CLCONFIG_FILE) {
59
+ /* Set the timestamp for the current config to control throttling,
60
+ * but only if it's not an initial file-based config. See CCBC-482 */
61
+ last_refresh = gethrtime();
62
+ errcounter = 0;
63
+ }
64
+
65
+ if (info->get_origin() == CLCONFIG_CCCP) {
66
+ /* Disable HTTP provider if we've received something via CCCP */
67
+
68
+ if (instance->cur_configinfo == NULL ||
69
+ instance->cur_configinfo->get_origin() != CLCONFIG_HTTP) {
70
+ /* Never disable HTTP if it's still being used */
71
+ instance->confmon->set_active(CLCONFIG_HTTP, false);
72
+ }
73
+ }
74
+
75
+ if (instance->type != LCB_TYPE_CLUSTER) {
76
+ lcb_update_vbconfig(instance, info);
77
+ }
78
+
79
+ if (state < S_BOOTSTRAPPED) {
80
+ state = S_BOOTSTRAPPED;
81
+ lcb_aspend_del(&instance->pendops, LCB_PENDTYPE_COUNTER, NULL);
82
+
83
+ if (instance->type == LCB_TYPE_BUCKET &&
84
+ LCBVB_DISTTYPE(LCBT_VBCONFIG(instance)) == LCBVB_DIST_KETAMA &&
85
+ instance->cur_configinfo->get_origin() != CLCONFIG_MCRAW) {
86
+
87
+ lcb_log(LOGARGS(instance, INFO), "Reverting to HTTP Config for memcached buckets");
88
+ instance->settings->bc_http_stream_time = -1;
89
+ instance->confmon->set_active(CLCONFIG_HTTP, true);
90
+ instance->confmon->set_active(CLCONFIG_CCCP, false);
91
+ }
92
+ instance->callbacks.bootstrap(instance, LCB_SUCCESS);
93
+ }
94
+
95
+ lcb_maybe_breakout(instance);
96
+ }
97
+
98
+ void Bootstrap::clconfig_lsn(EventType e, ConfigInfo *i) {
99
+ if (state == S_INITIAL_PRE) {
100
+ config_callback(e, i);
101
+ } else if (e == clconfig::CLCONFIG_EVENT_GOT_NEW_CONFIG) {
102
+ lcb_log(LOGARGS(parent, INFO), "Got new config. Will refresh asynchronously");
103
+ tm.signal();
104
+ }
105
+ }
106
+
107
+ /**
108
+ * This it the initial bootstrap timeout handler. This timeout pins down the
109
+ * instance. It is only scheduled during the initial bootstrap and is only
110
+ * triggered if the initial bootstrap fails to configure in time.
111
+ */
112
+ void Bootstrap::timer_dispatch() {
113
+ if (state > S_INITIAL_PRE) {
114
+ config_callback(clconfig::CLCONFIG_EVENT_GOT_NEW_CONFIG,
115
+ parent->confmon->get_config());
116
+ } else {
117
+ // Not yet bootstrapped!
118
+ initial_error(LCB_ETIMEDOUT, "Failed to bootstrap in time");
119
+ }
120
+ }
121
+
122
+
123
+ void Bootstrap::initial_error(lcb_error_t err, const char *errinfo) {
124
+ parent->last_error = parent->confmon->get_last_error();
125
+ if (parent->last_error == LCB_SUCCESS) {
126
+ parent->last_error = err;
127
+ }
128
+ parent->callbacks.error(parent, parent->last_error, errinfo);
129
+ lcb_log(LOGARGS(parent, ERR), "Failed to bootstrap client=%p. Error=%s, Message=%s", (void *)parent, lcb_strerror_short(parent->last_error), errinfo);
130
+ tm.cancel();
131
+
132
+ parent->callbacks.bootstrap(parent, parent->last_error);
133
+
134
+ lcb_aspend_del(&parent->pendops, LCB_PENDTYPE_COUNTER, NULL);
135
+ lcb_maybe_breakout(parent);
136
+ }
137
+
138
+ Bootstrap::Bootstrap(lcb_t instance)
139
+ : parent(instance),
140
+ tm(parent->iotable, this),
141
+ last_refresh(0),
142
+ errcounter(0),
143
+ state(S_INITIAL_PRE) {
144
+ parent->confmon->add_listener(this);
145
+ }
146
+
147
+ lcb_error_t Bootstrap::bootstrap(unsigned options) {
148
+ hrtime_t now = gethrtime();
149
+ if (parent->confmon->is_refreshing()) {
150
+ return LCB_SUCCESS;
151
+ }
152
+
153
+ if (options & BS_REFRESH_THROTTLE) {
154
+ /* Refresh throttle requested. This is not true if options == ALWAYS */
155
+ hrtime_t next_ts;
156
+ unsigned errthresh = LCBT_SETTING(parent, weird_things_threshold);
157
+
158
+ if (options & BS_REFRESH_INCRERR) {
159
+ errcounter++;
160
+ }
161
+ next_ts = last_refresh;
162
+ next_ts += LCB_US2NS(LCBT_SETTING(parent, weird_things_delay));
163
+ if (now < next_ts && errcounter < errthresh) {
164
+ lcb_log(LOGARGS(parent, INFO),
165
+ "Not requesting a config refresh because of throttling parameters. Next refresh possible in %ums or %u errors. "
166
+ "See LCB_CNTL_CONFDELAY_THRESH and LCB_CNTL_CONFERRTHRESH to modify the throttling settings",
167
+ LCB_NS2US(next_ts-now)/1000, (unsigned)errthresh-errcounter);
168
+ return LCB_SUCCESS;
169
+ }
170
+ }
171
+
172
+ if (options == BS_REFRESH_INITIAL) {
173
+ state = S_INITIAL_PRE;
174
+ parent->confmon->prepare();
175
+ tm.rearm(LCBT_SETTING(parent, config_timeout));
176
+ lcb_aspend_add(&parent->pendops, LCB_PENDTYPE_COUNTER, NULL);
177
+ }
178
+
179
+ /* Reset the counters */
180
+ errcounter = 0;
181
+ if (options != BS_REFRESH_INITIAL) {
182
+ last_refresh = now;
183
+ }
184
+ parent->confmon->start();
185
+ return LCB_SUCCESS;
186
+ }
187
+
188
+ Bootstrap::~Bootstrap() {
189
+ tm.release();
190
+ parent->confmon->remove_listener(this);
191
+ }
192
+
193
+ LIBCOUCHBASE_API
194
+ lcb_error_t
195
+ lcb_get_bootstrap_status(lcb_t instance)
196
+ {
197
+ if (instance->cur_configinfo) {
198
+ return LCB_SUCCESS;
199
+ }
200
+ if (instance->last_error != LCB_SUCCESS) {
201
+ return instance->last_error;
202
+ }
203
+ if (instance->type == LCB_TYPE_CLUSTER) {
204
+ if (lcb::clconfig::http_get_conn(instance->confmon) != NULL) {
205
+ return LCB_SUCCESS;
206
+ }
207
+ }
208
+ return LCB_ERROR;
209
+ }
210
+
211
+ LIBCOUCHBASE_API
212
+ void
213
+ lcb_refresh_config(lcb_t instance)
214
+ {
215
+ instance->bootstrap(BS_REFRESH_ALWAYS);
216
+ }
@@ -17,9 +17,6 @@
17
17
 
18
18
  #ifndef LCB_BOOTSTRAP_H
19
19
  #define LCB_BOOTSTRAP_H
20
- #ifdef __cplusplus
21
- extern "C" {
22
- #endif
23
20
 
24
21
  /**@file
25
22
  * Core bootstrap/cluster configuration routines */
@@ -29,19 +26,43 @@ extern "C" {
29
26
  * @{
30
27
  */
31
28
 
32
- #if defined(__LCB_DOXYGEN__) || defined(LCB_BOOTSTRAP_DEFINE_STRUCT)
29
+ #ifdef __cplusplus
33
30
  #include "bucketconfig/clconfig.h"
31
+ #include <lcbio/timer-cxx.h>
34
32
 
33
+ namespace lcb {
35
34
  /**
36
35
  * Structure containing the bootstrap state for the instance.
36
+ *
37
+ * Derived from Listener,
38
+ * used to react when a new configuration is received. This
39
+ * is used for both requested configurations (i.e. an explicit call to
40
+ * lcb_bootstrap_common()) as well as unsolicited updates such as
41
+ * HTTP streaming configurations or Not-My-Vbucket "Carrier" updates.
37
42
  */
38
- struct lcb_BOOTSTRAP {
39
- /**Listener object used to react when a new configuration is received. This
40
- * is used for both requested configurations (i.e. an explicit call to
41
- * lcb_bootstrap_common()) as well as unsolicited updates such as
42
- * HTTP streaming configurations or Not-My-Vbucket "Carrier" updates.
43
- */
44
- clconfig_listener listener;
43
+ class Bootstrap : lcb::clconfig::Listener {
44
+ public:
45
+ Bootstrap(lcb_t);
46
+ ~Bootstrap();
47
+ lcb_error_t bootstrap(unsigned options);
48
+
49
+ hrtime_t get_last_refresh() const {
50
+ return last_refresh;
51
+ }
52
+ void reset_last_refresh() {
53
+ last_refresh = 0;
54
+ }
55
+ size_t get_errcounter() const {
56
+ return errcounter;
57
+ }
58
+
59
+ private:
60
+ // Override
61
+ void clconfig_lsn(lcb::clconfig::EventType e, lcb::clconfig::ConfigInfo* i);
62
+
63
+ inline void config_callback(lcb::clconfig::EventType, lcb::clconfig::ConfigInfo*);
64
+ inline void initial_error(lcb_error_t, const char *);
65
+ void timer_dispatch();
45
66
 
46
67
  lcb_t parent;
47
68
 
@@ -49,7 +70,7 @@ struct lcb_BOOTSTRAP {
49
70
  * updates as an asynchronous event (to allow safe updates and avoid
50
71
  * reentrancy issues)
51
72
  */
52
- lcbio_pTIMER tm;
73
+ lcb::io::Timer<Bootstrap, &Bootstrap::timer_dispatch> tm;
53
74
 
54
75
  /**
55
76
  * Timestamp indicating the most recent configuration activity. This
@@ -73,57 +94,47 @@ struct lcb_BOOTSTRAP {
73
94
  */
74
95
  unsigned errcounter;
75
96
 
76
- /** Flag indicating whether the _initial_ configuration has been received */
77
- int bootstrapped;
97
+ enum State {
98
+ /** Initial 'blank' state */
99
+ S_INITIAL_PRE = 0,
100
+ /** We got something after our initial callback */
101
+ S_INITIAL_TRIGGERED,
102
+ /** Have received at least one valid configuration */
103
+ S_BOOTSTRAPPED
104
+ };
105
+ State state;
78
106
  };
79
- #endif
80
107
 
81
108
  /**
82
109
  * These flags control the bootstrap refreshing mode that will take place
83
110
  * when lcb_bootstrap_common() is invoked. These options may be OR'd with
84
111
  * each other (with the exception of ::LCB_BS_REFRESH_ALWAYS).
85
112
  */
86
- typedef enum {
113
+ enum BootstrapOptions {
87
114
  /** Always fetch a new configuration. No throttling checks are performed */
88
- LCB_BS_REFRESH_ALWAYS = 0x00,
115
+ BS_REFRESH_ALWAYS = 0x00,
89
116
  /** Special mode used to fetch the first configuration */
90
- LCB_BS_REFRESH_INITIAL = 0x02,
117
+ BS_REFRESH_INITIAL = 0x02,
91
118
 
92
119
  /** Make the request for a new configuration subject to throttling
93
120
  * limitations. Currently this will be subject to the interval specified
94
121
  * in the @ref LCB_CNTL_CONFDELAY_THRESH setting and the @ref
95
122
  * LCB_CNTL_CONFERRTHRESH setting. If the refresh has been throttled
96
123
  * the lcb_confmon_is_refreshing() function will return false */
97
- LCB_BS_REFRESH_THROTTLE = 0x04,
124
+ BS_REFRESH_THROTTLE = 0x04,
98
125
 
99
126
  /** To be used in conjunction with ::LCB_BS_REFRESH_THROTTLE, this will
100
127
  * increment the error counter in case the current refresh is throttled,
101
128
  * such that when the error counter reaches the threshold, the throttle
102
129
  * limitations will expire and a new refresh will take place */
103
- LCB_BS_REFRESH_INCRERR = 0x08
104
- } lcb_BSFLAGS;
105
-
106
- /**
107
- * @brief Request that the handle update its configuration.
108
- *
109
- * This function acts as a gateway to the more abstract confmon interface.
110
- *
111
- * @param instance The instance
112
- * @param options A set of options specified as flags, indicating under what
113
- * conditions a new configuration should be refetched.
114
- *
115
- * @return
116
- */
117
- LCB_INTERNAL_API
118
- lcb_error_t
119
- lcb_bootstrap_common(lcb_t instance, int options);
130
+ BS_REFRESH_INCRERR = 0x08
131
+ };
120
132
 
121
133
  void
122
134
  lcb_bootstrap_destroy(lcb_t instance);
123
135
 
124
136
  /**@}*/
125
137
 
126
- #ifdef __cplusplus
127
- }
128
- #endif
138
+ } // namespace lcb
139
+ #endif // __cplusplus
129
140
  #endif /* LCB_BOOTSTRAP_H */
@@ -0,0 +1,455 @@
1
+ /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2014 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
+ /**
19
+ * This file contains the CCCP (Cluster Carrier Configuration Protocol)
20
+ * implementation of the confmon provider. It utilizes a memcached connection
21
+ * to retrieve configuration information.
22
+ */
23
+
24
+ #include "internal.h"
25
+ #include "clconfig.h"
26
+ #include "packetutils.h"
27
+ #include <mcserver/negotiate.h>
28
+ #include <lcbio/lcbio.h>
29
+ #include <lcbio/timer-cxx.h>
30
+ #include <lcbio/ssl.h>
31
+ #include "ctx-log-inl.h"
32
+ #define LOGARGS(cccp, lvl) cccp->parent->settings, "cccp", LCB_LOG_##lvl, __FILE__, __LINE__
33
+ #define LOGFMT "<%s:%s> "
34
+ #define LOGID(cccp) get_ctx_host(cccp->ioctx), get_ctx_port(cccp->ioctx)
35
+
36
+ struct CccpCookie;
37
+
38
+ using namespace lcb::clconfig;
39
+
40
+ struct CccpProvider : public Provider {
41
+ CccpProvider(Confmon *);
42
+ ~CccpProvider();
43
+
44
+ void release_socket(bool can_reuse);
45
+ lcb_error_t schedule_next_request(lcb_error_t why, bool can_rollover);
46
+ lcb_error_t mcio_error(lcb_error_t why);
47
+ void on_timeout() { mcio_error(LCB_ETIMEDOUT); }
48
+ lcb_error_t update(const char *host, const char* data);
49
+ void request_config();
50
+ void on_io_read();
51
+
52
+ bool pause(); // Override
53
+ void configure_nodes(const lcb::Hostlist&); // Override
54
+ void config_updated(lcbvb_CONFIG *); // Override;
55
+ void dump(FILE*) const; // Override
56
+ lcb_error_t refresh(); // Override
57
+
58
+ ConfigInfo *get_cached() /* Override */ {
59
+ return config;
60
+ }
61
+
62
+ const lcb::Hostlist* get_nodes() const /* Override */ {
63
+ return nodes;
64
+ }
65
+
66
+ void enable(void *arg) {
67
+ instance = reinterpret_cast<lcb_t>(arg);
68
+ Provider::enable();
69
+ }
70
+
71
+ lcb::Hostlist *nodes;
72
+ ConfigInfo *config;
73
+ bool server_active;
74
+ lcb::io::Timer<CccpProvider, &CccpProvider::on_timeout> timer;
75
+ lcb_t instance;
76
+ lcbio_CONNREQ creq;
77
+ lcbio_CTX *ioctx;
78
+ CccpCookie *cmdcookie;
79
+ };
80
+
81
+ struct CccpCookie {
82
+ CccpProvider *parent;
83
+ bool ignore_errors;
84
+ CccpCookie(CccpProvider *parent_) : parent(parent_), ignore_errors(false) {
85
+ }
86
+ };
87
+
88
+ static void io_error_handler(lcbio_CTX *, lcb_error_t);
89
+ static void io_read_handler(lcbio_CTX *, unsigned nr);
90
+ static void on_connected(lcbio_SOCKET *, void*, lcb_error_t, lcbio_OSERR);
91
+
92
+ static void
93
+ pooled_close_cb(lcbio_SOCKET *sock, int reusable, void *arg)
94
+ {
95
+ bool *ru_ex = reinterpret_cast<bool*>(arg);
96
+ lcbio_ref(sock);
97
+ if (reusable && *ru_ex) {
98
+ lcbio_mgr_put(sock);
99
+ } else {
100
+ lcbio_mgr_discard(sock);
101
+ }
102
+ }
103
+
104
+ void
105
+ CccpProvider::release_socket(bool can_reuse)
106
+ {
107
+ if (cmdcookie) {
108
+ cmdcookie->ignore_errors = 1;
109
+ cmdcookie = NULL;
110
+ return;
111
+ }
112
+
113
+ lcbio_connreq_cancel(&creq);
114
+
115
+ if (ioctx) {
116
+ lcbio_ctx_close(ioctx, pooled_close_cb, &can_reuse);
117
+ ioctx = NULL;
118
+ }
119
+ }
120
+
121
+ lcb_error_t
122
+ CccpProvider::schedule_next_request(lcb_error_t err, bool can_rollover)
123
+ {
124
+ lcb::Server *server;
125
+ lcb_host_t *next_host = nodes->next(can_rollover);
126
+ if (!next_host) {
127
+ timer.cancel();
128
+ parent->provider_failed(this, err);
129
+ server_active = false;
130
+ return err;
131
+ }
132
+
133
+ server = instance->find_server(*next_host);
134
+ if (server) {
135
+ CccpCookie *cookie = new CccpCookie(this);
136
+ cmdcookie = cookie;
137
+ lcb_log(LOGARGS(this, INFO), "Re-Issuing CCCP Command on server struct %p (%s:%s)", (void*)server, next_host->host, next_host->port);
138
+ timer.rearm(settings().config_node_timeout);
139
+ instance->request_config(cookie, server);
140
+
141
+ } else {
142
+ lcbio_pMGRREQ preq;
143
+
144
+ lcb_log(LOGARGS(this, INFO), "Requesting connection to node %s:%s for CCCP configuration", next_host->host, next_host->port);
145
+ preq = lcbio_mgr_get(
146
+ instance->memd_sockpool, next_host,
147
+ settings().config_node_timeout,
148
+ on_connected, this);
149
+ LCBIO_CONNREQ_MKPOOLED(&creq, preq);
150
+ }
151
+
152
+ server_active = true;
153
+ return LCB_SUCCESS;
154
+ }
155
+
156
+ lcb_error_t
157
+ CccpProvider::mcio_error(lcb_error_t err)
158
+ {
159
+ if (err != LCB_NOT_SUPPORTED && err != LCB_UNKNOWN_COMMAND) {
160
+ lcb_log(LOGARGS(this, ERR), LOGFMT "Could not get configuration: %s", LOGID(this), lcb_strerror_short(err));
161
+ }
162
+
163
+ release_socket(err == LCB_NOT_SUPPORTED);
164
+ return schedule_next_request(err, false);
165
+ }
166
+
167
+ /** Update the configuration from a server. */
168
+ lcb_error_t
169
+ lcb::clconfig::cccp_update(Provider *provider, const char *host, const char *data) {
170
+ return static_cast<CccpProvider*>(provider)->update(host, data);
171
+ }
172
+
173
+ lcb_error_t
174
+ CccpProvider::update(const char *host, const char *data)
175
+ {
176
+ /** TODO: replace this with lcbvb_ names */
177
+ lcbvb_CONFIG* vbc;
178
+ int rv;
179
+ ConfigInfo *new_config;
180
+ vbc = lcbvb_create();
181
+
182
+ if (!vbc) {
183
+ return LCB_CLIENT_ENOMEM;
184
+ }
185
+ rv = lcbvb_load_json(vbc, data);
186
+
187
+ if (rv) {
188
+ lcb_log(LOGARGS(this, ERROR), LOGFMT "Failed to parse config", LOGID(this));
189
+ lcb_log_badconfig(LOGARGS(this, ERROR), vbc, data);
190
+ lcbvb_destroy(vbc);
191
+ return LCB_PROTOCOL_ERROR;
192
+ }
193
+
194
+ lcbvb_replace_host(vbc, host);
195
+ new_config = ConfigInfo::create(vbc, CLCONFIG_CCCP);
196
+
197
+ if (!new_config) {
198
+ lcbvb_destroy(vbc);
199
+ return LCB_CLIENT_ENOMEM;
200
+ }
201
+
202
+ if (config) {
203
+ config->decref();
204
+ }
205
+
206
+ /** TODO: Figure out the comparison vector */
207
+ config = new_config;
208
+ parent->provider_got_config(this, new_config);
209
+ return LCB_SUCCESS;
210
+ }
211
+
212
+ void lcb::clconfig::cccp_update(
213
+ const void *cookie, lcb_error_t err,
214
+ const void *bytes, size_t nbytes, const lcb_host_t *origin)
215
+ {
216
+ CccpCookie *ck = reinterpret_cast<CccpCookie*>(const_cast<void*>(cookie));
217
+ CccpProvider *cccp = ck->parent;
218
+
219
+ if (ck == cccp->cmdcookie) {
220
+ cccp->timer.cancel();
221
+ cccp->cmdcookie = NULL;
222
+ }
223
+
224
+ if (err == LCB_SUCCESS) {
225
+ std::string ss(reinterpret_cast<const char *>(bytes), nbytes);
226
+ err = cccp->update(origin->host, ss.c_str());
227
+ }
228
+
229
+ if (err != LCB_SUCCESS && ck->ignore_errors == 0) {
230
+ cccp->mcio_error(err);
231
+ }
232
+
233
+ free(ck);
234
+ }
235
+
236
+ static void
237
+ on_connected(lcbio_SOCKET *sock, void *data, lcb_error_t err, lcbio_OSERR)
238
+ {
239
+ lcbio_CTXPROCS ioprocs;
240
+ CccpProvider *cccp = reinterpret_cast<CccpProvider*>(data);
241
+ lcb_settings *settings = cccp->parent->settings;
242
+
243
+ LCBIO_CONNREQ_CLEAR(&cccp->creq);
244
+ if (err != LCB_SUCCESS) {
245
+ if (sock) {
246
+ lcbio_mgr_discard(sock);
247
+ }
248
+ cccp->mcio_error(err);
249
+ return;
250
+ }
251
+
252
+ if (lcbio_protoctx_get(sock, LCBIO_PROTOCTX_SESSINFO) == NULL) {
253
+ lcb::SessionRequest *sreq = lcb::SessionRequest::start(
254
+ sock, settings, settings->config_node_timeout, on_connected,
255
+ cccp);
256
+ LCBIO_CONNREQ_MKGENERIC(&cccp->creq, sreq, lcb::sessreq_cancel);
257
+ return;
258
+ }
259
+
260
+ ioprocs.cb_err = io_error_handler;
261
+ ioprocs.cb_read = io_read_handler;
262
+ cccp->ioctx = lcbio_ctx_new(sock, data, &ioprocs);
263
+ cccp->ioctx->subsys = "bc_cccp";
264
+ cccp->request_config();
265
+ }
266
+
267
+ lcb_error_t CccpProvider::refresh() {
268
+ if (creq.u.p_generic || server_active || cmdcookie) {
269
+ return LCB_BUSY;
270
+ }
271
+
272
+ return schedule_next_request(LCB_SUCCESS, true);
273
+ }
274
+
275
+ bool
276
+ CccpProvider::pause()
277
+ {
278
+ if (!server_active) {
279
+ return true;
280
+ }
281
+
282
+ server_active = 0;
283
+ release_socket(false);
284
+ timer.cancel();
285
+ return true;
286
+ }
287
+
288
+ CccpProvider::~CccpProvider() {
289
+ release_socket(false);
290
+
291
+ if (config) {
292
+ config->decref();
293
+ }
294
+ if (nodes) {
295
+ delete nodes;
296
+ }
297
+ timer.release();
298
+ if (cmdcookie) {
299
+ cmdcookie->ignore_errors = 1;
300
+ }
301
+ }
302
+
303
+ void
304
+ CccpProvider::configure_nodes(const lcb::Hostlist& nodes_)
305
+ {
306
+ nodes->assign(nodes_);
307
+ if (parent->settings->randomize_bootstrap_nodes) {
308
+ nodes->randomize();
309
+ }
310
+ }
311
+
312
+ void
313
+ CccpProvider::config_updated(lcbvb_CONFIG *vbc)
314
+ {
315
+ lcbvb_SVCMODE mode;
316
+ if (LCBVB_NSERVERS(vbc) < 1) {
317
+ return;
318
+ }
319
+
320
+ nodes->clear();
321
+ if (settings().sslopts & LCB_SSL_ENABLED) {
322
+ mode = LCBVB_SVCMODE_SSL;
323
+ } else {
324
+ mode = LCBVB_SVCMODE_PLAIN;
325
+ }
326
+ for (size_t ii = 0; ii < LCBVB_NSERVERS(vbc); ii++) {
327
+ const char *mcaddr = lcbvb_get_hostport(vbc,
328
+ ii, LCBVB_SVCTYPE_DATA, mode);
329
+ if (!mcaddr) {
330
+ lcb_log(LOGARGS(this, DEBUG), "Node %lu has no data service", ii);
331
+ continue;
332
+ }
333
+ nodes->add(mcaddr, LCB_CONFIG_MCD_PORT);
334
+ }
335
+
336
+ if (settings().randomize_bootstrap_nodes) {
337
+ nodes->randomize();
338
+ }
339
+ }
340
+
341
+ static void
342
+ io_error_handler(lcbio_CTX *ctx, lcb_error_t err)
343
+ {
344
+ CccpProvider *cccp = reinterpret_cast<CccpProvider*>(lcbio_ctx_data(ctx));
345
+ cccp->mcio_error(err);
346
+ }
347
+
348
+ static void io_read_handler(lcbio_CTX *ioctx, unsigned) {
349
+ reinterpret_cast<CccpProvider*>(lcbio_ctx_data(ioctx))->on_io_read();
350
+ }
351
+
352
+ void
353
+ CccpProvider::on_io_read()
354
+ {
355
+ unsigned required;
356
+
357
+ #define return_error(e) \
358
+ resp.release(ioctx); \
359
+ mcio_error(e); \
360
+ return
361
+
362
+ lcb::MemcachedResponse resp;
363
+ if (!resp.load(ioctx, &required)) {
364
+ lcbio_ctx_rwant(ioctx, required);
365
+ lcbio_ctx_schedule(ioctx);
366
+ return;
367
+ }
368
+
369
+ if (resp.status() != PROTOCOL_BINARY_RESPONSE_SUCCESS) {
370
+ lcb_log(LOGARGS(this, WARN), LOGFMT "CCCP Packet responded with 0x%x; nkey=%d, nbytes=%lu, cmd=0x%x, seq=0x%x", LOGID(this),
371
+ resp.status(), resp.keylen(), (unsigned long)resp.bodylen(),
372
+ resp.opcode(), resp.opaque());
373
+
374
+ switch (resp.status()) {
375
+ case PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED:
376
+ case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
377
+ return_error(LCB_NOT_SUPPORTED);
378
+ default:
379
+ return_error(LCB_PROTOCOL_ERROR);
380
+ }
381
+
382
+ return;
383
+ }
384
+
385
+ if (!resp.bodylen()) {
386
+ return_error(LCB_PROTOCOL_ERROR);
387
+ }
388
+
389
+ std::string jsonstr(resp.body<const char*>(), resp.bodylen());
390
+ std::string hoststr(lcbio_get_host(lcbio_ctx_sock(ioctx))->host);
391
+
392
+ resp.release(ioctx);
393
+ release_socket(true);
394
+
395
+ lcb_error_t err = update(hoststr.c_str(), jsonstr.c_str());
396
+
397
+ if (err == LCB_SUCCESS) {
398
+ timer.cancel();
399
+ server_active = false;
400
+ } else {
401
+ schedule_next_request(LCB_PROTOCOL_ERROR, 0);
402
+ }
403
+
404
+ #undef return_error
405
+ }
406
+
407
+ void CccpProvider::request_config()
408
+ {
409
+ lcb::MemcachedRequest req(PROTOCOL_BINARY_CMD_GET_CLUSTER_CONFIG);
410
+ req.opaque(0xF00D);
411
+ lcbio_ctx_put(ioctx, req.data(), req.size());
412
+ lcbio_ctx_rwant(ioctx, 24);
413
+ lcbio_ctx_schedule(ioctx);
414
+ timer.rearm(settings().config_node_timeout);
415
+ }
416
+
417
+ void CccpProvider::dump(FILE *fp) const {
418
+ if (!enabled) {
419
+ return;
420
+ }
421
+
422
+ fprintf(fp, "## BEGIN CCCP PROVIDER DUMP ##\n");
423
+ fprintf(fp, "TIMER ACTIVE: %s\n", timer.is_armed() ? "YES" : "NO");
424
+ fprintf(fp, "PIPELINE RESPONSE COOKIE: %p\n", (void*)cmdcookie);
425
+ if (ioctx) {
426
+ fprintf(fp, "CCCP Owns connection:\n");
427
+ lcbio_ctx_dump(ioctx, fp);
428
+ } else if (creq.u.p_generic) {
429
+ fprintf(fp, "CCCP Is connecting\n");
430
+ } else {
431
+ fprintf(fp, "CCCP does not have a dedicated connection\n");
432
+ }
433
+
434
+ for (size_t ii = 0; ii < nodes->size(); ii++) {
435
+ const lcb_host_t &curhost = (*nodes)[ii];
436
+ fprintf(fp, "CCCP NODE: %s:%s\n", curhost.host, curhost.port);
437
+ }
438
+ fprintf(fp, "## END CCCP PROVIDER DUMP ##\n");
439
+ }
440
+
441
+ CccpProvider::CccpProvider(Confmon *mon)
442
+ : Provider(mon, CLCONFIG_CCCP),
443
+ nodes(new lcb::Hostlist()),
444
+ config(NULL),
445
+ server_active(false),
446
+ timer(mon->iot, this),
447
+ instance(NULL),
448
+ ioctx(NULL),
449
+ cmdcookie(NULL) {
450
+ std::memset(&creq, 0, sizeof creq);
451
+ }
452
+
453
+ Provider* lcb::clconfig::new_cccp_provider(Confmon *mon) {
454
+ return new CccpProvider(mon);
455
+ }