libcouchbase 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/libcouchbase/.gitignore +2 -0
- data/ext/libcouchbase/CMakeLists.txt +5 -7
- data/ext/libcouchbase/README.markdown +2 -2
- data/ext/libcouchbase/RELEASE_NOTES.markdown +49 -0
- data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +11 -0
- data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -0
- data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +2 -1
- data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
- data/ext/libcouchbase/cmake/config-cmake.h.in +2 -0
- data/ext/libcouchbase/cmake/defs.mk.in +0 -2
- data/ext/libcouchbase/cmake/source_files.cmake +34 -14
- data/ext/libcouchbase/configure.pl +1 -1
- data/ext/libcouchbase/contrib/genhash/genhash.h +6 -0
- data/ext/libcouchbase/include/libcouchbase/auth.h +10 -0
- data/ext/libcouchbase/include/libcouchbase/couchbase.h +10 -0
- data/ext/libcouchbase/include/libcouchbase/error.h +7 -0
- data/ext/libcouchbase/include/libcouchbase/n1ql.h +13 -1
- data/ext/libcouchbase/include/libcouchbase/plugins/io/bsdio-inl.c +1 -1
- data/ext/libcouchbase/include/libcouchbase/subdoc.h +9 -0
- data/ext/libcouchbase/include/libcouchbase/views.h +7 -1
- data/ext/libcouchbase/include/libcouchbase/visibility.h +1 -0
- data/ext/libcouchbase/include/memcached/protocol_binary.h +21 -1132
- data/ext/libcouchbase/packaging/parse-git-describe.pl +1 -1
- data/ext/libcouchbase/plugins/io/libev/libev_io_opts.h +3 -2
- data/ext/libcouchbase/src/README.md +0 -2
- data/ext/libcouchbase/src/auth-priv.h +1 -0
- data/ext/libcouchbase/src/auth.cc +10 -0
- data/ext/libcouchbase/src/bootstrap.cc +216 -0
- data/ext/libcouchbase/src/bootstrap.h +50 -39
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +455 -0
- data/ext/libcouchbase/src/bucketconfig/bc_file.cc +281 -0
- data/ext/libcouchbase/src/bucketconfig/bc_http.cc +528 -0
- data/ext/libcouchbase/src/bucketconfig/bc_http.h +50 -25
- data/ext/libcouchbase/src/bucketconfig/bc_mcraw.cc +115 -0
- data/ext/libcouchbase/src/bucketconfig/clconfig.h +407 -386
- data/ext/libcouchbase/src/bucketconfig/confmon.cc +378 -0
- data/ext/libcouchbase/src/cbft.cc +22 -27
- data/ext/libcouchbase/src/cntl.cc +24 -24
- data/ext/libcouchbase/src/connspec.cc +30 -1
- data/ext/libcouchbase/src/connspec.h +17 -0
- data/ext/libcouchbase/src/dns-srv.cc +143 -0
- data/ext/libcouchbase/src/{dump.c → dump.cc} +8 -11
- data/ext/libcouchbase/src/getconfig.cc +73 -0
- data/ext/libcouchbase/src/handler.cc +84 -85
- data/ext/libcouchbase/src/hostlist.cc +0 -1
- data/ext/libcouchbase/src/hostlist.h +6 -1
- data/ext/libcouchbase/src/http/http-priv.h +125 -112
- data/ext/libcouchbase/src/http/http.cc +9 -29
- data/ext/libcouchbase/src/http/http.h +1 -34
- data/ext/libcouchbase/src/http/http_io.cc +22 -26
- data/ext/libcouchbase/src/instance.cc +102 -28
- data/ext/libcouchbase/src/internal.h +47 -29
- data/ext/libcouchbase/src/jsparse/parser.cc +146 -202
- data/ext/libcouchbase/src/jsparse/parser.h +91 -98
- data/ext/libcouchbase/src/lcbht/lcbht.cc +177 -0
- data/ext/libcouchbase/src/lcbht/lcbht.h +174 -163
- data/ext/libcouchbase/src/lcbio/connect.cc +562 -0
- data/ext/libcouchbase/src/lcbio/connect.h +9 -2
- data/ext/libcouchbase/src/lcbio/ctx.c +1 -1
- data/ext/libcouchbase/src/lcbio/iotable.h +61 -16
- data/ext/libcouchbase/src/lcbio/ioutils.h +1 -1
- data/ext/libcouchbase/src/lcbio/manager.c +2 -2
- data/ext/libcouchbase/src/lcbio/timer-cxx.h +87 -0
- data/ext/libcouchbase/src/mc/mcreq.h +9 -2
- data/ext/libcouchbase/src/mcserver/mcserver.cc +723 -0
- data/ext/libcouchbase/src/mcserver/mcserver.h +160 -70
- data/ext/libcouchbase/src/mcserver/negotiate.cc +118 -152
- data/ext/libcouchbase/src/mcserver/negotiate.h +85 -74
- data/ext/libcouchbase/src/mctx-helper.h +51 -0
- data/ext/libcouchbase/src/n1ql/ixmgmt.cc +1 -2
- data/ext/libcouchbase/src/n1ql/n1ql.cc +56 -32
- data/ext/libcouchbase/src/{newconfig.c → newconfig.cc} +42 -70
- data/ext/libcouchbase/src/nodeinfo.cc +4 -8
- data/ext/libcouchbase/src/operations/{cbflush.c → cbflush.cc} +7 -15
- data/ext/libcouchbase/src/operations/{counter.c → counter.cc} +0 -0
- data/ext/libcouchbase/src/operations/{durability-cas.c → durability-cas.cc} +92 -76
- data/ext/libcouchbase/src/operations/{durability-seqno.c → durability-seqno.cc} +55 -49
- data/ext/libcouchbase/src/operations/durability.cc +643 -0
- data/ext/libcouchbase/src/operations/durability_internal.h +212 -124
- data/ext/libcouchbase/src/operations/{get.c → get.cc} +24 -26
- data/ext/libcouchbase/src/operations/{observe-seqno.c → observe-seqno.cc} +5 -8
- data/ext/libcouchbase/src/operations/{observe.c → observe.cc} +69 -94
- data/ext/libcouchbase/src/operations/{pktfwd.c → pktfwd.cc} +0 -0
- data/ext/libcouchbase/src/operations/{remove.c → remove.cc} +0 -0
- data/ext/libcouchbase/src/operations/{stats.c → stats.cc} +66 -78
- data/ext/libcouchbase/src/operations/{store.c → store.cc} +27 -32
- data/ext/libcouchbase/src/operations/subdoc.cc +38 -18
- data/ext/libcouchbase/src/operations/{touch.c → touch.cc} +0 -0
- data/ext/libcouchbase/src/packetutils.h +200 -137
- data/ext/libcouchbase/src/probes.d +1 -1
- data/ext/libcouchbase/src/{retrychk.c → retrychk.cc} +3 -4
- data/ext/libcouchbase/src/retryq.cc +394 -0
- data/ext/libcouchbase/src/retryq.h +116 -104
- data/ext/libcouchbase/src/settings.h +2 -1
- data/ext/libcouchbase/src/ssl/ssl_c.c +1 -0
- data/ext/libcouchbase/src/ssl/ssl_e.c +0 -1
- data/ext/libcouchbase/src/trace.h +8 -8
- data/ext/libcouchbase/src/vbucket/vbucket.c +0 -1
- data/ext/libcouchbase/src/views/{docreq.c → docreq.cc} +48 -54
- data/ext/libcouchbase/src/views/docreq.h +24 -30
- data/ext/libcouchbase/src/views/viewreq.cc +318 -0
- data/ext/libcouchbase/src/views/viewreq.h +43 -13
- data/ext/libcouchbase/src/{wait.c → wait.cc} +12 -17
- data/ext/libcouchbase/tests/basic/t_connstr.cc +89 -50
- data/ext/libcouchbase/tests/basic/t_jsparse.cc +27 -78
- data/ext/libcouchbase/tests/basic/t_packet.cc +35 -42
- data/ext/libcouchbase/tests/htparse/t_basic.cc +58 -78
- data/ext/libcouchbase/tests/iotests/t_confmon.cc +94 -111
- data/ext/libcouchbase/tests/iotests/t_sched.cc +1 -2
- data/ext/libcouchbase/tests/mc/t_alloc.cc +9 -9
- data/ext/libcouchbase/tools/cbc-pillowfight.cc +1 -1
- data/lib/libcouchbase/version.rb +1 -1
- metadata +36 -39
- data/ext/libcouchbase/include/memcached/vbucket.h +0 -42
- data/ext/libcouchbase/src/bootstrap.c +0 -269
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.c +0 -495
- data/ext/libcouchbase/src/bucketconfig/bc_file.c +0 -347
- data/ext/libcouchbase/src/bucketconfig/bc_http.c +0 -630
- data/ext/libcouchbase/src/bucketconfig/bc_mcraw.c +0 -150
- data/ext/libcouchbase/src/bucketconfig/confmon.c +0 -474
- data/ext/libcouchbase/src/getconfig.c +0 -100
- data/ext/libcouchbase/src/lcbht/lcbht.c +0 -282
- data/ext/libcouchbase/src/lcbio/connect.c +0 -557
- data/ext/libcouchbase/src/mcserver/mcserver.c +0 -784
- data/ext/libcouchbase/src/operations/durability.c +0 -668
- data/ext/libcouchbase/src/packetutils.c +0 -60
- data/ext/libcouchbase/src/retryq.c +0 -424
- data/ext/libcouchbase/src/simplestring.c +0 -211
- data/ext/libcouchbase/src/simplestring.h +0 -228
- data/ext/libcouchbase/src/ssobuf.h +0 -82
- data/ext/libcouchbase/src/views/viewreq.c +0 -358
- data/ext/libcouchbase/tests/basic/t_string.cc +0 -112
@@ -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
|
-
|
24
|
-
|
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
|
-
|
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
|
-
|
68
|
-
|
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
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
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
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
124
|
-
|
125
|
-
|
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
|
-
|
132
|
-
|
133
|
-
|
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
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
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
|