libcouchbase 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/ext/libcouchbase/.gitignore +2 -0
  3. data/ext/libcouchbase/CMakeLists.txt +5 -7
  4. data/ext/libcouchbase/README.markdown +2 -2
  5. data/ext/libcouchbase/RELEASE_NOTES.markdown +49 -0
  6. data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +11 -0
  7. data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -0
  8. data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +2 -1
  9. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
  10. data/ext/libcouchbase/cmake/config-cmake.h.in +2 -0
  11. data/ext/libcouchbase/cmake/defs.mk.in +0 -2
  12. data/ext/libcouchbase/cmake/source_files.cmake +34 -14
  13. data/ext/libcouchbase/configure.pl +1 -1
  14. data/ext/libcouchbase/contrib/genhash/genhash.h +6 -0
  15. data/ext/libcouchbase/include/libcouchbase/auth.h +10 -0
  16. data/ext/libcouchbase/include/libcouchbase/couchbase.h +10 -0
  17. data/ext/libcouchbase/include/libcouchbase/error.h +7 -0
  18. data/ext/libcouchbase/include/libcouchbase/n1ql.h +13 -1
  19. data/ext/libcouchbase/include/libcouchbase/plugins/io/bsdio-inl.c +1 -1
  20. data/ext/libcouchbase/include/libcouchbase/subdoc.h +9 -0
  21. data/ext/libcouchbase/include/libcouchbase/views.h +7 -1
  22. data/ext/libcouchbase/include/libcouchbase/visibility.h +1 -0
  23. data/ext/libcouchbase/include/memcached/protocol_binary.h +21 -1132
  24. data/ext/libcouchbase/packaging/parse-git-describe.pl +1 -1
  25. data/ext/libcouchbase/plugins/io/libev/libev_io_opts.h +3 -2
  26. data/ext/libcouchbase/src/README.md +0 -2
  27. data/ext/libcouchbase/src/auth-priv.h +1 -0
  28. data/ext/libcouchbase/src/auth.cc +10 -0
  29. data/ext/libcouchbase/src/bootstrap.cc +216 -0
  30. data/ext/libcouchbase/src/bootstrap.h +50 -39
  31. data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +455 -0
  32. data/ext/libcouchbase/src/bucketconfig/bc_file.cc +281 -0
  33. data/ext/libcouchbase/src/bucketconfig/bc_http.cc +528 -0
  34. data/ext/libcouchbase/src/bucketconfig/bc_http.h +50 -25
  35. data/ext/libcouchbase/src/bucketconfig/bc_mcraw.cc +115 -0
  36. data/ext/libcouchbase/src/bucketconfig/clconfig.h +407 -386
  37. data/ext/libcouchbase/src/bucketconfig/confmon.cc +378 -0
  38. data/ext/libcouchbase/src/cbft.cc +22 -27
  39. data/ext/libcouchbase/src/cntl.cc +24 -24
  40. data/ext/libcouchbase/src/connspec.cc +30 -1
  41. data/ext/libcouchbase/src/connspec.h +17 -0
  42. data/ext/libcouchbase/src/dns-srv.cc +143 -0
  43. data/ext/libcouchbase/src/{dump.c → dump.cc} +8 -11
  44. data/ext/libcouchbase/src/getconfig.cc +73 -0
  45. data/ext/libcouchbase/src/handler.cc +84 -85
  46. data/ext/libcouchbase/src/hostlist.cc +0 -1
  47. data/ext/libcouchbase/src/hostlist.h +6 -1
  48. data/ext/libcouchbase/src/http/http-priv.h +125 -112
  49. data/ext/libcouchbase/src/http/http.cc +9 -29
  50. data/ext/libcouchbase/src/http/http.h +1 -34
  51. data/ext/libcouchbase/src/http/http_io.cc +22 -26
  52. data/ext/libcouchbase/src/instance.cc +102 -28
  53. data/ext/libcouchbase/src/internal.h +47 -29
  54. data/ext/libcouchbase/src/jsparse/parser.cc +146 -202
  55. data/ext/libcouchbase/src/jsparse/parser.h +91 -98
  56. data/ext/libcouchbase/src/lcbht/lcbht.cc +177 -0
  57. data/ext/libcouchbase/src/lcbht/lcbht.h +174 -163
  58. data/ext/libcouchbase/src/lcbio/connect.cc +562 -0
  59. data/ext/libcouchbase/src/lcbio/connect.h +9 -2
  60. data/ext/libcouchbase/src/lcbio/ctx.c +1 -1
  61. data/ext/libcouchbase/src/lcbio/iotable.h +61 -16
  62. data/ext/libcouchbase/src/lcbio/ioutils.h +1 -1
  63. data/ext/libcouchbase/src/lcbio/manager.c +2 -2
  64. data/ext/libcouchbase/src/lcbio/timer-cxx.h +87 -0
  65. data/ext/libcouchbase/src/mc/mcreq.h +9 -2
  66. data/ext/libcouchbase/src/mcserver/mcserver.cc +723 -0
  67. data/ext/libcouchbase/src/mcserver/mcserver.h +160 -70
  68. data/ext/libcouchbase/src/mcserver/negotiate.cc +118 -152
  69. data/ext/libcouchbase/src/mcserver/negotiate.h +85 -74
  70. data/ext/libcouchbase/src/mctx-helper.h +51 -0
  71. data/ext/libcouchbase/src/n1ql/ixmgmt.cc +1 -2
  72. data/ext/libcouchbase/src/n1ql/n1ql.cc +56 -32
  73. data/ext/libcouchbase/src/{newconfig.c → newconfig.cc} +42 -70
  74. data/ext/libcouchbase/src/nodeinfo.cc +4 -8
  75. data/ext/libcouchbase/src/operations/{cbflush.c → cbflush.cc} +7 -15
  76. data/ext/libcouchbase/src/operations/{counter.c → counter.cc} +0 -0
  77. data/ext/libcouchbase/src/operations/{durability-cas.c → durability-cas.cc} +92 -76
  78. data/ext/libcouchbase/src/operations/{durability-seqno.c → durability-seqno.cc} +55 -49
  79. data/ext/libcouchbase/src/operations/durability.cc +643 -0
  80. data/ext/libcouchbase/src/operations/durability_internal.h +212 -124
  81. data/ext/libcouchbase/src/operations/{get.c → get.cc} +24 -26
  82. data/ext/libcouchbase/src/operations/{observe-seqno.c → observe-seqno.cc} +5 -8
  83. data/ext/libcouchbase/src/operations/{observe.c → observe.cc} +69 -94
  84. data/ext/libcouchbase/src/operations/{pktfwd.c → pktfwd.cc} +0 -0
  85. data/ext/libcouchbase/src/operations/{remove.c → remove.cc} +0 -0
  86. data/ext/libcouchbase/src/operations/{stats.c → stats.cc} +66 -78
  87. data/ext/libcouchbase/src/operations/{store.c → store.cc} +27 -32
  88. data/ext/libcouchbase/src/operations/subdoc.cc +38 -18
  89. data/ext/libcouchbase/src/operations/{touch.c → touch.cc} +0 -0
  90. data/ext/libcouchbase/src/packetutils.h +200 -137
  91. data/ext/libcouchbase/src/probes.d +1 -1
  92. data/ext/libcouchbase/src/{retrychk.c → retrychk.cc} +3 -4
  93. data/ext/libcouchbase/src/retryq.cc +394 -0
  94. data/ext/libcouchbase/src/retryq.h +116 -104
  95. data/ext/libcouchbase/src/settings.h +2 -1
  96. data/ext/libcouchbase/src/ssl/ssl_c.c +1 -0
  97. data/ext/libcouchbase/src/ssl/ssl_e.c +0 -1
  98. data/ext/libcouchbase/src/trace.h +8 -8
  99. data/ext/libcouchbase/src/vbucket/vbucket.c +0 -1
  100. data/ext/libcouchbase/src/views/{docreq.c → docreq.cc} +48 -54
  101. data/ext/libcouchbase/src/views/docreq.h +24 -30
  102. data/ext/libcouchbase/src/views/viewreq.cc +318 -0
  103. data/ext/libcouchbase/src/views/viewreq.h +43 -13
  104. data/ext/libcouchbase/src/{wait.c → wait.cc} +12 -17
  105. data/ext/libcouchbase/tests/basic/t_connstr.cc +89 -50
  106. data/ext/libcouchbase/tests/basic/t_jsparse.cc +27 -78
  107. data/ext/libcouchbase/tests/basic/t_packet.cc +35 -42
  108. data/ext/libcouchbase/tests/htparse/t_basic.cc +58 -78
  109. data/ext/libcouchbase/tests/iotests/t_confmon.cc +94 -111
  110. data/ext/libcouchbase/tests/iotests/t_sched.cc +1 -2
  111. data/ext/libcouchbase/tests/mc/t_alloc.cc +9 -9
  112. data/ext/libcouchbase/tools/cbc-pillowfight.cc +1 -1
  113. data/lib/libcouchbase/version.rb +1 -1
  114. metadata +36 -39
  115. data/ext/libcouchbase/include/memcached/vbucket.h +0 -42
  116. data/ext/libcouchbase/src/bootstrap.c +0 -269
  117. data/ext/libcouchbase/src/bucketconfig/bc_cccp.c +0 -495
  118. data/ext/libcouchbase/src/bucketconfig/bc_file.c +0 -347
  119. data/ext/libcouchbase/src/bucketconfig/bc_http.c +0 -630
  120. data/ext/libcouchbase/src/bucketconfig/bc_mcraw.c +0 -150
  121. data/ext/libcouchbase/src/bucketconfig/confmon.c +0 -474
  122. data/ext/libcouchbase/src/getconfig.c +0 -100
  123. data/ext/libcouchbase/src/lcbht/lcbht.c +0 -282
  124. data/ext/libcouchbase/src/lcbio/connect.c +0 -557
  125. data/ext/libcouchbase/src/mcserver/mcserver.c +0 -784
  126. data/ext/libcouchbase/src/operations/durability.c +0 -668
  127. data/ext/libcouchbase/src/packetutils.c +0 -60
  128. data/ext/libcouchbase/src/retryq.c +0 -424
  129. data/ext/libcouchbase/src/simplestring.c +0 -211
  130. data/ext/libcouchbase/src/simplestring.h +0 -228
  131. data/ext/libcouchbase/src/ssobuf.h +0 -82
  132. data/ext/libcouchbase/src/views/viewreq.c +0 -358
  133. data/ext/libcouchbase/tests/basic/t_string.cc +0 -112
