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