libcouchbase 0.3.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/ext/libcouchbase/CMakeLists.txt +6 -8
  3. data/ext/libcouchbase/README.markdown +2 -2
  4. data/ext/libcouchbase/RELEASE_NOTES.markdown +229 -2
  5. data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +11 -0
  6. data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +18 -0
  7. data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +3 -2
  8. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
  9. data/ext/libcouchbase/cmake/config-cmake.h.in +4 -0
  10. data/ext/libcouchbase/cmake/defs.mk.in +0 -2
  11. data/ext/libcouchbase/cmake/source_files.cmake +21 -5
  12. data/ext/libcouchbase/contrib/cJSON/cJSON.c +1 -1
  13. data/ext/libcouchbase/contrib/cbsasl/src/client.c +2 -0
  14. data/ext/libcouchbase/example/users/README +48 -0
  15. data/ext/libcouchbase/example/users/users.c +147 -0
  16. data/ext/libcouchbase/include/libcouchbase/auth.h +175 -31
  17. data/ext/libcouchbase/include/libcouchbase/cntl.h +82 -1
  18. data/ext/libcouchbase/include/libcouchbase/couchbase.h +45 -3
  19. data/ext/libcouchbase/include/libcouchbase/error.h +19 -1
  20. data/ext/libcouchbase/include/libcouchbase/iops.h +3 -0
  21. data/ext/libcouchbase/include/libcouchbase/n1ql.h +31 -1
  22. data/ext/libcouchbase/include/libcouchbase/plugins/io/bsdio-inl.c +4 -1
  23. data/ext/libcouchbase/include/libcouchbase/subdoc.h +36 -2
  24. data/ext/libcouchbase/include/libcouchbase/views.h +7 -1
  25. data/ext/libcouchbase/include/libcouchbase/visibility.h +1 -0
  26. data/ext/libcouchbase/include/memcached/protocol_binary.h +24 -1146
  27. data/ext/libcouchbase/packaging/parse-git-describe.pl +1 -1
  28. data/ext/libcouchbase/plugins/io/libev/libev_io_opts.h +3 -2
  29. data/ext/libcouchbase/src/README.md +0 -2
  30. data/ext/libcouchbase/src/auth-priv.h +23 -4
  31. data/ext/libcouchbase/src/auth.cc +51 -43
  32. data/ext/libcouchbase/src/bootstrap.cc +244 -0
  33. data/ext/libcouchbase/src/bootstrap.h +58 -38
  34. data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +120 -158
  35. data/ext/libcouchbase/src/bucketconfig/bc_file.cc +281 -0
  36. data/ext/libcouchbase/src/bucketconfig/bc_http.cc +526 -0
  37. data/ext/libcouchbase/src/bucketconfig/bc_http.h +50 -25
  38. data/ext/libcouchbase/src/bucketconfig/bc_static.cc +150 -0
  39. data/ext/libcouchbase/src/bucketconfig/clconfig.h +410 -386
  40. data/ext/libcouchbase/src/bucketconfig/confmon.cc +393 -0
  41. data/ext/libcouchbase/src/cbft.cc +22 -27
  42. data/ext/libcouchbase/src/cntl.cc +56 -22
  43. data/ext/libcouchbase/src/connspec.cc +47 -6
  44. data/ext/libcouchbase/src/connspec.h +27 -0
  45. data/ext/libcouchbase/src/dns-srv.cc +147 -0
  46. data/ext/libcouchbase/src/dump.cc +3 -3
  47. data/ext/libcouchbase/src/errmap.cc +173 -0
  48. data/ext/libcouchbase/src/errmap.h +198 -0
  49. data/ext/libcouchbase/src/getconfig.cc +7 -33
  50. data/ext/libcouchbase/src/handler.cc +118 -7
  51. data/ext/libcouchbase/src/hostlist.cc +0 -36
  52. data/ext/libcouchbase/src/hostlist.h +44 -62
  53. data/ext/libcouchbase/src/http/http-priv.h +125 -112
  54. data/ext/libcouchbase/src/http/http.cc +27 -35
  55. data/ext/libcouchbase/src/http/http.h +1 -34
  56. data/ext/libcouchbase/src/http/http_io.cc +28 -36
  57. data/ext/libcouchbase/src/instance.cc +131 -34
  58. data/ext/libcouchbase/src/internal.h +58 -26
  59. data/ext/libcouchbase/src/jsparse/parser.cc +136 -210
  60. data/ext/libcouchbase/src/jsparse/parser.h +84 -98
  61. data/ext/libcouchbase/src/lcbht/lcbht.cc +177 -0
  62. data/ext/libcouchbase/src/lcbht/lcbht.h +174 -163
  63. data/ext/libcouchbase/src/lcbio/connect.cc +569 -0
  64. data/ext/libcouchbase/src/lcbio/connect.h +16 -7
  65. data/ext/libcouchbase/src/lcbio/ctx.c +1 -1
  66. data/ext/libcouchbase/src/lcbio/iotable.h +101 -16
  67. data/ext/libcouchbase/src/lcbio/{ioutils.c → ioutils.cc} +30 -51
  68. data/ext/libcouchbase/src/lcbio/ioutils.h +29 -90
  69. data/ext/libcouchbase/src/lcbio/manager.cc +543 -0
  70. data/ext/libcouchbase/src/lcbio/manager.h +133 -96
  71. data/ext/libcouchbase/src/lcbio/protoctx.c +2 -2
  72. data/ext/libcouchbase/src/lcbio/timer-cxx.h +87 -0
  73. data/ext/libcouchbase/src/mc/mcreq.c +11 -2
  74. data/ext/libcouchbase/src/mc/mcreq.h +9 -2
  75. data/ext/libcouchbase/src/mcserver/mcserver.cc +175 -43
  76. data/ext/libcouchbase/src/mcserver/mcserver.h +9 -13
  77. data/ext/libcouchbase/src/mcserver/negotiate.cc +181 -62
  78. data/ext/libcouchbase/src/mcserver/negotiate.h +1 -3
  79. data/ext/libcouchbase/src/mctx-helper.h +51 -0
  80. data/ext/libcouchbase/src/n1ql/ixmgmt.cc +1 -2
  81. data/ext/libcouchbase/src/n1ql/n1ql.cc +74 -42
  82. data/ext/libcouchbase/src/netbuf/netbuf.c +4 -4
  83. data/ext/libcouchbase/src/newconfig.cc +6 -6
  84. data/ext/libcouchbase/src/nodeinfo.cc +2 -2
  85. data/ext/libcouchbase/src/operations/{cbflush.c → cbflush.cc} +7 -15
  86. data/ext/libcouchbase/src/operations/{counter.c → counter.cc} +0 -0
  87. data/ext/libcouchbase/src/operations/durability.cc +6 -26
  88. data/ext/libcouchbase/src/operations/durability_internal.h +6 -3
  89. data/ext/libcouchbase/src/operations/{get.c → get.cc} +24 -26
  90. data/ext/libcouchbase/src/operations/{observe.c → observe.cc} +68 -93
  91. data/ext/libcouchbase/src/operations/{pktfwd.c → pktfwd.cc} +0 -0
  92. data/ext/libcouchbase/src/operations/{remove.c → remove.cc} +0 -0
  93. data/ext/libcouchbase/src/operations/stats.cc +3 -8
  94. data/ext/libcouchbase/src/operations/{store.c → store.cc} +27 -32
  95. data/ext/libcouchbase/src/operations/subdoc.cc +129 -42
  96. data/ext/libcouchbase/src/operations/{touch.c → touch.cc} +0 -0
  97. data/ext/libcouchbase/src/packetutils.h +30 -2
  98. data/ext/libcouchbase/src/probes.d +1 -1
  99. data/ext/libcouchbase/src/rdb/rope.c +1 -1
  100. data/ext/libcouchbase/src/{retrychk.c → retrychk.cc} +2 -3
  101. data/ext/libcouchbase/src/retryq.cc +52 -14
  102. data/ext/libcouchbase/src/retryq.h +3 -3
  103. data/ext/libcouchbase/src/settings.c +5 -0
  104. data/ext/libcouchbase/src/settings.h +11 -0
  105. data/ext/libcouchbase/src/ssl/ssl_c.c +1 -0
  106. data/ext/libcouchbase/src/ssl/ssl_common.c +2 -0
  107. data/ext/libcouchbase/src/ssl/ssl_e.c +0 -1
  108. data/ext/libcouchbase/src/strcodecs/strcodecs.h +1 -1
  109. data/ext/libcouchbase/src/trace.h +4 -4
  110. data/ext/libcouchbase/src/vbucket/vbucket.c +6 -10
  111. data/ext/libcouchbase/src/views/{docreq.c → docreq.cc} +48 -54
  112. data/ext/libcouchbase/src/views/docreq.h +24 -30
  113. data/ext/libcouchbase/src/views/viewreq.cc +318 -0
  114. data/ext/libcouchbase/src/views/viewreq.h +43 -13
  115. data/ext/libcouchbase/tests/basic/t_connstr.cc +88 -50
  116. data/ext/libcouchbase/tests/basic/t_creds.cc +47 -5
  117. data/ext/libcouchbase/tests/basic/t_host.cc +67 -75
  118. data/ext/libcouchbase/tests/basic/t_jsparse.cc +27 -82
  119. data/ext/libcouchbase/tests/basic/t_misc.cc +1 -1
  120. data/ext/libcouchbase/tests/basic/t_n1qlstrings.cc +0 -1
  121. data/ext/libcouchbase/tests/htparse/t_basic.cc +58 -78
  122. data/ext/libcouchbase/tests/ioserver/connection.cc +1 -1
  123. data/ext/libcouchbase/tests/ioserver/ioserver.cc +19 -6
  124. data/ext/libcouchbase/tests/iotests/mock-environment.cc +28 -2
  125. data/ext/libcouchbase/tests/iotests/mock-environment.h +51 -1
  126. data/ext/libcouchbase/tests/iotests/t_behavior.cc +1 -7
  127. data/ext/libcouchbase/tests/iotests/t_confmon.cc +97 -115
  128. data/ext/libcouchbase/tests/iotests/t_durability.cc +0 -1
  129. data/ext/libcouchbase/tests/iotests/t_eerrs.cc +119 -0
  130. data/ext/libcouchbase/tests/iotests/t_errmap.cc +178 -0
  131. data/ext/libcouchbase/tests/iotests/t_misc.cc +3 -3
  132. data/ext/libcouchbase/tests/iotests/t_netfail.cc +1 -1
  133. data/ext/libcouchbase/tests/iotests/t_obseqno.cc +0 -1
  134. data/ext/libcouchbase/tests/iotests/t_subdoc.cc +18 -11
  135. data/ext/libcouchbase/tests/mc/t_alloc.cc +9 -9
  136. data/ext/libcouchbase/tests/socktests/socktest.cc +7 -10
  137. data/ext/libcouchbase/tests/socktests/socktest.h +2 -3
  138. data/ext/libcouchbase/tests/socktests/t_basic.cc +6 -6
  139. data/ext/libcouchbase/tests/socktests/t_manager.cc +5 -6
  140. data/ext/libcouchbase/tests/socktests/t_ssl.cc +1 -1
  141. data/ext/libcouchbase/tests/vbucket/confdata/ketama_expected.json +2562 -0
  142. data/ext/libcouchbase/tests/vbucket/confdata/memd_ketama_config.json +31 -0
  143. data/ext/libcouchbase/tests/vbucket/t_config.cc +35 -5
  144. data/ext/libcouchbase/tools/CMakeLists.txt +2 -2
  145. data/ext/libcouchbase/tools/cbc-handlers.h +128 -0
  146. data/ext/libcouchbase/tools/cbc-n1qlback.cc +64 -10
  147. data/ext/libcouchbase/tools/cbc-pillowfight.cc +2 -2
  148. data/ext/libcouchbase/tools/cbc.cc +143 -10
  149. data/ext/libcouchbase/tools/docgen/loc.h +1 -1
  150. data/lib/libcouchbase/connection.rb +4 -3
  151. data/lib/libcouchbase/version.rb +1 -1
  152. metadata +37 -28
  153. data/ext/libcouchbase/include/memcached/vbucket.h +0 -42
  154. data/ext/libcouchbase/src/bootstrap.c +0 -269
  155. data/ext/libcouchbase/src/bucketconfig/bc_file.c +0 -347
  156. data/ext/libcouchbase/src/bucketconfig/bc_http.c +0 -630
  157. data/ext/libcouchbase/src/bucketconfig/bc_mcraw.c +0 -150
  158. data/ext/libcouchbase/src/bucketconfig/confmon.c +0 -474
  159. data/ext/libcouchbase/src/lcbht/lcbht.c +0 -282
  160. data/ext/libcouchbase/src/lcbio/connect.c +0 -557
  161. data/ext/libcouchbase/src/lcbio/manager.c +0 -584
  162. data/ext/libcouchbase/src/packetutils.c +0 -37
  163. data/ext/libcouchbase/src/simplestring.c +0 -211
  164. data/ext/libcouchbase/src/simplestring.h +0 -228
  165. data/ext/libcouchbase/src/ssobuf.h +0 -82
  166. data/ext/libcouchbase/src/views/viewreq.c +0 -358
  167. 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
+ }