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.
- checksums.yaml +4 -4
- data/ext/libcouchbase/.gitignore +2 -0
- data/ext/libcouchbase/CMakeLists.txt +5 -7
- data/ext/libcouchbase/README.markdown +2 -2
- data/ext/libcouchbase/RELEASE_NOTES.markdown +49 -0
- data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +11 -0
- data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -0
- data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +2 -1
- data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
- data/ext/libcouchbase/cmake/config-cmake.h.in +2 -0
- data/ext/libcouchbase/cmake/defs.mk.in +0 -2
- data/ext/libcouchbase/cmake/source_files.cmake +34 -14
- data/ext/libcouchbase/configure.pl +1 -1
- data/ext/libcouchbase/contrib/genhash/genhash.h +6 -0
- data/ext/libcouchbase/include/libcouchbase/auth.h +10 -0
- data/ext/libcouchbase/include/libcouchbase/couchbase.h +10 -0
- data/ext/libcouchbase/include/libcouchbase/error.h +7 -0
- data/ext/libcouchbase/include/libcouchbase/n1ql.h +13 -1
- data/ext/libcouchbase/include/libcouchbase/plugins/io/bsdio-inl.c +1 -1
- data/ext/libcouchbase/include/libcouchbase/subdoc.h +9 -0
- data/ext/libcouchbase/include/libcouchbase/views.h +7 -1
- data/ext/libcouchbase/include/libcouchbase/visibility.h +1 -0
- data/ext/libcouchbase/include/memcached/protocol_binary.h +21 -1132
- data/ext/libcouchbase/packaging/parse-git-describe.pl +1 -1
- data/ext/libcouchbase/plugins/io/libev/libev_io_opts.h +3 -2
- data/ext/libcouchbase/src/README.md +0 -2
- data/ext/libcouchbase/src/auth-priv.h +1 -0
- data/ext/libcouchbase/src/auth.cc +10 -0
- data/ext/libcouchbase/src/bootstrap.cc +216 -0
- data/ext/libcouchbase/src/bootstrap.h +50 -39
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +455 -0
- data/ext/libcouchbase/src/bucketconfig/bc_file.cc +281 -0
- data/ext/libcouchbase/src/bucketconfig/bc_http.cc +528 -0
- data/ext/libcouchbase/src/bucketconfig/bc_http.h +50 -25
- data/ext/libcouchbase/src/bucketconfig/bc_mcraw.cc +115 -0
- data/ext/libcouchbase/src/bucketconfig/clconfig.h +407 -386
- data/ext/libcouchbase/src/bucketconfig/confmon.cc +378 -0
- data/ext/libcouchbase/src/cbft.cc +22 -27
- data/ext/libcouchbase/src/cntl.cc +24 -24
- data/ext/libcouchbase/src/connspec.cc +30 -1
- data/ext/libcouchbase/src/connspec.h +17 -0
- data/ext/libcouchbase/src/dns-srv.cc +143 -0
- data/ext/libcouchbase/src/{dump.c → dump.cc} +8 -11
- data/ext/libcouchbase/src/getconfig.cc +73 -0
- data/ext/libcouchbase/src/handler.cc +84 -85
- data/ext/libcouchbase/src/hostlist.cc +0 -1
- data/ext/libcouchbase/src/hostlist.h +6 -1
- data/ext/libcouchbase/src/http/http-priv.h +125 -112
- data/ext/libcouchbase/src/http/http.cc +9 -29
- data/ext/libcouchbase/src/http/http.h +1 -34
- data/ext/libcouchbase/src/http/http_io.cc +22 -26
- data/ext/libcouchbase/src/instance.cc +102 -28
- data/ext/libcouchbase/src/internal.h +47 -29
- data/ext/libcouchbase/src/jsparse/parser.cc +146 -202
- data/ext/libcouchbase/src/jsparse/parser.h +91 -98
- data/ext/libcouchbase/src/lcbht/lcbht.cc +177 -0
- data/ext/libcouchbase/src/lcbht/lcbht.h +174 -163
- data/ext/libcouchbase/src/lcbio/connect.cc +562 -0
- data/ext/libcouchbase/src/lcbio/connect.h +9 -2
- data/ext/libcouchbase/src/lcbio/ctx.c +1 -1
- data/ext/libcouchbase/src/lcbio/iotable.h +61 -16
- data/ext/libcouchbase/src/lcbio/ioutils.h +1 -1
- data/ext/libcouchbase/src/lcbio/manager.c +2 -2
- data/ext/libcouchbase/src/lcbio/timer-cxx.h +87 -0
- data/ext/libcouchbase/src/mc/mcreq.h +9 -2
- data/ext/libcouchbase/src/mcserver/mcserver.cc +723 -0
- data/ext/libcouchbase/src/mcserver/mcserver.h +160 -70
- data/ext/libcouchbase/src/mcserver/negotiate.cc +118 -152
- data/ext/libcouchbase/src/mcserver/negotiate.h +85 -74
- data/ext/libcouchbase/src/mctx-helper.h +51 -0
- data/ext/libcouchbase/src/n1ql/ixmgmt.cc +1 -2
- data/ext/libcouchbase/src/n1ql/n1ql.cc +56 -32
- data/ext/libcouchbase/src/{newconfig.c → newconfig.cc} +42 -70
- data/ext/libcouchbase/src/nodeinfo.cc +4 -8
- data/ext/libcouchbase/src/operations/{cbflush.c → cbflush.cc} +7 -15
- data/ext/libcouchbase/src/operations/{counter.c → counter.cc} +0 -0
- data/ext/libcouchbase/src/operations/{durability-cas.c → durability-cas.cc} +92 -76
- data/ext/libcouchbase/src/operations/{durability-seqno.c → durability-seqno.cc} +55 -49
- data/ext/libcouchbase/src/operations/durability.cc +643 -0
- data/ext/libcouchbase/src/operations/durability_internal.h +212 -124
- data/ext/libcouchbase/src/operations/{get.c → get.cc} +24 -26
- data/ext/libcouchbase/src/operations/{observe-seqno.c → observe-seqno.cc} +5 -8
- data/ext/libcouchbase/src/operations/{observe.c → observe.cc} +69 -94
- data/ext/libcouchbase/src/operations/{pktfwd.c → pktfwd.cc} +0 -0
- data/ext/libcouchbase/src/operations/{remove.c → remove.cc} +0 -0
- data/ext/libcouchbase/src/operations/{stats.c → stats.cc} +66 -78
- data/ext/libcouchbase/src/operations/{store.c → store.cc} +27 -32
- data/ext/libcouchbase/src/operations/subdoc.cc +38 -18
- data/ext/libcouchbase/src/operations/{touch.c → touch.cc} +0 -0
- data/ext/libcouchbase/src/packetutils.h +200 -137
- data/ext/libcouchbase/src/probes.d +1 -1
- data/ext/libcouchbase/src/{retrychk.c → retrychk.cc} +3 -4
- data/ext/libcouchbase/src/retryq.cc +394 -0
- data/ext/libcouchbase/src/retryq.h +116 -104
- data/ext/libcouchbase/src/settings.h +2 -1
- data/ext/libcouchbase/src/ssl/ssl_c.c +1 -0
- data/ext/libcouchbase/src/ssl/ssl_e.c +0 -1
- data/ext/libcouchbase/src/trace.h +8 -8
- data/ext/libcouchbase/src/vbucket/vbucket.c +0 -1
- data/ext/libcouchbase/src/views/{docreq.c → docreq.cc} +48 -54
- data/ext/libcouchbase/src/views/docreq.h +24 -30
- data/ext/libcouchbase/src/views/viewreq.cc +318 -0
- data/ext/libcouchbase/src/views/viewreq.h +43 -13
- data/ext/libcouchbase/src/{wait.c → wait.cc} +12 -17
- data/ext/libcouchbase/tests/basic/t_connstr.cc +89 -50
- data/ext/libcouchbase/tests/basic/t_jsparse.cc +27 -78
- data/ext/libcouchbase/tests/basic/t_packet.cc +35 -42
- data/ext/libcouchbase/tests/htparse/t_basic.cc +58 -78
- data/ext/libcouchbase/tests/iotests/t_confmon.cc +94 -111
- data/ext/libcouchbase/tests/iotests/t_sched.cc +1 -2
- data/ext/libcouchbase/tests/mc/t_alloc.cc +9 -9
- data/ext/libcouchbase/tools/cbc-pillowfight.cc +1 -1
- data/lib/libcouchbase/version.rb +1 -1
- metadata +36 -39
- data/ext/libcouchbase/include/memcached/vbucket.h +0 -42
- data/ext/libcouchbase/src/bootstrap.c +0 -269
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.c +0 -495
- data/ext/libcouchbase/src/bucketconfig/bc_file.c +0 -347
- data/ext/libcouchbase/src/bucketconfig/bc_http.c +0 -630
- data/ext/libcouchbase/src/bucketconfig/bc_mcraw.c +0 -150
- data/ext/libcouchbase/src/bucketconfig/confmon.c +0 -474
- data/ext/libcouchbase/src/getconfig.c +0 -100
- data/ext/libcouchbase/src/lcbht/lcbht.c +0 -282
- data/ext/libcouchbase/src/lcbio/connect.c +0 -557
- data/ext/libcouchbase/src/mcserver/mcserver.c +0 -784
- data/ext/libcouchbase/src/operations/durability.c +0 -668
- data/ext/libcouchbase/src/packetutils.c +0 -60
- data/ext/libcouchbase/src/retryq.c +0 -424
- data/ext/libcouchbase/src/simplestring.c +0 -211
- data/ext/libcouchbase/src/simplestring.h +0 -228
- data/ext/libcouchbase/src/ssobuf.h +0 -82
- data/ext/libcouchbase/src/views/viewreq.c +0 -358
- data/ext/libcouchbase/tests/basic/t_string.cc +0 -112
|
@@ -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
|
|
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
|
-
#
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
|
|
113
|
+
enum BootstrapOptions {
|
|
87
114
|
/** Always fetch a new configuration. No throttling checks are performed */
|
|
88
|
-
|
|
115
|
+
BS_REFRESH_ALWAYS = 0x00,
|
|
89
116
|
/** Special mode used to fetch the first configuration */
|
|
90
|
-
|
|
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
|
-
|
|
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
|
-
|
|
104
|
-
}
|
|
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
|
-
|
|
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
|
+
}
|