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.
- 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
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2012 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
|
+
#define LCBDUR_PRIV_SYMS 1
|
|
19
|
+
#define NOMINMAX
|
|
20
|
+
|
|
21
|
+
#include "internal.h"
|
|
22
|
+
#include "durability_internal.h"
|
|
23
|
+
#include <algorithm>
|
|
24
|
+
#include <lcbio/iotable.h>
|
|
25
|
+
|
|
26
|
+
using namespace lcb::durability;
|
|
27
|
+
|
|
28
|
+
#define LOGARGS(c, lvl) (c)->instance->settings, "endure", LCB_LOG_##lvl, __FILE__, __LINE__
|
|
29
|
+
#define LOGARGS_T(lvl) LOGARGS(this, lvl)
|
|
30
|
+
|
|
31
|
+
static void timer_callback(lcb_socket_t sock, short which, void *arg);
|
|
32
|
+
|
|
33
|
+
bool
|
|
34
|
+
Item::is_all_done() const
|
|
35
|
+
{
|
|
36
|
+
const lcb_DURABILITYOPTSv0& opts = parent->opts;
|
|
37
|
+
|
|
38
|
+
if (!res().exists_master) {
|
|
39
|
+
/** Primary cache doesn't have correct version */
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (opts.persist_to) {
|
|
43
|
+
if (!res().persisted_master) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
if (res().npersisted < opts.persist_to) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (opts.replicate_to) {
|
|
52
|
+
if (res().nreplicated < opts.replicate_to) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
bool
|
|
61
|
+
Item::is_server_done(const ServerInfo &info, bool is_master) const
|
|
62
|
+
{
|
|
63
|
+
// Item not in cache. Return false
|
|
64
|
+
if (!info.exists) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Item is already persisted to the server
|
|
69
|
+
if (info.persisted) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Item not persisted, but no persistence requested
|
|
74
|
+
if (parent->opts.persist_to == 0) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Master persistence requested, but server is not master
|
|
79
|
+
if (parent->opts.persist_to == 1 && !is_master) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Require persistence from this server, but item is not persisted.
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
size_t
|
|
88
|
+
Item::prepare(uint16_t ixarray[4])
|
|
89
|
+
{
|
|
90
|
+
size_t oix = 0, maxix = 0;
|
|
91
|
+
lcb_t instance = parent->instance;
|
|
92
|
+
|
|
93
|
+
res().persisted_master = 0;
|
|
94
|
+
res().exists_master = 0;
|
|
95
|
+
res().npersisted = 0;
|
|
96
|
+
res().nreplicated = 0;
|
|
97
|
+
res().cas = 0;
|
|
98
|
+
res().rc = LCB_SUCCESS;
|
|
99
|
+
|
|
100
|
+
if (parent->opts.persist_to == 1 && parent->opts.replicate_to == 0) {
|
|
101
|
+
maxix = 1; /* Only master! */
|
|
102
|
+
} else {
|
|
103
|
+
maxix = LCBT_NREPLICAS(instance) + 1;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (size_t ii = 0; ii < maxix; ii++) {
|
|
107
|
+
int cur_ix;
|
|
108
|
+
ServerInfo& info = sinfo[ii];
|
|
109
|
+
|
|
110
|
+
cur_ix = lcbvb_vbserver(LCBT_VBCONFIG(instance), vbid, ii);
|
|
111
|
+
if (cur_ix < 0) {
|
|
112
|
+
info.clear();
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const lcb::Server *s_exp = instance->get_server(cur_ix);
|
|
117
|
+
if (s_exp != info.server) {
|
|
118
|
+
info.clear();
|
|
119
|
+
|
|
120
|
+
} else if (is_server_done(info, ii==0)) {
|
|
121
|
+
/* Update counters as required */
|
|
122
|
+
if (ii == 0) {
|
|
123
|
+
res().exists_master = 1;
|
|
124
|
+
} else {
|
|
125
|
+
res().nreplicated++;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (info.persisted) {
|
|
129
|
+
res().npersisted++;
|
|
130
|
+
if (ii == 0) {
|
|
131
|
+
res().persisted_master = 1;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Otherwise, write the expected server out */
|
|
138
|
+
ixarray[oix++] = s_exp->get_index();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return oix;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
void
|
|
145
|
+
Item::update(int flags, int srvix)
|
|
146
|
+
{
|
|
147
|
+
if (!flags || done) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
ServerInfo *info = get_server_info(srvix);
|
|
152
|
+
if (!info) {
|
|
153
|
+
lcb_log(LOGARGS(parent, DEBUG), "Ignoring response from server %d. Not a master or replica for vBucket %d", srvix, vbid);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
lcb_t instance = parent->instance;
|
|
158
|
+
bool is_master = lcbvb_vbmaster(LCBT_VBCONFIG(instance), vbid) == srvix;
|
|
159
|
+
const lcb::Server *server = instance->get_server(srvix);
|
|
160
|
+
|
|
161
|
+
memset(info, 0, sizeof(*info));
|
|
162
|
+
info->server = server;
|
|
163
|
+
|
|
164
|
+
if (flags & UPDATE_PERSISTED) {
|
|
165
|
+
info->persisted = 1;
|
|
166
|
+
res().npersisted++;
|
|
167
|
+
if (is_master) {
|
|
168
|
+
res().persisted_master = 1;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (flags & UPDATE_REPLICATED) {
|
|
173
|
+
info->exists = 1;
|
|
174
|
+
if (is_master) {
|
|
175
|
+
res().exists_master = 1;
|
|
176
|
+
} else {
|
|
177
|
+
res().nreplicated++;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (is_all_done()) {
|
|
182
|
+
finish(LCB_SUCCESS);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
ServerInfo *
|
|
187
|
+
Item::get_server_info(int srvix)
|
|
188
|
+
{
|
|
189
|
+
size_t ii;
|
|
190
|
+
lcb_t instance = parent->instance;
|
|
191
|
+
|
|
192
|
+
for (ii = 0; ii < LCBT_NREPLICAS(instance)+1; ii++) {
|
|
193
|
+
int ix = lcbvb_vbserver(LCBT_VBCONFIG(instance), vbid, ii);
|
|
194
|
+
if (ix > -1 && ix == srvix) {
|
|
195
|
+
return &sinfo[ii];
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return NULL;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
void
|
|
202
|
+
Item::finish()
|
|
203
|
+
{
|
|
204
|
+
lcb_RESPCALLBACK cb;
|
|
205
|
+
lcb_t instance;
|
|
206
|
+
|
|
207
|
+
if (done) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
done = 1;
|
|
212
|
+
parent->nremaining--;
|
|
213
|
+
|
|
214
|
+
/** Invoke the callback now :) */
|
|
215
|
+
result.cookie = (void *)parent->cookie;
|
|
216
|
+
instance = parent->instance;
|
|
217
|
+
|
|
218
|
+
if (parent->is_durstore) {
|
|
219
|
+
lcb_RESPSTOREDUR resp = { 0 };
|
|
220
|
+
resp.key = result.key;
|
|
221
|
+
resp.nkey = result.nkey;
|
|
222
|
+
resp.rc = result.rc;
|
|
223
|
+
resp.cas = reqcas;
|
|
224
|
+
resp.cookie = result.cookie;
|
|
225
|
+
resp.store_ok = 1;
|
|
226
|
+
resp.dur_resp = &result;
|
|
227
|
+
|
|
228
|
+
cb = lcb_find_callback(instance, LCB_CALLBACK_STOREDUR);
|
|
229
|
+
cb(instance, LCB_CALLBACK_STOREDUR, (lcb_RESPBASE*)&resp);
|
|
230
|
+
} else {
|
|
231
|
+
cb = lcb_find_callback(instance, LCB_CALLBACK_ENDURE);
|
|
232
|
+
cb(instance, LCB_CALLBACK_ENDURE, (lcb_RESPBASE*)&result);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (parent->nremaining == 0) {
|
|
236
|
+
parent->decref();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Called when the last (primitive) OBSERVE response is received for the entry.
|
|
242
|
+
*/
|
|
243
|
+
void
|
|
244
|
+
Durset::on_poll_done()
|
|
245
|
+
{
|
|
246
|
+
lcb_assert(waiting || ("Got NULL callback twice!" && 0));
|
|
247
|
+
|
|
248
|
+
waiting = 0;
|
|
249
|
+
|
|
250
|
+
if (nremaining > 0) {
|
|
251
|
+
switch_state(STATE_OBSPOLL);
|
|
252
|
+
}
|
|
253
|
+
decref();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Schedules a single sweep of observe requests.
|
|
258
|
+
* The `initial` parameter determines if this is a retry or if this is the
|
|
259
|
+
* initial scheduling.
|
|
260
|
+
*/
|
|
261
|
+
void
|
|
262
|
+
Durset::poll()
|
|
263
|
+
{
|
|
264
|
+
lcb_error_t err;
|
|
265
|
+
|
|
266
|
+
/* We should never be called while an 'iter' operation is still in progress */
|
|
267
|
+
lcb_assert(waiting == 0);
|
|
268
|
+
incref();
|
|
269
|
+
|
|
270
|
+
err = poll_impl();
|
|
271
|
+
if (err == LCB_SUCCESS) {
|
|
272
|
+
incref();
|
|
273
|
+
switch_state(STATE_TIMEOUT);
|
|
274
|
+
} else {
|
|
275
|
+
lasterr = err;
|
|
276
|
+
switch_state(STATE_OBSPOLL);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
decref();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
LIBCOUCHBASE_API
|
|
283
|
+
lcb_error_t
|
|
284
|
+
lcb_durability_validate(lcb_t instance,
|
|
285
|
+
lcb_U16 *persist_to, lcb_U16 *replicate_to, int options)
|
|
286
|
+
{
|
|
287
|
+
int replica_max = std::min(
|
|
288
|
+
LCBT_NREPLICAS(instance),
|
|
289
|
+
LCBT_NDATASERVERS(instance)-1);
|
|
290
|
+
int persist_max = replica_max + 1;
|
|
291
|
+
|
|
292
|
+
if (*persist_to == 0 && *replicate_to == 0) {
|
|
293
|
+
/* Empty values! */
|
|
294
|
+
return LCB_EINVAL;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* persist_max is always one more than replica_max */
|
|
298
|
+
if (static_cast<int>(*persist_to) > persist_max) {
|
|
299
|
+
if (options & LCB_DURABILITY_VALIDATE_CAPMAX) {
|
|
300
|
+
*persist_to = persist_max;
|
|
301
|
+
} else {
|
|
302
|
+
return LCB_DURABILITY_ETOOMANY;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (*replicate_to == 0) {
|
|
307
|
+
return LCB_SUCCESS;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (replica_max < 0) {
|
|
311
|
+
replica_max = 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* now, we need at least as many nodes as we have replicas */
|
|
315
|
+
if (static_cast<int>(*replicate_to) > replica_max) {
|
|
316
|
+
if (options & LCB_DURABILITY_VALIDATE_CAPMAX) {
|
|
317
|
+
*replicate_to = replica_max;
|
|
318
|
+
} else {
|
|
319
|
+
return LCB_DURABILITY_ETOOMANY;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return LCB_SUCCESS;
|
|
323
|
+
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
lcb_error_t Durset::MCTX_addcmd(const lcb_CMDBASE *cmd) {
|
|
327
|
+
if (LCB_KEYBUF_IS_EMPTY(&cmd->key)) {
|
|
328
|
+
return LCB_EMPTY_KEY;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
entries.resize(entries.size() + 1);
|
|
332
|
+
Item& ent = entries.back();
|
|
333
|
+
|
|
334
|
+
int vbid, srvix;
|
|
335
|
+
mcreq_map_key(&instance->cmdq, &cmd->key, &cmd->_hashkey,
|
|
336
|
+
MCREQ_PKT_BASESIZE, &vbid, &srvix);
|
|
337
|
+
|
|
338
|
+
/* ok. now let's initialize the entry..*/
|
|
339
|
+
memset(&ent, 0, sizeof (ent));
|
|
340
|
+
ent.res().nkey = cmd->key.contig.nbytes;
|
|
341
|
+
ent.reqcas = cmd->cas;
|
|
342
|
+
ent.parent = this;
|
|
343
|
+
ent.vbid = vbid;
|
|
344
|
+
|
|
345
|
+
kvbufs.append(reinterpret_cast<const char *>(cmd->key.contig.bytes),
|
|
346
|
+
cmd->key.contig.nbytes);
|
|
347
|
+
|
|
348
|
+
return after_add(ent, reinterpret_cast<const lcb_CMDENDURE*>(cmd));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
lcb_error_t
|
|
352
|
+
Durset::MCTX_done(const void *cookie_) {
|
|
353
|
+
lcb_error_t err;
|
|
354
|
+
const char *kptr = kvbufs.c_str();
|
|
355
|
+
|
|
356
|
+
if (entries.empty()) {
|
|
357
|
+
delete this;
|
|
358
|
+
return LCB_EINVAL;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
for (size_t ii = 0; ii < entries.size(); ii++) {
|
|
362
|
+
Item* ent = &entries[ii];
|
|
363
|
+
ent->res().key = kptr;
|
|
364
|
+
kptr += ent->res().nkey;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if ((err = prepare_schedule()) != LCB_SUCCESS) {
|
|
368
|
+
delete this;
|
|
369
|
+
return err;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
incref();
|
|
373
|
+
|
|
374
|
+
cookie = cookie_;
|
|
375
|
+
nremaining = entries.size();
|
|
376
|
+
ns_timeout = gethrtime() + LCB_US2NS(opts.timeout);
|
|
377
|
+
|
|
378
|
+
lcb_aspend_add(&instance->pendops, LCB_PENDTYPE_DURABILITY, this);
|
|
379
|
+
switch_state(STATE_INIT);
|
|
380
|
+
return LCB_SUCCESS;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
void Durset::MCTX_fail() {
|
|
384
|
+
delete this;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
void lcbdurctx_set_durstore(lcb_MULTICMD_CTX *mctx, int enabled)
|
|
388
|
+
{
|
|
389
|
+
static_cast<Durset*>(mctx)->is_durstore = enabled;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
static lcb_U8
|
|
393
|
+
get_poll_meth(lcb_t instance, const lcb_durability_opts_t *options)
|
|
394
|
+
{
|
|
395
|
+
/* Need to call this first, so we can actually allocate the appropriate
|
|
396
|
+
* data for this.. */
|
|
397
|
+
uint8_t meth;
|
|
398
|
+
if (options->version > 0) {
|
|
399
|
+
meth = options->v.v0.pollopts;
|
|
400
|
+
} else {
|
|
401
|
+
meth = LCB_DURABILITY_MODE_DEFAULT;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (meth == LCB_DURABILITY_MODE_DEFAULT) {
|
|
405
|
+
meth = LCB_DURABILITY_MODE_CAS;
|
|
406
|
+
|
|
407
|
+
if (LCBT_SETTING(instance, fetch_mutation_tokens) &&
|
|
408
|
+
LCBT_SETTING(instance, dur_mutation_tokens)) {
|
|
409
|
+
for (size_t ii = 0; ii < LCBT_NSERVERS(instance); ii++) {
|
|
410
|
+
if (instance->get_server(ii)->supports_mutation_tokens()) {
|
|
411
|
+
meth = LCB_DURABILITY_MODE_SEQNO;
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return meth;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
Durset::Durset(lcb_t instance_, const lcb_durability_opts_t *options)
|
|
422
|
+
: MultiCmdContext(),
|
|
423
|
+
nremaining(0), waiting(0), refcnt(0), next_state(STATE_OBSPOLL),
|
|
424
|
+
lasterr(LCB_SUCCESS), is_durstore(false), cookie(NULL),
|
|
425
|
+
ns_timeout(0), timer(NULL), instance(instance_)
|
|
426
|
+
{
|
|
427
|
+
const lcb_DURABILITYOPTSv0 *opts_in = &options->v.v0;
|
|
428
|
+
|
|
429
|
+
std::memset(&opts, 0, sizeof opts);
|
|
430
|
+
|
|
431
|
+
/* Ensure we don't clobber options from older versions */
|
|
432
|
+
opts.cap_max = opts_in->cap_max;
|
|
433
|
+
opts.check_delete = opts_in->check_delete;
|
|
434
|
+
opts.interval = opts_in->interval;
|
|
435
|
+
opts.persist_to = opts_in->persist_to;
|
|
436
|
+
opts.replicate_to = opts_in->replicate_to;
|
|
437
|
+
opts.timeout = opts_in->timeout;
|
|
438
|
+
|
|
439
|
+
if (!opts.timeout) {
|
|
440
|
+
opts.timeout = LCBT_SETTING(instance, durability_timeout);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (!opts.interval) {
|
|
444
|
+
opts.interval = LCBT_SETTING(instance, durability_interval);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
lcbio_pTABLE io = instance->iotable;
|
|
448
|
+
timer = io->timer.create(io->p);
|
|
449
|
+
|
|
450
|
+
lasterr = lcb_durability_validate(instance,
|
|
451
|
+
&opts.persist_to, &opts.replicate_to,
|
|
452
|
+
opts.cap_max ? LCB_DURABILITY_VALIDATE_CAPMAX : 0);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
LIBCOUCHBASE_API
|
|
456
|
+
lcb_MULTICMD_CTX *
|
|
457
|
+
lcb_endure3_ctxnew(lcb_t instance, const lcb_durability_opts_t *options,
|
|
458
|
+
lcb_error_t *errp)
|
|
459
|
+
{
|
|
460
|
+
lcb_error_t err_s;
|
|
461
|
+
if (!errp) {
|
|
462
|
+
errp = &err_s;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
*errp = LCB_SUCCESS;
|
|
466
|
+
|
|
467
|
+
if (!LCBT_VBCONFIG(instance)) {
|
|
468
|
+
*errp = LCB_CLIENT_ETMPFAIL;
|
|
469
|
+
return NULL;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
Durset *dset = NULL;
|
|
473
|
+
uint8_t pollmeth = get_poll_meth(instance, options);
|
|
474
|
+
if (pollmeth == LCB_DURABILITY_MODE_CAS) {
|
|
475
|
+
dset = Durset::createCasDurset(instance, options);
|
|
476
|
+
} else if (pollmeth == LCB_DURABILITY_MODE_SEQNO) {
|
|
477
|
+
dset = Durset::createSeqnoDurset(instance, options);
|
|
478
|
+
} else {
|
|
479
|
+
*errp = LCB_EINVAL;
|
|
480
|
+
return NULL;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if ((*errp = dset->lasterr) != LCB_SUCCESS) {
|
|
484
|
+
delete dset;
|
|
485
|
+
dset = NULL;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return dset;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
LIBCOUCHBASE_API
|
|
492
|
+
lcb_error_t
|
|
493
|
+
lcb_durability_poll(lcb_t instance, const void *cookie,
|
|
494
|
+
const lcb_durability_opts_t *options, lcb_size_t ncmds,
|
|
495
|
+
const lcb_durability_cmd_t *const *cmds)
|
|
496
|
+
{
|
|
497
|
+
lcb_MULTICMD_CTX *mctx;
|
|
498
|
+
lcb_error_t err;
|
|
499
|
+
|
|
500
|
+
if (ncmds == 0) {
|
|
501
|
+
return LCB_EINVAL;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
mctx = lcb_endure3_ctxnew(instance, options, &err);
|
|
505
|
+
if (!mctx) {
|
|
506
|
+
return err;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
for (size_t ii = 0; ii < ncmds; ii++) {
|
|
510
|
+
lcb_CMDENDURE cmd = { 0 };
|
|
511
|
+
const lcb_DURABILITYCMDv0 *src = &cmds[ii]->v.v0;
|
|
512
|
+
cmd.key.contig.bytes = src->key;
|
|
513
|
+
cmd.key.contig.nbytes = src->nkey;
|
|
514
|
+
cmd._hashkey.contig.bytes = src->hashkey;
|
|
515
|
+
cmd._hashkey.contig.nbytes = src->nhashkey;
|
|
516
|
+
cmd.cas = src->cas;
|
|
517
|
+
|
|
518
|
+
err = mctx->addcmd(mctx, (lcb_CMDBASE*)&cmd);
|
|
519
|
+
if (err != LCB_SUCCESS) {
|
|
520
|
+
mctx->fail(mctx);
|
|
521
|
+
return err;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
lcb_sched_enter(instance);
|
|
526
|
+
err = mctx->done(mctx, cookie);
|
|
527
|
+
if (err != LCB_SUCCESS) {
|
|
528
|
+
lcb_sched_fail(instance);
|
|
529
|
+
return err;
|
|
530
|
+
} else {
|
|
531
|
+
lcb_sched_leave(instance);
|
|
532
|
+
SYNCMODE_INTERCEPT(instance)
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Actually free the resources allocated by the dset (and all its entries).
|
|
538
|
+
* Called by some other functions in libcouchbase
|
|
539
|
+
*/
|
|
540
|
+
void lcbdur_destroy(void *dset) {
|
|
541
|
+
delete reinterpret_cast<Durset*>(dset);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
Durset::~Durset()
|
|
545
|
+
{
|
|
546
|
+
if (timer) {
|
|
547
|
+
lcbio_TABLE *io = instance->iotable;
|
|
548
|
+
io->timer.cancel(io->p, timer);
|
|
549
|
+
io->timer.destroy(io->p, timer);
|
|
550
|
+
timer = NULL;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
lcb_aspend_del(&instance->pendops, LCB_PENDTYPE_DURABILITY, this);
|
|
554
|
+
lcb_maybe_breakout(instance);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* All-purpose callback dispatcher.
|
|
559
|
+
*/
|
|
560
|
+
static void timer_callback(lcb_socket_t, short, void *arg) {
|
|
561
|
+
reinterpret_cast<Durset*>(arg)->tick();
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
void
|
|
565
|
+
Durset::tick()
|
|
566
|
+
{
|
|
567
|
+
hrtime_t now = gethrtime();
|
|
568
|
+
|
|
569
|
+
if (ns_timeout && now > ns_timeout) {
|
|
570
|
+
next_state = STATE_TIMEOUT;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
switch (next_state) {
|
|
574
|
+
case STATE_OBSPOLL:
|
|
575
|
+
case STATE_INIT:
|
|
576
|
+
poll();
|
|
577
|
+
break;
|
|
578
|
+
|
|
579
|
+
case STATE_TIMEOUT: {
|
|
580
|
+
lcb_error_t err = lasterr ? lasterr : LCB_ETIMEDOUT;
|
|
581
|
+
ns_timeout = 0;
|
|
582
|
+
next_state = STATE_IGNORE;
|
|
583
|
+
|
|
584
|
+
lcb_log(LOGARGS_T(WARN), "Polling durability timed out!");
|
|
585
|
+
|
|
586
|
+
incref();
|
|
587
|
+
|
|
588
|
+
for (size_t ii = 0; ii < entries.size(); ii++) {
|
|
589
|
+
Item *ent = &entries[ii];
|
|
590
|
+
if (ent->done) {
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
if (ent->res().rc == LCB_SUCCESS) {
|
|
594
|
+
ent->res().rc = err;
|
|
595
|
+
}
|
|
596
|
+
ent->finish();
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
decref();
|
|
600
|
+
break;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
case STATE_IGNORE:
|
|
604
|
+
break;
|
|
605
|
+
|
|
606
|
+
default:
|
|
607
|
+
lcb_assert("unexpected state" && 0);
|
|
608
|
+
break;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Schedules us to be notified with the given state within a particular amount
|
|
614
|
+
* of time. This is used both for the timeout and for the interval
|
|
615
|
+
*/
|
|
616
|
+
void
|
|
617
|
+
Durset::switch_state(State state)
|
|
618
|
+
{
|
|
619
|
+
uint32_t delay = 0;
|
|
620
|
+
lcbio_TABLE* io = instance->iotable;
|
|
621
|
+
hrtime_t now = gethrtime();
|
|
622
|
+
|
|
623
|
+
if (state == STATE_TIMEOUT) {
|
|
624
|
+
if (ns_timeout && now < ns_timeout) {
|
|
625
|
+
delay = LCB_NS2US(ns_timeout - now);
|
|
626
|
+
} else {
|
|
627
|
+
delay = 0;
|
|
628
|
+
}
|
|
629
|
+
} else if (state == STATE_OBSPOLL) {
|
|
630
|
+
if (now + LCB_US2NS(opts.interval) < ns_timeout) {
|
|
631
|
+
delay = opts.interval;
|
|
632
|
+
} else {
|
|
633
|
+
delay = 0;
|
|
634
|
+
state = STATE_TIMEOUT;
|
|
635
|
+
}
|
|
636
|
+
} else if (state == STATE_INIT) {
|
|
637
|
+
delay = 0;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
next_state = state;
|
|
641
|
+
io->timer.cancel(io->p, timer);
|
|
642
|
+
io->timer.schedule(io->p, timer, delay, this, timer_callback);
|
|
643
|
+
}
|