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.
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
+ }