libcouchbase 0.0.7 → 0.0.8

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