libcouchbase 0.3.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/libcouchbase/CMakeLists.txt +6 -8
- data/ext/libcouchbase/README.markdown +2 -2
- data/ext/libcouchbase/RELEASE_NOTES.markdown +229 -2
- data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +11 -0
- data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +18 -0
- data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +3 -2
- data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
- data/ext/libcouchbase/cmake/config-cmake.h.in +4 -0
- data/ext/libcouchbase/cmake/defs.mk.in +0 -2
- data/ext/libcouchbase/cmake/source_files.cmake +21 -5
- data/ext/libcouchbase/contrib/cJSON/cJSON.c +1 -1
- data/ext/libcouchbase/contrib/cbsasl/src/client.c +2 -0
- data/ext/libcouchbase/example/users/README +48 -0
- data/ext/libcouchbase/example/users/users.c +147 -0
- data/ext/libcouchbase/include/libcouchbase/auth.h +175 -31
- data/ext/libcouchbase/include/libcouchbase/cntl.h +82 -1
- data/ext/libcouchbase/include/libcouchbase/couchbase.h +45 -3
- data/ext/libcouchbase/include/libcouchbase/error.h +19 -1
- data/ext/libcouchbase/include/libcouchbase/iops.h +3 -0
- data/ext/libcouchbase/include/libcouchbase/n1ql.h +31 -1
- data/ext/libcouchbase/include/libcouchbase/plugins/io/bsdio-inl.c +4 -1
- data/ext/libcouchbase/include/libcouchbase/subdoc.h +36 -2
- 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 +24 -1146
- 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 +23 -4
- data/ext/libcouchbase/src/auth.cc +51 -43
- data/ext/libcouchbase/src/bootstrap.cc +244 -0
- data/ext/libcouchbase/src/bootstrap.h +58 -38
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +120 -158
- data/ext/libcouchbase/src/bucketconfig/bc_file.cc +281 -0
- data/ext/libcouchbase/src/bucketconfig/bc_http.cc +526 -0
- data/ext/libcouchbase/src/bucketconfig/bc_http.h +50 -25
- data/ext/libcouchbase/src/bucketconfig/bc_static.cc +150 -0
- data/ext/libcouchbase/src/bucketconfig/clconfig.h +410 -386
- data/ext/libcouchbase/src/bucketconfig/confmon.cc +393 -0
- data/ext/libcouchbase/src/cbft.cc +22 -27
- data/ext/libcouchbase/src/cntl.cc +56 -22
- data/ext/libcouchbase/src/connspec.cc +47 -6
- data/ext/libcouchbase/src/connspec.h +27 -0
- data/ext/libcouchbase/src/dns-srv.cc +147 -0
- data/ext/libcouchbase/src/dump.cc +3 -3
- data/ext/libcouchbase/src/errmap.cc +173 -0
- data/ext/libcouchbase/src/errmap.h +198 -0
- data/ext/libcouchbase/src/getconfig.cc +7 -33
- data/ext/libcouchbase/src/handler.cc +118 -7
- data/ext/libcouchbase/src/hostlist.cc +0 -36
- data/ext/libcouchbase/src/hostlist.h +44 -62
- data/ext/libcouchbase/src/http/http-priv.h +125 -112
- data/ext/libcouchbase/src/http/http.cc +27 -35
- data/ext/libcouchbase/src/http/http.h +1 -34
- data/ext/libcouchbase/src/http/http_io.cc +28 -36
- data/ext/libcouchbase/src/instance.cc +131 -34
- data/ext/libcouchbase/src/internal.h +58 -26
- data/ext/libcouchbase/src/jsparse/parser.cc +136 -210
- data/ext/libcouchbase/src/jsparse/parser.h +84 -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 +569 -0
- data/ext/libcouchbase/src/lcbio/connect.h +16 -7
- data/ext/libcouchbase/src/lcbio/ctx.c +1 -1
- data/ext/libcouchbase/src/lcbio/iotable.h +101 -16
- data/ext/libcouchbase/src/lcbio/{ioutils.c → ioutils.cc} +30 -51
- data/ext/libcouchbase/src/lcbio/ioutils.h +29 -90
- data/ext/libcouchbase/src/lcbio/manager.cc +543 -0
- data/ext/libcouchbase/src/lcbio/manager.h +133 -96
- data/ext/libcouchbase/src/lcbio/protoctx.c +2 -2
- data/ext/libcouchbase/src/lcbio/timer-cxx.h +87 -0
- data/ext/libcouchbase/src/mc/mcreq.c +11 -2
- data/ext/libcouchbase/src/mc/mcreq.h +9 -2
- data/ext/libcouchbase/src/mcserver/mcserver.cc +175 -43
- data/ext/libcouchbase/src/mcserver/mcserver.h +9 -13
- data/ext/libcouchbase/src/mcserver/negotiate.cc +181 -62
- data/ext/libcouchbase/src/mcserver/negotiate.h +1 -3
- 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 +74 -42
- data/ext/libcouchbase/src/netbuf/netbuf.c +4 -4
- data/ext/libcouchbase/src/newconfig.cc +6 -6
- data/ext/libcouchbase/src/nodeinfo.cc +2 -2
- 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.cc +6 -26
- data/ext/libcouchbase/src/operations/durability_internal.h +6 -3
- data/ext/libcouchbase/src/operations/{get.c → get.cc} +24 -26
- data/ext/libcouchbase/src/operations/{observe.c → observe.cc} +68 -93
- 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.cc +3 -8
- data/ext/libcouchbase/src/operations/{store.c → store.cc} +27 -32
- data/ext/libcouchbase/src/operations/subdoc.cc +129 -42
- data/ext/libcouchbase/src/operations/{touch.c → touch.cc} +0 -0
- data/ext/libcouchbase/src/packetutils.h +30 -2
- data/ext/libcouchbase/src/probes.d +1 -1
- data/ext/libcouchbase/src/rdb/rope.c +1 -1
- data/ext/libcouchbase/src/{retrychk.c → retrychk.cc} +2 -3
- data/ext/libcouchbase/src/retryq.cc +52 -14
- data/ext/libcouchbase/src/retryq.h +3 -3
- data/ext/libcouchbase/src/settings.c +5 -0
- data/ext/libcouchbase/src/settings.h +11 -0
- data/ext/libcouchbase/src/ssl/ssl_c.c +1 -0
- data/ext/libcouchbase/src/ssl/ssl_common.c +2 -0
- data/ext/libcouchbase/src/ssl/ssl_e.c +0 -1
- data/ext/libcouchbase/src/strcodecs/strcodecs.h +1 -1
- data/ext/libcouchbase/src/trace.h +4 -4
- data/ext/libcouchbase/src/vbucket/vbucket.c +6 -10
- 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/tests/basic/t_connstr.cc +88 -50
- data/ext/libcouchbase/tests/basic/t_creds.cc +47 -5
- data/ext/libcouchbase/tests/basic/t_host.cc +67 -75
- data/ext/libcouchbase/tests/basic/t_jsparse.cc +27 -82
- data/ext/libcouchbase/tests/basic/t_misc.cc +1 -1
- data/ext/libcouchbase/tests/basic/t_n1qlstrings.cc +0 -1
- data/ext/libcouchbase/tests/htparse/t_basic.cc +58 -78
- data/ext/libcouchbase/tests/ioserver/connection.cc +1 -1
- data/ext/libcouchbase/tests/ioserver/ioserver.cc +19 -6
- data/ext/libcouchbase/tests/iotests/mock-environment.cc +28 -2
- data/ext/libcouchbase/tests/iotests/mock-environment.h +51 -1
- data/ext/libcouchbase/tests/iotests/t_behavior.cc +1 -7
- data/ext/libcouchbase/tests/iotests/t_confmon.cc +97 -115
- data/ext/libcouchbase/tests/iotests/t_durability.cc +0 -1
- data/ext/libcouchbase/tests/iotests/t_eerrs.cc +119 -0
- data/ext/libcouchbase/tests/iotests/t_errmap.cc +178 -0
- data/ext/libcouchbase/tests/iotests/t_misc.cc +3 -3
- data/ext/libcouchbase/tests/iotests/t_netfail.cc +1 -1
- data/ext/libcouchbase/tests/iotests/t_obseqno.cc +0 -1
- data/ext/libcouchbase/tests/iotests/t_subdoc.cc +18 -11
- data/ext/libcouchbase/tests/mc/t_alloc.cc +9 -9
- data/ext/libcouchbase/tests/socktests/socktest.cc +7 -10
- data/ext/libcouchbase/tests/socktests/socktest.h +2 -3
- data/ext/libcouchbase/tests/socktests/t_basic.cc +6 -6
- data/ext/libcouchbase/tests/socktests/t_manager.cc +5 -6
- data/ext/libcouchbase/tests/socktests/t_ssl.cc +1 -1
- data/ext/libcouchbase/tests/vbucket/confdata/ketama_expected.json +2562 -0
- data/ext/libcouchbase/tests/vbucket/confdata/memd_ketama_config.json +31 -0
- data/ext/libcouchbase/tests/vbucket/t_config.cc +35 -5
- data/ext/libcouchbase/tools/CMakeLists.txt +2 -2
- data/ext/libcouchbase/tools/cbc-handlers.h +128 -0
- data/ext/libcouchbase/tools/cbc-n1qlback.cc +64 -10
- data/ext/libcouchbase/tools/cbc-pillowfight.cc +2 -2
- data/ext/libcouchbase/tools/cbc.cc +143 -10
- data/ext/libcouchbase/tools/docgen/loc.h +1 -1
- data/lib/libcouchbase/connection.rb +4 -3
- data/lib/libcouchbase/version.rb +1 -1
- metadata +37 -28
- data/ext/libcouchbase/include/memcached/vbucket.h +0 -42
- data/ext/libcouchbase/src/bootstrap.c +0 -269
- 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/lcbht/lcbht.c +0 -282
- data/ext/libcouchbase/src/lcbio/connect.c +0 -557
- data/ext/libcouchbase/src/lcbio/manager.c +0 -584
- data/ext/libcouchbase/src/packetutils.c +0 -37
- 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
|
@@ -0,0 +1,543 @@
|
|
|
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
|
+
#include "manager.h"
|
|
19
|
+
#include "hostlist.h"
|
|
20
|
+
#include "iotable.h"
|
|
21
|
+
#include "timer-ng.h"
|
|
22
|
+
#include "internal.h"
|
|
23
|
+
|
|
24
|
+
#define LOGARGS(mgr, lvl) mgr->settings, "lcbio_mgr", LCB_LOG_##lvl, __FILE__, __LINE__
|
|
25
|
+
|
|
26
|
+
using namespace lcb::io;
|
|
27
|
+
|
|
28
|
+
namespace lcb {
|
|
29
|
+
namespace io {
|
|
30
|
+
|
|
31
|
+
struct PoolHost {
|
|
32
|
+
inline PoolHost(Pool*, const std::string&);
|
|
33
|
+
inline void connection_available();
|
|
34
|
+
inline void start_new_connection(uint32_t timeout);
|
|
35
|
+
|
|
36
|
+
void ref() {
|
|
37
|
+
refcount++;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void unref() {
|
|
41
|
+
if (!--refcount) {
|
|
42
|
+
delete this;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
~PoolHost() {
|
|
47
|
+
if (parent) {
|
|
48
|
+
parent->unref();
|
|
49
|
+
parent = NULL;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
inline void dump(FILE *fp) const;
|
|
54
|
+
|
|
55
|
+
size_t num_pending() const {
|
|
56
|
+
return LCB_CLIST_SIZE(&ll_pending);
|
|
57
|
+
}
|
|
58
|
+
size_t num_idle() const {
|
|
59
|
+
return LCB_CLIST_SIZE(&ll_idle);
|
|
60
|
+
}
|
|
61
|
+
size_t num_requests() const {
|
|
62
|
+
return LCB_CLIST_SIZE(&requests);
|
|
63
|
+
}
|
|
64
|
+
size_t num_leased() const {
|
|
65
|
+
return n_total - (num_idle() + num_pending());
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
lcb_clist_t ll_idle; /* idle connections */
|
|
69
|
+
lcb_clist_t ll_pending; /* pending cinfo */
|
|
70
|
+
lcb_clist_t requests; /* pending requests */
|
|
71
|
+
const std::string key; /* host:port */
|
|
72
|
+
Pool *parent;
|
|
73
|
+
lcb::io::Timer<PoolHost, &PoolHost::connection_available> async;
|
|
74
|
+
unsigned n_total; /* number of total connections */
|
|
75
|
+
unsigned refcount;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
struct CinfoNode : lcb_list_t {};
|
|
81
|
+
|
|
82
|
+
namespace lcb {
|
|
83
|
+
namespace io {
|
|
84
|
+
struct PoolConnInfo : lcbio_PROTOCTX, CinfoNode {
|
|
85
|
+
inline PoolConnInfo(PoolHost *parent, uint32_t timeout);
|
|
86
|
+
inline ~PoolConnInfo();
|
|
87
|
+
inline void on_idle_timeout();
|
|
88
|
+
inline void on_connected(lcbio_SOCKET *sock, lcb_error_t err);
|
|
89
|
+
|
|
90
|
+
void set_leased() {
|
|
91
|
+
lcb_assert(state == IDLE);
|
|
92
|
+
state = LEASED;
|
|
93
|
+
idle_timer.cancel();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static PoolConnInfo *from_llnode(lcb_list_t *node) {
|
|
97
|
+
return static_cast<PoolConnInfo*>(static_cast<CinfoNode*>(node));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static PoolConnInfo *from_sock(lcbio_SOCKET *sock) {
|
|
101
|
+
lcbio_PROTOCTX *ctx = lcbio_protoctx_get(sock, LCBIO_PROTOCTX_POOL);
|
|
102
|
+
return static_cast<PoolConnInfo*>(ctx);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
PoolHost *parent;
|
|
106
|
+
lcbio_SOCKET *sock;
|
|
107
|
+
lcbio_pCONNSTART cs;
|
|
108
|
+
lcb::io::Timer<PoolConnInfo, &PoolConnInfo::on_idle_timeout> idle_timer;
|
|
109
|
+
|
|
110
|
+
enum State { PENDING, IDLE, LEASED };
|
|
111
|
+
State state;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
struct ReqNode : lcb_list_t {};
|
|
117
|
+
namespace lcb {
|
|
118
|
+
namespace io {
|
|
119
|
+
struct PoolRequest : ReqNode, ConnectionRequest {
|
|
120
|
+
PoolRequest(PoolHost *host_, lcbio_CONNDONE_cb cb, void *cbarg)
|
|
121
|
+
: host(host_), callback(cb), arg(cbarg), timer(host->parent->io, this),
|
|
122
|
+
state(PENDING), sock(NULL), err(LCB_SUCCESS) {
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
virtual ~PoolRequest() {}
|
|
126
|
+
virtual void cancel();
|
|
127
|
+
inline void invoke();
|
|
128
|
+
void invoke(lcb_error_t err_) {
|
|
129
|
+
err = err_;
|
|
130
|
+
invoke();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
inline void timer_handler();
|
|
134
|
+
inline void set_ready(PoolConnInfo *cinfo) {
|
|
135
|
+
cinfo->set_leased();
|
|
136
|
+
sock = cinfo->sock;
|
|
137
|
+
state = ASSIGNED;
|
|
138
|
+
timer.signal();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
inline void set_pending(uint32_t timeout) {
|
|
142
|
+
timer.rearm(timeout);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
static PoolRequest *from_llnode(lcb_list_t *node) {
|
|
146
|
+
return static_cast<PoolRequest*>(static_cast<ReqNode*>(node));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
PoolHost *host;
|
|
150
|
+
lcbio_CONNDONE_cb callback;
|
|
151
|
+
void *arg;
|
|
152
|
+
Timer<PoolRequest, &PoolRequest::timer_handler> timer;
|
|
153
|
+
|
|
154
|
+
enum State { ASSIGNED, PENDING };
|
|
155
|
+
State state;
|
|
156
|
+
lcbio_SOCKET *sock;
|
|
157
|
+
lcb_error_t err;
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
static const char *get_hehost(PoolHost *h) {
|
|
163
|
+
if (!h) { return "NOHOST:NOPORT"; }
|
|
164
|
+
return h->key.c_str();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Format string arguments for %p%s:%s */
|
|
168
|
+
#define HE_LOGID(h) get_hehost(h), (void*)h
|
|
169
|
+
#define HE_LOGFMT "<%s> (HE=%p) "
|
|
170
|
+
|
|
171
|
+
PoolConnInfo::~PoolConnInfo() {
|
|
172
|
+
parent->n_total--;
|
|
173
|
+
if (state == IDLE) {
|
|
174
|
+
lcb_clist_delete(&parent->ll_idle, this);
|
|
175
|
+
|
|
176
|
+
} else if (state == PENDING && cs) {
|
|
177
|
+
lcbio_connect_cancel(cs);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (sock) {
|
|
181
|
+
// Ensure destructor is not called!
|
|
182
|
+
dtor = NULL;
|
|
183
|
+
lcbio_protoctx_delptr(sock, this, 0);
|
|
184
|
+
lcbio_unref(sock);
|
|
185
|
+
}
|
|
186
|
+
parent->unref();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
static void
|
|
190
|
+
cinfo_protoctx_dtor(lcbio_PROTOCTX *ctx)
|
|
191
|
+
{
|
|
192
|
+
PoolConnInfo *info = reinterpret_cast<PoolConnInfo*>(ctx);
|
|
193
|
+
info->sock = NULL;
|
|
194
|
+
delete info;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
Pool::Pool(lcb_settings* settings_, lcbio_pTABLE io_)
|
|
198
|
+
: settings(settings_), io(io_), refcount(1) {
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
typedef std::vector<PoolHost*> HeList;
|
|
202
|
+
|
|
203
|
+
void Pool::ref() {
|
|
204
|
+
refcount++;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
void Pool::unref() {
|
|
208
|
+
if (!--refcount) {
|
|
209
|
+
delete this;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
void Pool::shutdown() {
|
|
214
|
+
HeList hes;
|
|
215
|
+
HostMap::iterator h_it;
|
|
216
|
+
|
|
217
|
+
for (h_it = ht.begin(); h_it != ht.end(); ++h_it) {
|
|
218
|
+
PoolHost *he = h_it->second;
|
|
219
|
+
|
|
220
|
+
lcb_list_t *cur, *next;
|
|
221
|
+
LCB_LIST_SAFE_FOR(cur, next, (lcb_list_t *)&he->ll_idle) {
|
|
222
|
+
delete PoolConnInfo::from_llnode(cur);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
LCB_LIST_SAFE_FOR(cur, next, (lcb_list_t *)&he->ll_pending) {
|
|
226
|
+
delete PoolConnInfo::from_llnode(cur);
|
|
227
|
+
}
|
|
228
|
+
hes.push_back(he);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
for (HeList::iterator it = hes.begin(); it != hes.end(); ++it) {
|
|
232
|
+
PoolHost *he = *it;
|
|
233
|
+
ht.erase(he->key);
|
|
234
|
+
he->async.release();
|
|
235
|
+
he->unref();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
unref();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
void
|
|
242
|
+
PoolRequest::invoke() {
|
|
243
|
+
if (sock) {
|
|
244
|
+
PoolConnInfo *info = PoolConnInfo::from_sock(sock);
|
|
245
|
+
info->set_leased();
|
|
246
|
+
state = ASSIGNED;
|
|
247
|
+
lcb_log(LOGARGS(info->parent->parent, DEBUG), HE_LOGFMT "Assigning R=%p SOCKET=%p",HE_LOGID(info->parent), (void*)this, (void*)sock);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
callback(sock, arg, err, 0);
|
|
251
|
+
if (sock) {
|
|
252
|
+
lcbio_unref(sock);
|
|
253
|
+
}
|
|
254
|
+
delete this;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Called to notify that a connection has become available.
|
|
259
|
+
*/
|
|
260
|
+
void
|
|
261
|
+
PoolHost::connection_available() {
|
|
262
|
+
while (LCB_CLIST_SIZE(&requests) && LCB_CLIST_SIZE(&ll_idle)) {
|
|
263
|
+
lcb_list_t *reqitem = lcb_clist_shift(&requests);
|
|
264
|
+
lcb_list_t *connitem = lcb_clist_pop(&ll_idle);
|
|
265
|
+
|
|
266
|
+
PoolRequest* req = PoolRequest::from_llnode(reqitem);
|
|
267
|
+
PoolConnInfo* info = PoolConnInfo::from_llnode(connitem);
|
|
268
|
+
req->sock = info->sock;
|
|
269
|
+
req->invoke();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Connection callback invoked from lcbio_connect() when a result is received
|
|
275
|
+
*/
|
|
276
|
+
static void
|
|
277
|
+
on_connected(lcbio_SOCKET *sock, void *arg, lcb_error_t err, lcbio_OSERR)
|
|
278
|
+
{
|
|
279
|
+
reinterpret_cast<PoolConnInfo*>(arg)->on_connected(sock, err);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
void PoolConnInfo::on_connected(lcbio_SOCKET *sock_, lcb_error_t err) {
|
|
284
|
+
lcb_assert(state == PENDING);
|
|
285
|
+
cs = NULL;
|
|
286
|
+
|
|
287
|
+
lcb_log(LOGARGS(parent->parent, DEBUG), HE_LOGFMT "Received result for I=%p,C=%p; E=0x%x", HE_LOGID(parent), (void*)this, (void*)sock, err);
|
|
288
|
+
lcb_clist_delete(&parent->ll_pending, this);
|
|
289
|
+
|
|
290
|
+
if (err != LCB_SUCCESS) {
|
|
291
|
+
/** If the connection failed, fail out all remaining requests */
|
|
292
|
+
lcb_list_t *cur, *next;
|
|
293
|
+
LCB_LIST_SAFE_FOR(cur, next, (lcb_list_t *)&parent->requests) {
|
|
294
|
+
PoolRequest *req = PoolRequest::from_llnode(cur);
|
|
295
|
+
lcb_clist_delete(&parent->requests, req);
|
|
296
|
+
req->sock = NULL;
|
|
297
|
+
req->invoke(err);
|
|
298
|
+
}
|
|
299
|
+
delete this;
|
|
300
|
+
|
|
301
|
+
} else {
|
|
302
|
+
state = IDLE;
|
|
303
|
+
sock = sock_;
|
|
304
|
+
lcbio_ref(sock);
|
|
305
|
+
lcbio_protoctx_add(sock, this);
|
|
306
|
+
|
|
307
|
+
lcb_clist_append(&parent->ll_idle, this);
|
|
308
|
+
idle_timer.rearm(parent->parent->options.maxidle);
|
|
309
|
+
parent->connection_available();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
PoolConnInfo::PoolConnInfo(PoolHost *he, uint32_t timeout)
|
|
314
|
+
: parent(he), sock(NULL), cs(NULL), idle_timer(he->parent->io, this),
|
|
315
|
+
state(PENDING) {
|
|
316
|
+
|
|
317
|
+
// protoctx fields
|
|
318
|
+
id = LCBIO_PROTOCTX_POOL;
|
|
319
|
+
dtor = cinfo_protoctx_dtor;
|
|
320
|
+
|
|
321
|
+
lcb_host_t tmphost;
|
|
322
|
+
lcb_error_t err = lcb_host_parsez(&tmphost, he->key.c_str(), 80);
|
|
323
|
+
if (err != LCB_SUCCESS) {
|
|
324
|
+
lcb_log(LOGARGS(he->parent, ERROR), HE_LOGFMT "Could not parse host! Will supply dummy host (I=%p)", HE_LOGID(he), (void*)this);
|
|
325
|
+
strcpy(tmphost.host, "BADHOST");
|
|
326
|
+
strcpy(tmphost.port, "BADPORT");
|
|
327
|
+
}
|
|
328
|
+
lcb_log(LOGARGS(he->parent, TRACE), HE_LOGFMT "New pool entry: I=%p", HE_LOGID(he), (void*)this);
|
|
329
|
+
|
|
330
|
+
cs = lcbio_connect(he->parent->io, he->parent->settings, &tmphost,
|
|
331
|
+
timeout, ::on_connected, this);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
void
|
|
335
|
+
PoolHost::start_new_connection(uint32_t tmo)
|
|
336
|
+
{
|
|
337
|
+
PoolConnInfo *info = new PoolConnInfo(this, tmo);
|
|
338
|
+
lcb_clist_append(&ll_pending, info);
|
|
339
|
+
n_total++;
|
|
340
|
+
refcount++;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
void PoolRequest::timer_handler() {
|
|
344
|
+
if (state == ASSIGNED) {
|
|
345
|
+
PoolConnInfo *cinfo = PoolConnInfo::from_sock(sock);
|
|
346
|
+
// Note - invoke() checks to make sure we've been passed an IDLE
|
|
347
|
+
// connection. We should probably add a dedicated state for this
|
|
348
|
+
// in a separate commit.
|
|
349
|
+
cinfo->state = PoolConnInfo::IDLE;
|
|
350
|
+
invoke();
|
|
351
|
+
} else {
|
|
352
|
+
lcb_clist_delete(&host->requests, this);
|
|
353
|
+
invoke(LCB_ETIMEDOUT);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
PoolHost::PoolHost(Pool *parent_, const std::string& key_)
|
|
358
|
+
: key(key_), parent(parent_), async(parent->io, this),
|
|
359
|
+
n_total(0), refcount(1) {
|
|
360
|
+
|
|
361
|
+
lcb_clist_init(&ll_idle);
|
|
362
|
+
lcb_clist_init(&ll_pending);
|
|
363
|
+
lcb_clist_init(&requests);
|
|
364
|
+
parent->ref();
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
ConnectionRequest*
|
|
368
|
+
Pool::get(const lcb_host_t& dest, uint32_t timeout, lcbio_CONNDONE_cb cb,
|
|
369
|
+
void *cbarg)
|
|
370
|
+
{
|
|
371
|
+
PoolHost *he;
|
|
372
|
+
lcb_list_t *cur;
|
|
373
|
+
|
|
374
|
+
std::string key(dest.host);
|
|
375
|
+
key.append(":").append(dest.port);
|
|
376
|
+
|
|
377
|
+
HostMap::iterator m = ht.find(key);
|
|
378
|
+
if (m == ht.end()) {
|
|
379
|
+
he = new PoolHost(this, key);
|
|
380
|
+
ht.insert(std::make_pair(key, he));
|
|
381
|
+
} else {
|
|
382
|
+
he = m->second;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
PoolRequest *req = new PoolRequest(he, cb, cbarg);
|
|
386
|
+
|
|
387
|
+
GT_POPAGAIN:
|
|
388
|
+
|
|
389
|
+
cur = lcb_clist_pop(&he->ll_idle);
|
|
390
|
+
if (cur) {
|
|
391
|
+
int clstatus;
|
|
392
|
+
PoolConnInfo *info = PoolConnInfo::from_llnode(cur);
|
|
393
|
+
|
|
394
|
+
clstatus = lcbio_is_netclosed(info->sock, LCB_IO_SOCKCHECK_PEND_IS_ERROR);
|
|
395
|
+
|
|
396
|
+
if (clstatus == LCB_IO_SOCKCHECK_STATUS_CLOSED) {
|
|
397
|
+
lcb_log(LOGARGS(this, WARN), HE_LOGFMT "Pooled socket is dead. Continuing to next one", HE_LOGID(he));
|
|
398
|
+
|
|
399
|
+
/* Set to LEASED, since it's not inside any of our lists */
|
|
400
|
+
info->state = PoolConnInfo::LEASED;
|
|
401
|
+
delete info;
|
|
402
|
+
goto GT_POPAGAIN;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
req->set_ready(info);
|
|
406
|
+
lcb_log(LOGARGS(this, INFO), HE_LOGFMT "Found ready connection in pool. Reusing socket and not creating new connection", HE_LOGID(he));
|
|
407
|
+
|
|
408
|
+
} else {
|
|
409
|
+
req->set_pending(timeout);
|
|
410
|
+
|
|
411
|
+
lcb_clist_append(&he->requests, req);
|
|
412
|
+
if (he->num_pending() < he->num_requests()) {
|
|
413
|
+
lcb_log(LOGARGS(this, DEBUG), HE_LOGFMT "Creating new connection because none are available in the pool", HE_LOGID(he));
|
|
414
|
+
he->start_new_connection(timeout);
|
|
415
|
+
|
|
416
|
+
} else {
|
|
417
|
+
lcb_log(LOGARGS(this, DEBUG), HE_LOGFMT "Not creating a new connection. There are still pending ones", HE_LOGID(he));
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return req;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
void PoolRequest::cancel() {
|
|
424
|
+
Pool *mgr = host->parent;
|
|
425
|
+
|
|
426
|
+
if (sock) {
|
|
427
|
+
lcb_log(LOGARGS(mgr, DEBUG), HE_LOGFMT "Cancelling request=%p with existing connection", HE_LOGID(host), (void*)this);
|
|
428
|
+
Pool::put(sock);
|
|
429
|
+
host->async.signal();
|
|
430
|
+
} else {
|
|
431
|
+
lcb_log(LOGARGS(mgr, DEBUG), HE_LOGFMT "Request=%p has no connection.. yet", HE_LOGID(host), (void*)this);
|
|
432
|
+
lcb_clist_delete(&host->requests, this);
|
|
433
|
+
}
|
|
434
|
+
delete this;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
void PoolConnInfo::on_idle_timeout() {
|
|
438
|
+
lcb_log(LOGARGS(parent->parent, DEBUG), HE_LOGFMT "Idle connection expired", HE_LOGID(parent));
|
|
439
|
+
lcbio_unref(sock);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
void Pool::put(lcbio_SOCKET *sock)
|
|
443
|
+
{
|
|
444
|
+
PoolHost *he;
|
|
445
|
+
Pool *mgr;
|
|
446
|
+
PoolConnInfo *info = PoolConnInfo::from_sock(sock);
|
|
447
|
+
|
|
448
|
+
if (!info) {
|
|
449
|
+
fprintf(stderr, "Requested put() for non-pooled (or detached) socket=%p\n", (void *)sock);
|
|
450
|
+
lcbio_unref(sock);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
he = info->parent;
|
|
455
|
+
mgr = he->parent;
|
|
456
|
+
|
|
457
|
+
if (he->num_idle() >= mgr->options.maxidle) {
|
|
458
|
+
lcb_log(LOGARGS(mgr, INFO), HE_LOGFMT "Closing idle connection. Too many in quota", HE_LOGID(he));
|
|
459
|
+
lcbio_unref(info->sock);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
lcb_log(LOGARGS(mgr, INFO), HE_LOGFMT "Placing socket back into the pool. I=%p,C=%p", HE_LOGID(he), (void*)info, (void*)sock);
|
|
464
|
+
info->idle_timer.rearm(mgr->options.tmoidle);
|
|
465
|
+
lcb_clist_append(&he->ll_idle, info);
|
|
466
|
+
info->state = PoolConnInfo::IDLE;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
void Pool::discard(lcbio_SOCKET *sock) {
|
|
470
|
+
lcbio_unref(sock);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
void Pool::detach(lcbio_SOCKET *sock) {
|
|
474
|
+
lcbio_protoctx_delid(sock, LCBIO_PROTOCTX_POOL, 1);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
bool Pool::is_from_pool(const lcbio_SOCKET *sock) {
|
|
478
|
+
return lcbio_protoctx_get(sock, LCBIO_PROTOCTX_POOL) != NULL;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
#define CONN_INDENT " "
|
|
483
|
+
|
|
484
|
+
static void
|
|
485
|
+
write_he_list(const lcb_clist_t *ll, FILE *out)
|
|
486
|
+
{
|
|
487
|
+
lcb_list_t *llcur;
|
|
488
|
+
LCB_LIST_FOR(llcur, (lcb_list_t *)ll) {
|
|
489
|
+
PoolConnInfo *info = PoolConnInfo::from_llnode(llcur);
|
|
490
|
+
fprintf(out, "%sCONN [I=%p,C=%p ",
|
|
491
|
+
CONN_INDENT, (void *)info, (void *)&info->sock);
|
|
492
|
+
|
|
493
|
+
if (info->sock->io->model == LCB_IOMODEL_EVENT) {
|
|
494
|
+
fprintf(out, "SOCKFD=%d", (int)info->sock->u.fd);
|
|
495
|
+
} else {
|
|
496
|
+
fprintf(out, "SOCKDATA=%p", (void *)info->sock->u.sd);
|
|
497
|
+
}
|
|
498
|
+
fprintf(out, " STATE=0x%x", info->state);
|
|
499
|
+
fprintf(out, "]\n");
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
void
|
|
505
|
+
PoolHost::dump(FILE *out) const {
|
|
506
|
+
lcb_list_t *llcur;
|
|
507
|
+
fprintf(out, "HOST=%s", key.c_str());
|
|
508
|
+
fprintf(out, "Requests=%lu, Idle=%lu, Pending=%lu, Leased=%lu\n",
|
|
509
|
+
num_requests(), num_idle(), num_pending(), num_leased());
|
|
510
|
+
|
|
511
|
+
fprintf(out, CONN_INDENT "Idle Connections:\n");
|
|
512
|
+
write_he_list(&ll_idle, out);
|
|
513
|
+
fprintf(out, CONN_INDENT "Pending Connections: \n");
|
|
514
|
+
write_he_list(&ll_pending, out);
|
|
515
|
+
fprintf(out, CONN_INDENT "Pending Requests:\n");
|
|
516
|
+
|
|
517
|
+
LCB_LIST_FOR(llcur, (lcb_list_t *)&requests) {
|
|
518
|
+
PoolRequest *req = PoolRequest::from_llnode(llcur);
|
|
519
|
+
union {
|
|
520
|
+
lcbio_CONNDONE_cb cb;
|
|
521
|
+
void *ptr;
|
|
522
|
+
} u_cb;
|
|
523
|
+
|
|
524
|
+
u_cb.cb = req->callback;
|
|
525
|
+
|
|
526
|
+
fprintf(out, "%sREQ [R=%p, Callback=%p, Data=%p, State=0x%x]\n",
|
|
527
|
+
CONN_INDENT, (void *)req, u_cb.ptr, (void *)req->arg,
|
|
528
|
+
req->state);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
fprintf(out, "\n");
|
|
532
|
+
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
void Pool::dump(FILE *out) const {
|
|
536
|
+
if (out == NULL) {
|
|
537
|
+
out = stderr;
|
|
538
|
+
}
|
|
539
|
+
HostMap::const_iterator ii;
|
|
540
|
+
for (ii = ht.begin(); ii != ht.end(); ++ii) {
|
|
541
|
+
ii->second->dump(out);
|
|
542
|
+
}
|
|
543
|
+
}
|