libcouchbase 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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