@@ -28,7 +28,7 @@ provider libcouchbase {
28
28
  uint16_t, /* return code (from libcouchbase) */
29
29
  const char*, /* key */
30
30
  size_t, /* nkey */
31
- const void*, /* bytes */
31
+ const char*, /* bytes */
32
32
  size_t, /* nbytes */
33
33
  uint32_t, /* flags */
34
34
  uint64_t, /* cas */
@@ -18,10 +18,10 @@
18
18
  #include "internal.h"
19
19
 
20
20
  int
21
- lcb_should_retry(lcb_settings *settings, mc_PACKET *pkt, lcb_error_t err)
21
+ lcb_should_retry(const lcb_settings *settings, const mc_PACKET *pkt, lcb_error_t err)
22
22
  {
23
- lcb_RETRYCMDOPTS policy;
24
- lcb_RETRYMODEOPTS mode;
23
+ unsigned policy;
24
+ unsigned mode;
25
25
  protocol_binary_request_header hdr;
26
26
 
27
27
  mcreq_read_hdr(pkt, &hdr);
@@ -70,7 +70,6 @@ lcb_should_retry(lcb_settings *settings, mc_PACKET *pkt, lcb_error_t err)
70
70
 
71
71
  /* get is a safe operation which may be retried */
72
72
  case PROTOCOL_BINARY_CMD_GET:
73
- case PROTOCOL_BINARY_CMD_GETKQ:
74
73
  case PROTOCOL_BINARY_CMD_SUBDOC_GET:
75
74
  case PROTOCOL_BINARY_CMD_SUBDOC_EXISTS:
76
75
  case PROTOCOL_BINARY_CMD_SUBDOC_MULTI_LOOKUP:
@@ -0,0 +1,394 @@
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 "packetutils.h"
19
+ #include "retryq.h"
20
+ #include "config.h"
21
+ #include "logging.h"
22
+ #include "internal.h"
23
+ #include "bucketconfig/clconfig.h"
24
+
25
+ #define LOGARGS(rq, lvl) (rq)->settings, "retryq", LCB_LOG_##lvl, __FILE__, __LINE__
26
+ #define RETRY_PKT_KEY "retry_queue"
27
+
28
+ using namespace lcb;
29
+ struct SchedNode : lcb_list_t {};
30
+ struct TmoNode : lcb_list_t {};
31
+
32
+ struct lcb::RetryOp : mc_EPKTDATUM, SchedNode, TmoNode {
33
+ /**Cache the actual start time of the command. Since the start time may
34
+ * change if read_ts_wait is enabled, and we don't want to end up looping
35
+ * on a command forever. */
36
+ hrtime_t start;
37
+ hrtime_t trytime; /**< Next retry time */
38
+ mc_PACKET *pkt;
39
+ lcb_error_t origerr;
40
+ RetryOp();
41
+ };
42
+
43
+ static RetryOp *from_schednode(lcb_list_t *ll) {
44
+ return static_cast<RetryOp*>(static_cast<SchedNode*>(ll));
45
+ }
46
+ static RetryOp *from_tmonode(lcb_list_t *ll) {
47
+ return static_cast<RetryOp*>(static_cast<TmoNode*>(ll));
48
+ }
49
+ template <typename T>
50
+ int list_cmp(const T& a, const T& b) {
51
+ if (a == b) {
52
+ return 0;
53
+ } else if (a > b) {
54
+ return 1;
55
+ } else {
56
+ return -1;
57
+ }
58
+ }
59
+
60
+ hrtime_t
61
+ RetryQueue::get_retry_interval() const {
62
+ return LCB_US2NS(settings->retry_interval);
63
+ }
64
+
65
+ /**
66
+ * Fuzz offset. When callback is received to schedule an operation, we may
67
+ * retry commands whose expiry is up to this many seconds in the future. This
68
+ * is to avoid excessive callbacks into the timer function
69
+ */
70
+ #define TIMEFUZZ_NS LCB_US2NS(LCB_MS2US(5))
71
+
72
+ void
73
+ RetryQueue::update_trytime(RetryOp *op, hrtime_t now)
74
+ {
75
+ /**
76
+ * Estimate the next retry timestamp. This is:
77
+ * Base interval + (Number of retries x Backoff factor)
78
+ */
79
+ if (!now) {
80
+ now = gethrtime();
81
+ }
82
+ op->trytime = now + (hrtime_t) (
83
+ (float)get_retry_interval() *
84
+ (float)op->pkt->retries *
85
+ (float)settings->retry_backoff);
86
+ }
87
+
88
+ /** Comparison routine for sorting by timeout */
89
+ static int cmpfn_tmo(lcb_list_t *ll_a, lcb_list_t *ll_b) {
90
+ return list_cmp(from_tmonode(ll_a)->start, from_tmonode(ll_b)->start);
91
+ }
92
+
93
+ static int cmpfn_retry(lcb_list_t *ll_a, lcb_list_t *ll_b) {
94
+ return list_cmp(from_schednode(ll_a)->trytime, from_schednode(ll_b)->trytime);
95
+ }
96
+
97
+ static void
98
+ assign_error(RetryOp *op, lcb_error_t err)
99
+ {
100
+ if (err == LCB_NOT_MY_VBUCKET) {
101
+ err = LCB_ETIMEDOUT; /* :( */
102
+ }
103
+
104
+ if (op->origerr == LCB_SUCCESS) {
105
+ op->origerr = err;
106
+ }
107
+
108
+ if (err == LCB_ETIMEDOUT) {
109
+ return; /* Ignore timeout errors */
110
+ }
111
+
112
+ if (LCB_EIFNET(op->origerr) && op->origerr != LCB_ETIMEDOUT &&
113
+ (err == LCB_NETWORK_ERROR || err == LCB_CONNECT_ERROR)) {
114
+ return;
115
+ }
116
+
117
+ op->origerr = err;
118
+ }
119
+
120
+ void
121
+ RetryQueue::erase(RetryOp *op)
122
+ {
123
+ lcb_list_delete(static_cast<SchedNode*>(op));
124
+ lcb_list_delete(static_cast<TmoNode*>(op));
125
+ }
126
+
127
+ void
128
+ RetryQueue::fail(RetryOp *op, lcb_error_t err)
129
+ {
130
+ protocol_binary_request_header hdr;
131
+
132
+ lcb::Server tmpsrv; /** Temporary pipeline */
133
+ tmpsrv.instance = get_instance();
134
+ tmpsrv.parent = cq;
135
+
136
+ mcreq_read_hdr(op->pkt, &hdr);
137
+ MemcachedResponse resp(protocol_binary_command(hdr.request.opcode),
138
+ hdr.request.opaque,
139
+ PROTOCOL_BINARY_RESPONSE_EINVAL);
140
+
141
+ assign_error(op, err);
142
+ lcb_log(LOGARGS(this, WARN), "Failing command (seq=%u) from retry queue with error code 0x%x", op->pkt->opaque, op->origerr);
143
+
144
+ mcreq_dispatch_response(&tmpsrv, op->pkt, &resp, op->origerr);
145
+ op->pkt->flags |= MCREQ_F_FLUSHED|MCREQ_F_INVOKED;
146
+ erase(op);
147
+ mcreq_packet_done(&tmpsrv, op->pkt);
148
+ lcb_maybe_breakout(get_instance());
149
+ }
150
+
151
+ void
152
+ RetryQueue::schedule(hrtime_t now)
153
+ {
154
+ if (empty()) {
155
+ lcbio_timer_disarm(timer);
156
+ return;
157
+ }
158
+
159
+ if (!now) {
160
+ now = gethrtime();
161
+ }
162
+
163
+ /** Figure out which is first */
164
+ RetryOp *first_tmo = from_tmonode(LCB_LIST_HEAD(&tmoops));
165
+ RetryOp *first_sched = from_schednode(LCB_LIST_HEAD(&schedops));
166
+
167
+ hrtime_t schednext = first_sched->trytime;
168
+ hrtime_t tmonext = first_tmo->start +LCB_US2NS(settings->operation_timeout);
169
+ hrtime_t selected = schednext > tmonext ? tmonext : schednext;
170
+
171
+ hrtime_t diff;
172
+ if (selected <= now) {
173
+ diff = 0;
174
+ } else {
175
+ diff = selected - now;
176
+ }
177
+
178
+ uint32_t us_interval = LCB_NS2US(diff);
179
+ lcb_log(LOGARGS(this, TRACE), "Next tick in %u ms", (unsigned)us_interval/1000);
180
+ lcbio_timer_rearm(timer, us_interval);
181
+ }
182
+
183
+ /**
184
+ * Flush the queue
185
+ * @param rq The queue to flush
186
+ * @param throttle Whether to throttle operations to be retried. If this is
187
+ * set to false then all operations will be attempted (assuming they have
188
+ * not timed out)
189
+ */
190
+ void
191
+ RetryQueue::flush(bool throttle)
192
+ {
193
+ hrtime_t now = gethrtime();
194
+ lcb_list_t *ll, *ll_next;
195
+ lcb_list_t resched_next;
196
+
197
+ /** Check timeouts first */
198
+ LCB_LIST_SAFE_FOR(ll, ll_next, &tmoops) {
199
+ RetryOp *op = from_tmonode(ll);
200
+ hrtime_t curtmo = op->start + LCB_US2NS(settings->operation_timeout);
201
+
202
+ if (curtmo <= now) {
203
+ fail(op, LCB_ETIMEDOUT);
204
+ } else {
205
+ break;
206
+ }
207
+ }
208
+
209
+ lcb_list_init(&resched_next);
210
+ LCB_LIST_SAFE_FOR(ll, ll_next, &schedops) {
211
+ protocol_binary_request_header hdr;
212
+ int vbid, srvix;
213
+ hrtime_t curnext;
214
+
215
+ RetryOp *op = from_schednode(ll);
216
+ curnext = op->trytime - TIMEFUZZ_NS;
217
+
218
+ if (curnext > now && throttle) {
219
+ break;
220
+ }
221
+
222
+ mcreq_read_hdr(op->pkt, &hdr);
223
+ vbid = ntohs(hdr.request.vbucket);
224
+ srvix = lcbvb_vbmaster(cq->config, vbid);
225
+
226
+ if (srvix < 0 || (unsigned)srvix >= cq->npipelines) {
227
+ /* No server found to map to */
228
+ assign_error(op, LCB_NO_MATCHING_SERVER);
229
+
230
+ /* Request a new configuration. If it's time to request a new
231
+ * configuration (i.e. the attempt has not been throttled) then
232
+ * keep the command in there until it has a chance to be scheduled.
233
+ */
234
+ get_instance()->bootstrap(lcb::BS_REFRESH_THROTTLE);
235
+ if (get_instance()->confmon->is_refreshing() ||
236
+ settings->retry[LCB_RETRY_ON_MISSINGNODE]) {
237
+
238
+ lcb_list_delete(static_cast<SchedNode*>(op));
239
+ lcb_list_delete(static_cast<TmoNode*>(op));
240
+ lcb_list_append(&resched_next, static_cast<SchedNode*>(op));
241
+ op->pkt->retries++;
242
+ update_trytime(op, now);
243
+ } else {
244
+ fail(op, LCB_NO_MATCHING_SERVER);
245
+ }
246
+ } else {
247
+ mc_PIPELINE *newpl = cq->pipelines[srvix];
248
+ mcreq_enqueue_packet(newpl, op->pkt);
249
+ newpl->flush_start(newpl);
250
+ erase(op);
251
+ }
252
+ }
253
+
254
+ LCB_LIST_SAFE_FOR(ll, ll_next, &resched_next) {
255
+ RetryOp *op = from_schednode(ll);
256
+ lcb_list_add_sorted(&schedops, static_cast<SchedNode*>(op), cmpfn_retry);
257
+ lcb_list_add_sorted(&tmoops, static_cast<TmoNode*>(op), cmpfn_tmo);
258
+ }
259
+
260
+ schedule(now);
261
+ }
262
+
263
+ static void rq_tick(void *arg) {
264
+ reinterpret_cast<RetryQueue*>(arg)->tick();
265
+ }
266
+
267
+ void RetryQueue::tick() {
268
+ flush(true);
269
+ }
270
+
271
+ void RetryQueue::signal() {
272
+ flush(false);
273
+ }
274
+
275
+ static void op_dtorfn(mc_EPKTDATUM *d) {
276
+ delete static_cast<RetryOp*>(d);
277
+ }
278
+
279
+ RetryOp::RetryOp()
280
+ : mc_EPKTDATUM(), start(0), trytime(0), pkt(NULL), origerr(LCB_SUCCESS) {
281
+ mc_EPKTDATUM::dtorfn = op_dtorfn;
282
+ mc_EPKTDATUM::key = RETRY_PKT_KEY;
283
+ }
284
+
285
+ void
286
+ RetryQueue::add(mc_EXPACKET *pkt, const lcb_error_t err, int options)
287
+ {
288
+ RetryOp *op;
289
+ mc_EPKTDATUM *d = mcreq_epkt_find(pkt, RETRY_PKT_KEY);
290
+ if (d) {
291
+ op = static_cast<RetryOp *>(d);
292
+ } else {
293
+ op = new RetryOp();
294
+ op->start = MCREQ_PKT_RDATA(&pkt->base)->start;
295
+ mcreq_epkt_insert(pkt, op);
296
+ }
297
+
298
+ op->pkt = &pkt->base;
299
+ pkt->base.retries++;
300
+ assign_error(op, err);
301
+ if (options & RETRY_SCHED_IMM) {
302
+ op->trytime = gethrtime(); /* now */
303
+ } else if (err == LCB_NOT_MY_VBUCKET) {
304
+ op->trytime = gethrtime() + LCB_US2NS(settings->retry_nmv_interval);
305
+ } else {
306
+ update_trytime(op);
307
+ }
308
+
309
+ lcb_list_add_sorted(&schedops, static_cast<SchedNode*>(op), cmpfn_retry);
310
+ lcb_list_add_sorted(&tmoops, static_cast<TmoNode*>(op), cmpfn_tmo);
311
+
312
+ lcb_log(LOGARGS(this, DEBUG), "Adding PKT=%p to retry queue. Try count=%u", (void*)pkt, pkt->base.retries);
313
+ schedule();
314
+ }
315
+
316
+ void
317
+ RetryQueue::nmvadd(mc_EXPACKET *detchpkt)
318
+ {
319
+ int flags = 0;
320
+ if (settings->nmv_retry_imm) {
321
+ flags = RETRY_SCHED_IMM;
322
+ }
323
+ add(detchpkt, LCB_NOT_MY_VBUCKET, flags);
324
+ }
325
+
326
+ static void
327
+ fallback_handler(mc_CMDQUEUE *cq, mc_PACKET *pkt)
328
+ {
329
+ lcb_t instance = reinterpret_cast<lcb_t>(cq->cqdata);
330
+ instance->retryq->add_fallback(pkt);
331
+ }
332
+
333
+ void RetryQueue::add_fallback(mc_PACKET *pkt) {
334
+ mc_PACKET *copy = mcreq_renew_packet(pkt);
335
+ add((mc_EXPACKET*)copy, LCB_NO_MATCHING_SERVER, RETRY_SCHED_IMM);
336
+ }
337
+
338
+ void
339
+ RetryQueue::reset_timeouts(lcb_U64 now)
340
+ {
341
+ lcb_list_t *ll;
342
+ LCB_LIST_FOR(ll, &schedops) {
343
+ RetryOp *op = from_schednode(ll);
344
+ op->start = now;
345
+ }
346
+ }
347
+
348
+
349
+ RetryQueue::RetryQueue(mc_CMDQUEUE *cq_, lcbio_pTABLE table, lcb_settings *settings_) {
350
+ settings = settings_;
351
+ cq = cq_;
352
+ timer = lcbio_timer_new(table, this, rq_tick);
353
+
354
+ lcb_settings_ref(settings);
355
+ lcb_list_init(&tmoops);
356
+ lcb_list_init(&schedops);
357
+ mcreq_set_fallback_handler(cq, fallback_handler);
358
+ }
359
+
360
+ RetryQueue::~RetryQueue() {
361
+ lcb_list_t *llcur, *llnext;
362
+
363
+ LCB_LIST_SAFE_FOR(llcur, llnext, &schedops) {
364
+ RetryOp *op = from_schednode(llcur);
365
+ fail(op, LCB_ERROR);
366
+ }
367
+
368
+ lcbio_timer_destroy(timer);
369
+ lcb_settings_unref(settings);
370
+ }
371
+
372
+ lcb_error_t
373
+ RetryQueue::error_for(const mc_PACKET *packet)
374
+ {
375
+ if (! (packet->flags & MCREQ_F_DETACHED)) {
376
+ return LCB_SUCCESS; /* Not detached */
377
+ }
378
+
379
+ mc_EPKTDATUM *d = mcreq_epkt_find((mc_EXPACKET*)packet, RETRY_PKT_KEY);
380
+ if (!d) {
381
+ return LCB_SUCCESS;
382
+ }
383
+ return static_cast<RetryOp*>(d)->origerr;
384
+ }
385
+
386
+ void
387
+ RetryQueue::dump(FILE *fp, mcreq_payload_dump_fn dumpfn)
388
+ {
389
+ lcb_list_t *cur;
390
+ LCB_LIST_FOR(cur, &schedops) {
391
+ RetryOp *op = from_schednode(cur);
392
+ mcreq_dump_packet(op->pkt, fp, dumpfn);
393
+ }
394
+ }
@@ -17,15 +17,14 @@
17
17
 
18
18
  #ifndef LCB_RETRYQ_H
19
19
  #define LCB_RETRYQ_H
20
- #ifdef __cplusplus
21
- extern "C" {
22
- #endif
23
20
 
24
21
  #include <lcbio/lcbio.h>
25
22
  #include <lcbio/timer-ng.h>
26
23
  #include <mc/mcreq.h>
27
24
  #include "list.h"
28
25
 
26
+ #ifdef __cplusplus
27
+
29
28
  /**
30
29
  * @file
31
30
  * @brief Retry Queue
@@ -40,118 +39,131 @@ extern "C" {
40
39
  * @{
41
40
  */
42
41
 
43
- typedef struct lcb_RETRYQ {
44
- /** List of operations in retry ordering. Sorted by 'crtime' */
45
- lcb_list_t schedops;
46
- /** List of operations in timeout ordering. Ordered by 'start_time' */
47
- lcb_list_t tmoops;
48
- /** Parent command queue */
49
- mc_CMDQUEUE *cq;
50
- lcb_settings *settings;
51
- lcbio_pTIMER timer;
52
- } lcb_RETRYQ;
42
+ namespace lcb {
53
43
 
54
- /**
55
- * @brief Create a new retry queue.
56
- * The retry queue serves as an asynchronous poller which will retry operations
57
- * with a certain throttle.
58
- *
59
- * @param cq The parent cmdqueue object
60
- * @param table used to create the timer
61
- * @param settings Used for logging and interval timeouts
62
- * @return A new retry queue object
63
- */
64
- lcb_RETRYQ *
65
- lcb_retryq_new(mc_CMDQUEUE *cq, lcbio_pTABLE table, lcb_settings *settings);
44
+ struct RetryOp;
66
45
 
67
- void
68
- lcb_retryq_destroy(lcb_RETRYQ *rq);
46
+ class RetryQueue {
47
+ public:
48
+ /**
49
+ * @brief Create a new retry queue.
50
+ * The retry queue serves as an asynchronous poller which will retry operations
51
+ * with a certain throttle.
52
+ *
53
+ * @param cq The parent cmdqueue object
54
+ * @param table used to create the timer
55
+ * @param settings Used for logging and interval timeouts
56
+ * @return A new retry queue object
57
+ */
58
+ RetryQueue(mc_CMDQUEUE* cq_, lcbio_pTABLE, lcb_settings *);
59
+ ~RetryQueue();
69
60
 
70
- /**
71
- * @brief Enqueue a failed command
72
- * @param rq The retried queue
73
- * @param detchpkt A detached packet allocated with mcreq_renew_packet()
74
- * @param err the error code which caused the packet to be placed inside the
75
- * retry queue. Depending on the error code and subsequent errors, this code
76
- * will ultimately be sent back to the operation callback when the result is
77
- * final.
78
- *
79
- * @attention Only simple commands containing vBuckets may be placed here.
80
- * Complex commands such as OBSERVE or STAT may _not_ be retried through this
81
- * mechanism. Additionally since this relies on determining a vBucket master
82
- * it may _not_ be used for memcached buckets (which is typically OK, as we only
83
- * map things here as a response for a not-my-vbucket).
84
- */
85
- void
86
- lcb_retryq_add(lcb_RETRYQ *rq, mc_EXPACKET *detchpkt, lcb_error_t err);
61
+ /**
62
+ * @brief Enqueue a failed command
63
+ * @param detchpkt A detached packet allocated with mcreq_renew_packet()
64
+ * @param err the error code which caused the packet to be placed inside the
65
+ * retry queue. Depending on the error code and subsequent errors, this code
66
+ * will ultimately be sent back to the operation callback when the result is
67
+ * final.
68
+ *
69
+ * @attention Only simple commands containing vBuckets may be placed here.
70
+ * Complex commands such as OBSERVE or STAT may _not_ be retried through this
71
+ * mechanism. Additionally since this relies on determining a vBucket master
72
+ * it may _not_ be used for memcached buckets (which is typically OK, as we only
73
+ * map things here as a response for a not-my-vbucket).
74
+ */
75
+ void add(mc_EXPACKET *detchpkt, lcb_error_t err) {
76
+ add(detchpkt, err, 0);
77
+ }
87
78
 
88
- /**
89
- * Retries the given packet as a result of a NOT_MY_VBUCKET failure. Currently
90
- * this is provided to allow for different behavior when handling these types
91
- * of responses.
92
- *
93
- * @param rq The retry queue
94
- * @param detchpkt The new packet
95
- */
96
- void
97
- lcb_retryq_nmvadd(lcb_RETRYQ *rq, mc_EXPACKET *detchpkt);
79
+ /**
80
+ * Retries the given packet as a result of a NOT_MY_VBUCKET failure. Currently
81
+ * this is provided to allow for different behavior when handling these types
82
+ * of responses.
83
+ *
84
+ * @param detchpkt The new packet
85
+ */
86
+ void nmvadd(mc_EXPACKET *detchpkt);
98
87
 
99
- /**
100
- * @brief Retry all queued operations
101
- *
102
- * This should normally be called when a new server connection is made or when
103
- * a new configuration update has arrived.
104
- *
105
- * @param rq The queue
106
- */
107
- void
108
- lcb_retryq_signal(lcb_RETRYQ *rq);
88
+ /**
89
+ * @brief Retry all queued operations
90
+ *
91
+ * This should normally be called when a new server connection is made or when
92
+ * a new configuration update has arrived.
93
+ *
94
+ * @param rq The queue
95
+ */
96
+ void signal();
109
97
 
110
- /**
111
- * If this packet has been previously retried, this obtains the original error
112
- * which caused it to be enqueued in the first place. This eliminates spurious
113
- * timeout errors which mask the real cause of the error.
114
- *
115
- * @param pkt The packet to check for
116
- * @return An error code, or LCB_SUCCESS if the packet does not have an
117
- * original error.
118
- */
119
- lcb_error_t
120
- lcb_retryq_origerr(const mc_PACKET *pkt);
98
+ /**
99
+ * If this packet has been previously retried, this obtains the original error
100
+ * which caused it to be enqueued in the first place. This eliminates spurious
101
+ * timeout errors which mask the real cause of the error.
102
+ *
103
+ * @param pkt The packet to check for
104
+ * @return An error code, or LCB_SUCCESS if the packet does not have an
105
+ * original error.
106
+ */
107
+ static lcb_error_t error_for(const mc_PACKET*);
121
108
 
122
- /**
123
- * Dumps the packets inside the queue
124
- * @param rq The request queue
125
- * @param fp The file to which the output should be written to
126
- */
127
- void
128
- lcb_retryq_dump(lcb_RETRYQ *rq, FILE *fp, mcreq_payload_dump_fn dumpfn);
109
+ /**
110
+ * Dumps the packets inside the queue
111
+ * @param rq The request queue
112
+ * @param fp The file to which the output should be written to
113
+ */
114
+ void dump(FILE *fp, mcreq_payload_dump_fn dumpfn);
129
115
 
130
- /**
131
- * @brief Check if there are operations to retry
132
- * @param rq the queue
133
- * @return nonzero if there are pending operations
134
- */
135
- #define lcb_retryq_empty(rq) LCB_LIST_IS_EMPTY(&(rq)->schedops)
116
+ /**
117
+ * @brief Check if there are operations to retry
118
+ * @return nonzero if there are pending operations
119
+ */
120
+ bool empty() const { return LCB_LIST_IS_EMPTY(&schedops); }
136
121
 
137
- /**
138
- * @brief Reset all timeouts on the retry queue.
139
- *
140
- * This will defer the timeout to start from the current time rather than
141
- * the time it was initially placed in the queue. Items are usually placed
142
- * in the queue after a network failure or similar; however one exception
143
- * is items which are placed in the queue via the scheduling APIs directly
144
- * (if there is no host for the command's vBucket)
145
- *
146
- * @param rq The retry queue
147
- * @param now The time to use
148
- */
149
- void
150
- lcb_retryq_reset_timeouts(lcb_RETRYQ *rq, lcb_U64 now);
122
+ /**
123
+ * @brief Reset all timeouts on the retry queue.
124
+ *
125
+ * This will defer the timeout to start from the current time rather than
126
+ * the time it was initially placed in the queue. Items are usually placed
127
+ * in the queue after a network failure or similar; however one exception
128
+ * is items which are placed in the queue via the scheduling APIs directly
129
+ * (if there is no host for the command's vBucket)
130
+ *
131
+ * @param now The time to use
132
+ */
133
+ void reset_timeouts(uint64_t now = 0);
151
134
 
152
- /**@}*/
135
+ /** Event loop tick */
136
+ inline void tick();
137
+
138
+ inline void add_fallback(mc_PACKET *pkt);
139
+
140
+ private:
141
+ void erase(RetryOp*);
142
+ void fail(RetryOp*, lcb_error_t);
143
+ void schedule(hrtime_t now = 0);
144
+ void flush(bool throttle);
145
+ void update_trytime(RetryOp *op, hrtime_t now = 0);
146
+ hrtime_t get_retry_interval() const;
147
+ lcb_t get_instance() const {
148
+ return reinterpret_cast<lcb_t>(cq->cqdata);
149
+ }
150
+
151
+ enum AddOptions {
152
+ RETRY_SCHED_IMM = 0x01
153
+ };
154
+ void add(mc_EXPACKET *pkt, lcb_error_t, int options);
155
+
156
+ /** List of operations in retry ordering. Sorted by 'crtime' */
157
+ lcb_list_t schedops;
158
+ /** List of operations in timeout ordering. Ordered by 'start_time' */
159
+ lcb_list_t tmoops;
160
+ /** Parent command queue */
161
+ mc_CMDQUEUE *cq;
162
+ lcb_settings *settings;
163
+ lcbio_pTIMER timer;
164
+ };
153
165
 
154
- #ifdef __cplusplus
155
166
  }
167
+ /**@}*/
156
168
  #endif
157
169
  #endif