MB-21617: Change CAS resolution to nanoseconds
[ep-engine.git] / tests / ep_testsuite_xdcr.cc
1 /* -*- MODE: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2016 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 /*
19  * Testsuite for XDCR-related functionality in ep-engine.
20  */
21
22 #include "config.h"
23
24 #include "ep_test_apis.h"
25 #include "ep_testsuite_common.h"
26 #include "hlc.h"
27
28 #include <platform/cb_malloc.h>
29
30 // Helper functions ///////////////////////////////////////////////////////////
31
32 static void verifyLastMetaData(ItemMetaData imd) {
33     checkeq(imd.revSeqno, last_meta.revSeqno, "Seqno didn't match");
34     checkeq(imd.cas, last_meta.cas, "Cas didn't match");
35     checkeq(imd.exptime, last_meta.exptime, "Expiration time didn't match");
36     checkeq(imd.flags, last_meta.flags, "Flags didn't match");
37 }
38
39 // Testcases //////////////////////////////////////////////////////////////////
40
41 static enum test_result test_get_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
42 {
43     char const *key = "test_get_meta";
44     item *i = NULL;
45     checkeq(ENGINE_SUCCESS,
46             store(h, h1, NULL, OPERATION_SET, key, "somevalue", &i),
47             "Failed set.");
48     Item *it = reinterpret_cast<Item*>(i);
49     // check the stat
50     size_t temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
51     check(temp == 0, "Expect zero getMeta ops");
52
53     check(get_meta(h, h1, key), "Expected to get meta");
54     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
55             "Expected success");
56
57     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
58     ItemMetaData metadata(it->getCas(), it->getRevSeqno(),
59                           it->getFlags(), it->getExptime());
60     verifyLastMetaData(metadata);
61
62     // check the stat again
63     temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
64     check(temp == 1, "Expect one getMeta op");
65
66     h1->release(h, NULL, i);
67     return SUCCESS;
68 }
69
70 static enum test_result test_get_meta_with_extras(ENGINE_HANDLE *h,
71                                                   ENGINE_HANDLE_V1 *h1)
72 {
73     const char *key1 = "test_getm_one";
74     item *i = NULL;
75     checkeq(ENGINE_SUCCESS,
76             store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
77             "Failed set.");
78
79     wait_for_flusher_to_settle(h, h1);
80
81     Item *it1 = reinterpret_cast<Item*>(i);
82     // check the stat
83     size_t temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
84     check(temp == 0, "Expect zero getMeta ops");
85
86     check(get_meta(h, h1, key1, true), "Expected to get meta");
87     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
88     ItemMetaData metadata1(it1->getCas(), it1->getRevSeqno(),
89                            it1->getFlags(), it1->getExptime());
90     verifyLastMetaData(metadata1);
91     // check the stat again
92     temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
93     check(temp == 1, "Expect one getMeta op");
94     h1->release(h, NULL, i);
95
96     // restart
97     testHarness.reload_engine(&h, &h1,
98                               testHarness.engine_path,
99                               testHarness.get_current_testcase()->cfg,
100                               true, true);
101     wait_for_warmup_complete(h, h1);
102
103     check(get_meta(h, h1, key1, true), "Expected to get meta");
104     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "Expected success");
105     verifyLastMetaData(metadata1);
106
107     return SUCCESS;
108 }
109
110 static enum test_result test_get_meta_deleted(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
111 {
112     char const *key = "k1";
113     item *i = NULL;
114
115     checkeq(ENGINE_SUCCESS,
116             store(h, h1, NULL, OPERATION_SET, key, "somevalue", &i),
117             "Failed set.");
118     h1->release(h, NULL, i);
119     checkeq(ENGINE_SUCCESS,
120             store(h, h1, NULL, OPERATION_SET, key, "somevalue", &i),
121             "Failed set.");
122
123     Item *it = reinterpret_cast<Item*>(i);
124     wait_for_flusher_to_settle(h, h1);
125
126     checkeq(ENGINE_SUCCESS, del(h, h1, key, it->getCas(), 0), "Delete failed");
127     wait_for_flusher_to_settle(h, h1);
128
129     // check the stat
130     int temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
131     check(temp == 0, "Expect zero getMeta ops");
132
133     check(get_meta(h, h1, key), "Expected to get meta");
134     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
135     check(last_deleted_flag, "Expected deleted flag to be set");
136     check(last_meta.revSeqno == it->getRevSeqno() + 1, "Expected seqno to match");
137     check(last_meta.cas != it->getCas() , "Expected cas to be different");
138     check(last_meta.flags == it->getFlags(), "Expected flags to match");
139
140     // check the stat again
141     temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
142     checkeq(1, temp, "Expect one getMeta op");
143
144     h1->release(h, NULL, i);
145     return SUCCESS;
146 }
147
148 static enum test_result test_get_meta_nonexistent(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
149 {
150     char const *key = "k1";
151
152     // check the stat
153     int temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
154     check(temp == 0, "Expect zero getMeta ops");
155     check(!get_meta(h, h1, key), "Expected get meta to return false");
156     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(),
157             "Expected enoent");
158     // check the stat again
159     temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
160     checkeq(1, temp, "Expect one getMeta ops");
161
162     return SUCCESS;
163 }
164
165 static enum test_result test_get_meta_with_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
166 {
167     char const *key1 = "key1";
168     char const *key2 = "key2";
169
170     item *i = NULL;
171     // test get_meta followed by get for an existing key. should pass.
172     checkeq(ENGINE_SUCCESS,
173             store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
174             "Failed set.");
175     h1->release(h, NULL, i);
176     wait_for_flusher_to_settle(h, h1);
177     // check the stat
178     int temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
179     check(temp == 0, "Expect zero getMeta ops");
180     check(get_meta(h, h1, key1), "Expected to get meta");
181     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
182     checkeq(ENGINE_SUCCESS,
183             h1->get(h, NULL, &i, key1, strlen(key1), 0), "Expected get success");
184     h1->release(h, NULL, i);
185     // check the stat again
186     temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
187     check(temp == 1, "Expect one getMeta op");
188
189     // test get_meta followed by get for a deleted key. should fail.
190     checkeq(ENGINE_SUCCESS,
191             del(h, h1, key1, 0, 0), "Delete failed");
192     wait_for_flusher_to_settle(h, h1);
193     check(get_meta(h, h1, key1), "Expected to get meta");
194     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
195             "Expected success");
196     check(last_deleted_flag, "Expected deleted flag to be set");
197     checkeq(ENGINE_KEY_ENOENT,
198             h1->get(h, NULL, &i, key1, strlen(key1), 0), "Expected enoent");
199     // check the stat again
200     temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
201     checkeq(2, temp, "Expect more getMeta ops");
202
203     // test get_meta followed by get for a nonexistent key. should fail.
204     check(!get_meta(h, h1, key2), "Expected get meta to return false");
205     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(),
206             "Expected enoent");
207     checkeq(ENGINE_KEY_ENOENT,
208             h1->get(h, NULL, &i, key2, strlen(key2), 0), "Expected enoent");
209     // check the stat again
210     temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
211     checkeq(3, temp, "Expected one extra getMeta ops");
212
213     return SUCCESS;
214 }
215
216 static enum test_result test_get_meta_with_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
217 {
218     char const *key1 = "key1";
219     char const *key2 = "key2";
220
221     item *i = NULL;
222     ItemMetaData itm_meta;
223
224     // test get_meta followed by set for an existing key. should pass.
225     checkeq(ENGINE_SUCCESS,
226             store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
227             "Failed set.");
228     h1->release(h, NULL, i);
229     wait_for_flusher_to_settle(h, h1);
230     wait_for_stat_to_be(h, h1, "curr_items", 1);
231
232     // check the stat
233     checkeq(0, get_int_stat(h, h1, "ep_num_ops_get_meta"), "Expect zero getMeta ops");
234     check(get_meta(h, h1, key1), "Expected to get meta");
235     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
236             "Expected success");
237     checkeq(ENGINE_SUCCESS,
238             store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
239             "Failed set.");
240     // check the stat
241     checkeq(1, get_int_stat(h, h1, "ep_num_ops_get_meta"), "Expect one getMeta op");
242     checkeq(1, get_int_stat(h, h1, "curr_items"), "Expected single curr_items");
243     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
244     h1->release(h, NULL, i);
245
246     // check curr, temp item counts
247     checkeq(1, get_int_stat(h, h1, "curr_items"), "Expected single curr_items");
248     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
249
250     // test get_meta followed by set for a deleted key. should pass.
251     checkeq(ENGINE_SUCCESS, del(h, h1, key1, 0, 0), "Delete failed");
252     wait_for_flusher_to_settle(h, h1);
253
254     wait_for_stat_to_be(h, h1, "curr_items", 0);
255     check(get_meta(h, h1, key1), "Expected to get meta");
256     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
257     checkeq(1, get_int_stat(h, h1, "curr_temp_items"), "Expected single temp_items");
258
259     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
260             "Expected success");
261     check(last_deleted_flag, "Expected deleted flag to be set");
262     checkeq(ENGINE_SUCCESS,
263             store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
264             "Failed set.");
265
266     checkeq(1, get_int_stat(h, h1, "curr_items"), "Expected single curr_items");
267     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
268
269     // check the stat
270     checkeq(2, get_int_stat(h, h1, "ep_num_ops_get_meta"), "Expect more getMeta ops");
271     h1->release(h, NULL, i);
272
273     // test get_meta followed by set for a nonexistent key. should pass.
274     check(!get_meta(h, h1, key2), "Expected get meta to return false");
275     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(), "Expected enoent");
276     checkeq(ENGINE_SUCCESS,
277             store(h, h1, NULL, OPERATION_SET, key2, "someothervalue", &i),
278             "Failed set.");
279     // check the stat again
280     checkeq(3, get_int_stat(h, h1, "ep_num_ops_get_meta"),
281             "Expected one extra getMeta ops");
282
283     h1->release(h, NULL, i);
284     return SUCCESS;
285 }
286
287 static enum test_result test_get_meta_with_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
288 {
289     char const *key1 = "key1";
290     char const *key2 = "key2";
291
292     item *i = NULL;
293
294     // test get_meta followed by delete for an existing key. should pass.
295     checkeq(ENGINE_SUCCESS,
296             store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
297             "Failed set.");
298     h1->release(h, NULL, i);
299     wait_for_flusher_to_settle(h, h1);
300     // check the stat
301     int temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
302     check(temp == 0, "Expect zero getMeta ops");
303     check(get_meta(h, h1, key1), "Expected to get meta");
304     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
305     checkeq(ENGINE_SUCCESS, del(h, h1, key1, 0, 0), "Delete failed");
306     // check the stat
307     temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
308     check(temp == 1, "Expect one getMeta op");
309
310     // test get_meta followed by delete for a deleted key. should fail.
311     wait_for_flusher_to_settle(h, h1);
312     check(get_meta(h, h1, key1), "Expected to get meta");
313     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
314     check(last_deleted_flag, "Expected deleted flag to be set");
315     checkeq(ENGINE_KEY_ENOENT, del(h, h1, key1, 0, 0), "Expected enoent");
316     // check the stat
317     temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
318     checkeq(2, temp, "Expect more getMeta op");
319
320     // test get_meta followed by delete for a nonexistent key. should fail.
321     check(!get_meta(h, h1, key2), "Expected get meta to return false");
322     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(), "Expected enoent");
323     checkeq(ENGINE_KEY_ENOENT, del(h, h1, key2, 0, 0), "Expected enoent");
324     // check the stat again
325     temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
326     checkeq(3, temp, "Expected one extra getMeta ops");
327
328     return SUCCESS;
329 }
330
331 static enum test_result test_add_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
332 {
333     const char *key = "mykey";
334     const size_t keylen = strlen(key);
335     ItemMetaData itemMeta;
336     size_t temp = 0;
337
338     // put some random metadata
339     itemMeta.revSeqno = 10;
340     itemMeta.cas = 0xdeadbeef;
341     itemMeta.exptime = 0;
342     itemMeta.flags = 0xdeadbeef;
343     // check the stat
344     temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
345     check(temp == 0, "Expect zero setMeta ops");
346
347     // store an item with meta data
348     add_with_meta(h, h1, key, keylen, NULL, 0, 0, &itemMeta);
349     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
350
351     // store the item again, expect key exists
352     add_with_meta(h, h1, key, keylen, NULL, 0, 0, &itemMeta, true);
353     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(),
354             "Expected add to fail when the item exists already");
355     // check the stat
356     temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
357     check(temp == 1, "Failed op does not count");
358
359     return SUCCESS;
360 }
361
362 static enum test_result test_delete_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
363
364     const char *key1 = "delete_with_meta_key1";
365     const char *key2 = "delete_with_meta_key2";
366     const char *key3 = "delete_with_meta_key3";
367     const size_t keylen = strlen(key1);
368     ItemMetaData itemMeta;
369     uint64_t vb_uuid;
370     uint32_t high_seqno;
371     // check the stat
372     size_t temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
373     check(temp == 0, "Expect zero setMeta ops");
374
375     // put some random meta data
376     itemMeta.revSeqno = 10;
377     itemMeta.cas = 0xdeadbeef;
378     itemMeta.exptime = 0;
379     itemMeta.flags = 0xdeadbeef;
380
381     // store an item
382     item *i = NULL;
383     checkeq(ENGINE_SUCCESS,
384             store(h, h1, NULL, OPERATION_SET, key1,
385                   "somevalue", &i),
386             "Failed set.");
387     h1->release(h, NULL, i);
388
389     checkeq(ENGINE_SUCCESS,
390             store(h, h1, NULL, OPERATION_SET, key2,
391                   "somevalue2", &i),
392             "Failed set.");
393     h1->release(h, NULL, i);
394
395     checkeq(ENGINE_SUCCESS,
396             store(h, h1, NULL, OPERATION_SET, key3,
397                   "somevalue3", &i), "Failed set.");
398     h1->release(h, NULL, i);
399
400     vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
401     high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
402
403     const void *cookie = testHarness.create_cookie();
404
405     // delete an item with meta data
406     del_with_meta(h, h1, key1, keylen, 0, &itemMeta, 0, false, false, cookie);
407
408     check(last_uuid == vb_uuid, "Expected valid vbucket uuid");
409     check(last_seqno == high_seqno + 1, "Expected valid sequence number");
410     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
411     // check the stat
412     temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
413     check(temp == 1, "Expect more setMeta ops");
414
415     testHarness.set_mutation_extras_handling(cookie, false);
416
417     // delete an item with meta data
418     del_with_meta(h, h1, key2, keylen, 0, &itemMeta, 0, false, false, cookie);
419
420     check(last_uuid == vb_uuid, "Expected same vbucket uuid");
421     check(last_seqno == high_seqno + 1, "Expected same sequence number");
422     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
423
424     // delete an item with meta data
425     del_with_meta(h, h1, key3, keylen, 0, &itemMeta);
426
427     check(last_uuid == vb_uuid, "Expected valid vbucket uuid");
428     check(last_seqno == high_seqno + 3, "Expected valid sequence number");
429     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
430
431     testHarness.destroy_cookie(cookie);
432     return SUCCESS;
433 }
434
435 static enum test_result test_delete_with_meta_deleted(ENGINE_HANDLE *h,
436                                                       ENGINE_HANDLE_V1 *h1) {
437     const char *key = "delete_with_meta_key";
438     const size_t keylen = strlen(key);
439     item *i = NULL;
440
441     // check the stat
442     checkeq(0, get_int_stat(h, h1, "ep_num_ops_del_meta"),
443             "Expect zero setMeta ops");
444
445     // add a key
446     checkeq(ENGINE_SUCCESS,
447             store(h, h1, NULL, OPERATION_SET, key, "somevalue", &i),
448             "Failed set.");
449     wait_for_flusher_to_settle(h, h1);
450
451     // delete the key
452     checkeq(ENGINE_SUCCESS, del(h, h1, key, 0, 0),
453             "Delete failed");
454     wait_for_flusher_to_settle(h, h1);
455     wait_for_stat_to_be(h, h1, "curr_items", 0);
456
457     // get metadata of deleted key
458     check(get_meta(h, h1, key), "Expected to get meta");
459     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
460             "Expected success");
461     check(last_deleted_flag, "Expected deleted flag to be set");
462     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
463     checkeq(1,get_int_stat(h, h1, "curr_temp_items"), "Expected single temp_items");
464
465     // this is the cas to be used with a subsequent delete with meta
466     uint64_t valid_cas = last_cas;
467     uint64_t invalid_cas = 2012;
468     // put some random metadata and delete the item with new meta data
469     ItemMetaData itm_meta;
470     itm_meta.revSeqno = 10;
471     itm_meta.cas = 0xdeadbeef;
472     itm_meta.exptime = 1735689600; // expires in 2025
473     itm_meta.flags = 0xdeadbeef;
474
475     // do delete with meta with an incorrect cas value. should fail.
476     del_with_meta(h, h1, key, keylen, 0, &itm_meta, invalid_cas);
477     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(),
478             "Expected invalid cas error");
479     checkeq(0, get_int_stat(h, h1, "ep_num_ops_del_meta"), "Faild ops does not count");
480     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
481     checkeq(1,get_int_stat(h, h1, "curr_temp_items"), "Expected single temp_items");
482
483     // do delete with meta with the correct cas value. should pass.
484     del_with_meta(h, h1, key, keylen, 0, &itm_meta, valid_cas);
485     wait_for_flusher_to_settle(h, h1);
486
487     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
488     checkeq(1, get_int_stat(h, h1, "ep_num_ops_del_meta"), "Expect some ops");
489     wait_for_stat_to_be(h, h1, "curr_items", 0);
490     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
491
492     // get metadata again to verify that delete with meta was successful
493     check(get_meta(h, h1, key), "Expected to get meta");
494     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
495     check(last_deleted_flag, "Expected deleted flag to be set");
496     check(itm_meta.revSeqno == last_meta.revSeqno, "Expected seqno to match");
497     check(itm_meta.cas == last_meta.cas, "Expected cas to match");
498     check(itm_meta.flags == last_meta.flags, "Expected flags to match");
499     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
500     checkeq(1, get_int_stat(h, h1, "curr_temp_items"), "Expected single temp_items");
501
502     h1->release(h, NULL, i);
503     return SUCCESS;
504 }
505
506 static enum test_result test_delete_with_meta_nonexistent(ENGINE_HANDLE *h,
507                                                           ENGINE_HANDLE_V1 *h1) {
508     const char *key = "delete_with_meta_key";
509     const size_t keylen = strlen(key);
510     ItemMetaData itm_meta;
511
512     // check the stat
513     checkeq(0, get_int_stat(h, h1, "ep_num_ops_del_meta"),
514             "Expect zero setMeta ops");
515
516     // get metadata of nonexistent key
517     check(!get_meta(h, h1, key), "Expected get meta to return false");
518     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(),
519             "Expected enoent");
520     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
521
522     // this is the cas to be used with a subsequent delete with meta
523     uint64_t valid_cas = last_cas;
524     uint64_t invalid_cas = 2012;
525
526     // do delete with meta
527     // put some random metadata and delete the item with new meta data
528     itm_meta.revSeqno = 10;
529     itm_meta.cas = 0xdeadbeef;
530     itm_meta.exptime = 1735689600; // expires in 2025
531     itm_meta.flags = 0xdeadbeef;
532
533     // do delete with meta with an incorrect cas value. should fail.
534     del_with_meta(h, h1, key, keylen, 0, &itm_meta, invalid_cas);
535     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(),
536             "Expected invalid cas error");
537     // check the stat
538     checkeq(0, get_int_stat(h, h1, "ep_num_ops_del_meta"), "Failed op does not count");
539     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
540     checkeq(1, get_int_stat(h, h1, "curr_temp_items"), "Expected single temp_items");
541
542     // do delete with meta with the correct cas value. should pass.
543     del_with_meta(h, h1, key, keylen, 0, &itm_meta, valid_cas);
544     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
545     wait_for_flusher_to_settle(h, h1);
546
547     // check the stat
548     checkeq(1, get_int_stat(h, h1, "ep_num_ops_del_meta"), "Expect one op");
549     wait_for_stat_to_be(h, h1, "curr_items", 0);
550     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
551
552     // get metadata again to verify that delete with meta was successful
553     check(get_meta(h, h1, key), "Expected to get meta");
554     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
555     check(last_deleted_flag, "Expected deleted flag to be set");
556     check(itm_meta.revSeqno == last_meta.revSeqno, "Expected seqno to match");
557     check(itm_meta.cas == last_meta.cas, "Expected cas to match");
558     check(itm_meta.flags == last_meta.flags, "Expected flags to match");
559     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
560     checkeq(1, get_int_stat(h, h1, "curr_temp_items"), "Expected single temp_items");
561
562     return SUCCESS;
563 }
564
565 static enum test_result test_delete_with_meta_nonexistent_no_temp(ENGINE_HANDLE *h,
566                                                                   ENGINE_HANDLE_V1 *h1) {
567     const char *key1 = "delete_with_meta_no_temp_key1";
568     const size_t keylen1 = strlen(key1);
569     ItemMetaData itm_meta1;
570
571     // Run compaction to start using the bloomfilter
572     useconds_t sleepTime = 128;
573     compact_db(h, h1, 0, 1, 1, 0);
574     while (get_int_stat(h, h1, "ep_pending_compactions") != 0) {
575         decayingSleep(&sleepTime);
576     }
577
578     // put some random metadata and delete the item with new meta data
579     itm_meta1.revSeqno = 10;
580     itm_meta1.cas = 0xdeadbeef;
581     itm_meta1.exptime = 1735689600; // expires in 2025
582     itm_meta1.flags = 0xdeadbeef;
583
584     // do delete with meta with the correct cas value.
585     // skipConflictResolution false
586     del_with_meta(h, h1, key1, keylen1, 0, &itm_meta1, 0, false);
587     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
588     wait_for_flusher_to_settle(h, h1);
589
590     checkeq(1, get_int_stat(h, h1, "ep_num_ops_del_meta"), "Expect one op");
591     wait_for_stat_to_be(h, h1, "curr_items", 0);
592     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
593
594     // do delete with meta with the correct cas value.
595     // skipConflictResolution true
596     const char *key2 = "delete_with_meta_no_temp_key2";
597     const size_t keylen2 = strlen(key2);
598     ItemMetaData itm_meta2;
599
600     // put some random metadata and delete the item with new meta data
601     itm_meta2.revSeqno = 10;
602     itm_meta2.cas = 0xdeadbeef;
603     itm_meta2.exptime = 1735689600; // expires in 2025
604     itm_meta2.flags = 0xdeadbeef;
605
606     del_with_meta(h, h1, key2, keylen2, 0, &itm_meta2, 0, true);
607     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
608     wait_for_flusher_to_settle(h, h1);
609
610     checkeq(2, get_int_stat(h, h1, "ep_num_ops_del_meta"), "Expect one op");
611     wait_for_stat_to_be(h, h1, "curr_items", 0);
612     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
613
614     return SUCCESS;
615 }
616
617 static enum test_result test_delete_with_meta_race_with_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
618 {
619     char const *key1 = "key1";
620     const size_t keylen1 = strlen(key1);
621
622     item *i = NULL;
623     ItemMetaData itm_meta;
624     itm_meta.revSeqno = 10;
625     itm_meta.cas = 0xdeadbeef;
626     itm_meta.exptime = 1735689600; // expires in 2025
627     itm_meta.flags = 0xdeadbeef;
628     // check the stat
629     size_t temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
630     check(temp == 0, "Expect zero ops");
631
632     //
633     // test race with a concurrent set for an existing key. should fail.
634     //
635
636     // create a new key and do get_meta
637     checkeq(ENGINE_SUCCESS,
638             store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
639             "Failed set.");
640     h1->release(h, NULL, i);
641     wait_for_flusher_to_settle(h, h1);
642     check(get_meta(h, h1, key1), "Expected to get meta");
643     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
644
645     // do a concurrent set that changes the cas
646     checkeq(ENGINE_SUCCESS,
647             store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
648             "Failed set.");
649     h1->release(h, NULL, i);
650
651     // attempt delete_with_meta. should fail since cas is no longer valid.
652     del_with_meta(h, h1, key1, keylen1, 0, &itm_meta, last_cas);
653     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(),
654           "Expected invalid cas error");
655     // check the stat
656     temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
657     check(temp == 0, "Failed op does not count");
658
659     //
660     // test race with a concurrent set for a deleted key. should fail.
661     //
662
663     // do get_meta for the deleted key
664     checkeq(ENGINE_SUCCESS, del(h, h1, key1, 0, 0), "Delete failed");
665     wait_for_flusher_to_settle(h, h1);
666
667     check(get_meta(h, h1, key1), "Expected to get meta");
668     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
669     check(last_deleted_flag, "Expected deleted flag to be set");
670
671     // do a concurrent set that changes the cas
672     checkeq(ENGINE_SUCCESS,
673             store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
674             "Failed set.");
675     h1->release(h, NULL, i);
676     del_with_meta(h, h1, key1, keylen1, 0, &itm_meta, last_cas);
677     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(),
678           "Expected invalid cas error");
679     // check the stat
680     temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
681     check(temp == 0, "Failed op does not count");
682
683     return SUCCESS;
684 }
685
686 static enum test_result test_delete_with_meta_race_with_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
687 {
688     char const *key1 = "key1";
689     uint16_t keylen1 = (uint16_t)strlen(key1);
690     char const *key2 = "key2";
691     uint16_t keylen2 = (uint16_t)strlen(key2);
692     item *i = NULL;
693     ItemMetaData itm_meta;
694     itm_meta.cas = 0x1;
695     // check the stat
696     size_t temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
697     check(temp == 0, "Expect zero ops");
698
699     //
700     // test race with a concurrent delete for an existing key. should fail.
701     //
702
703     // create a new key and do get_meta
704     checkeq(ENGINE_SUCCESS,
705             store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
706             "Failed set.");
707     wait_for_flusher_to_settle(h, h1);
708     check(get_meta(h, h1, key1), "Expected to get meta");
709     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
710
711     // do a concurrent delete
712     checkeq(ENGINE_SUCCESS, del(h, h1, key1, 0, 0), "Delete failed");
713
714     // attempt delete_with_meta. should fail since cas is no longer valid.
715     del_with_meta(h, h1, key1, keylen1, 0, &itm_meta, last_cas, true);
716     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(),
717           "Expected invalid cas error");
718     // check the stat
719     temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
720     check(temp == 0, "Failed op does not count");
721
722     //
723     // test race with a concurrent delete for a deleted key. should pass since
724     // the delete itself will fail.
725     //
726
727     // do get_meta for the deleted key
728     wait_for_flusher_to_settle(h, h1);
729     check(get_meta(h, h1, key1), "Expected to get meta");
730     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
731     check(last_deleted_flag, "Expected deleted flag to be set");
732
733     // do a concurrent delete
734     checkeq(ENGINE_KEY_ENOENT, del(h, h1, key1, 0, 0), "Delete failed");
735
736     // attempt delete_with_meta. should pass.
737     del_with_meta(h, h1, key1, keylen1, 0, &itm_meta, last_cas, true);
738     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
739           "Expected delete_with_meta success");
740     // check the stat
741     temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
742     check(temp == 1, "Expect some ops");
743
744     //
745     // test race with a concurrent delete for a nonexistent key. should pass
746     // since the delete itself will fail.
747     //
748
749     // do get_meta for a nonexisting key
750     check(!get_meta(h, h1, key2), "Expected get meta to return false");
751     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(), "Expected enoent");
752
753     // do a concurrent delete
754     checkeq(ENGINE_KEY_ENOENT, del(h, h1, key1, 0, 0), "Delete failed");
755
756     // attempt delete_with_meta. should pass.
757     del_with_meta(h, h1, key2, keylen2, 0, &itm_meta, last_cas, true);
758     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
759           "Expected delete_with_meta success");
760     // check the stat
761     temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
762     check(temp == 2, "Expect some ops");
763
764     h1->release(h, NULL, i);
765     return SUCCESS;
766 }
767
768 static enum test_result test_set_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
769     const char* key = "set_with_meta_key";
770     size_t keylen = strlen(key);
771     const char* val = "somevalue";
772     const char* newVal = "someothervalue";
773     size_t newValLen = strlen(newVal);
774     uint64_t vb_uuid;
775     uint32_t high_seqno;
776
777     // check the stat
778     checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Expect zero ops");
779     checkeq(0, get_int_stat(h, h1, "ep_num_ops_get_meta_on_set_meta"),
780             "Expect zero ops");
781     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expect zero items");
782     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expect zero temp items");
783
784     // create a new key
785     item *i = NULL;
786     checkeq(ENGINE_SUCCESS,
787             store(h, h1, NULL, OPERATION_SET, key, val, &i),
788             "Failed set.");
789
790     // get metadata for the key
791     check(get_meta(h, h1, key), "Expected to get meta");
792     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
793     checkeq(1, get_int_stat(h, h1, "curr_items"), "Expect one item");
794     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expect zero temp item");
795
796     // this is the cas to be used with a subsequent set with meta
797     uint64_t cas_for_set = last_cas;
798     // init some random metadata
799     ItemMetaData itm_meta;
800     itm_meta.revSeqno = 10;
801     itm_meta.cas = 0xdeadbeef;
802     itm_meta.exptime = time(NULL) + 300;
803     itm_meta.flags = 0xdeadbeef;
804
805     char *bigValue = new char[32*1024*1024];
806     // do set with meta with the value size bigger than the max size allowed.
807     set_with_meta(h, h1, key, keylen, bigValue, 32*1024*1024, 0, &itm_meta, cas_for_set);
808     checkeq(PROTOCOL_BINARY_RESPONSE_E2BIG, last_status.load(),
809           "Expected the max value size exceeding error");
810     delete []bigValue;
811
812     // do set with meta with an incorrect cas value. should fail.
813     set_with_meta(h, h1, key, keylen, newVal, newValLen, 0, &itm_meta, 1229);
814     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(),
815           "Expected invalid cas error");
816     // check the stat
817     checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Failed op does not count");
818
819     vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
820     high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
821
822     const void *cookie = testHarness.create_cookie();
823
824     // do set with meta with the correct cas value. should pass.
825     set_with_meta(h, h1, key, keylen, newVal, newValLen, 0, &itm_meta, cas_for_set,
826                   false, 0, false, cookie);
827     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
828     check(last_uuid == vb_uuid, "Expected valid vbucket uuid");
829     check(last_seqno == high_seqno + 1, "Expected valid sequence number");
830
831     // check the stat
832     checkeq(1, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Expect some ops");
833     checkeq(1, get_int_stat(h, h1, "curr_items"), "Expect one item");
834     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expect zero temp item");
835
836     // get metadata again to verify that set with meta was successful
837     check(get_meta(h, h1, key), "Expected to get meta");
838     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
839     check(last_meta.revSeqno == 10, "Expected seqno to match");
840     check(last_meta.cas == 0xdeadbeef, "Expected cas to match");
841     check(last_meta.flags == 0xdeadbeef, "Expected flags to match");
842
843     //disable getting vb uuid and seqno as extras
844     testHarness.set_mutation_extras_handling(cookie, false);
845     itm_meta.revSeqno++;
846     cas_for_set = last_meta.cas;
847     set_with_meta(h, h1, key, keylen, newVal, newValLen, 0, &itm_meta, cas_for_set,
848                   false, 0, false, cookie);
849     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
850     check(last_uuid == vb_uuid, "Expected same vbucket uuid");
851     check(last_seqno == high_seqno + 1, "Expected same sequence number");
852
853     itm_meta.revSeqno++;
854     cas_for_set = last_meta.cas;
855     set_with_meta(h, h1, key, keylen, newVal, newValLen, 0, &itm_meta, cas_for_set);
856     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
857     check(last_uuid == vb_uuid, "Expected valid vbucket uuid");
858     check(last_seqno == high_seqno + 3, "Expected valid sequence number");
859
860     // Make sure the item expiration was processed correctly
861     testHarness.time_travel(301);
862     checkeq(ENGINE_KEY_ENOENT, h1->get(h, NULL, &i, key, keylen, 0),
863             "Failed to get value.");
864
865     h1->release(h, NULL, i);
866     testHarness.destroy_cookie(cookie);
867     return SUCCESS;
868 }
869
870 static enum test_result test_set_with_meta_by_force(ENGINE_HANDLE *h,
871                                                     ENGINE_HANDLE_V1 *h1) {
872     const char* key = "set_with_meta_key";
873     size_t keylen = strlen(key);
874     const char* val = "somevalue";
875
876     // init some random metadata
877     ItemMetaData itm_meta;
878     itm_meta.revSeqno = 10;
879     itm_meta.cas = 0xdeadbeef;
880     itm_meta.exptime = time(NULL) + 300;
881     itm_meta.flags = 0xdeadbeef;
882
883     // Pass true to force SetWithMeta.
884     set_with_meta(h, h1, key, keylen, val, strlen(val), 0, &itm_meta,
885                   0, true);
886     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
887     wait_for_flusher_to_settle(h, h1);
888
889     // get metadata again to verify that the warmup loads an item correctly.
890     check(get_meta(h, h1, key), "Expected to get meta");
891     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
892     check(last_meta.revSeqno == 10, "Expected seqno to match");
893     check(last_meta.cas == 0xdeadbeef, "Expected cas to match");
894     check(last_meta.flags == 0xdeadbeef, "Expected flags to match");
895
896     check_key_value(h, h1, key, val, strlen(val));
897
898     return SUCCESS;
899 }
900
901 static enum test_result test_set_with_meta_deleted(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
902     const char* key = "set_with_meta_key";
903     size_t keylen = strlen(key);
904     const char* val = "somevalue";
905     const char* newVal = "someothervalue";
906     uint16_t newValLen = (uint16_t)strlen(newVal);
907
908     // check the stat
909     checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Expect zero ops");
910     checkeq(0, get_int_stat(h, h1, "ep_num_ops_get_meta_on_set_meta"),
911             "Expect zero ops");
912
913     // create a new key
914     item *i = NULL;
915     checkeq(ENGINE_SUCCESS,
916             store(h, h1, NULL, OPERATION_SET, key, val, &i),
917             "Failed set.");
918     wait_for_flusher_to_settle(h, h1);
919     checkeq(1, get_int_stat(h, h1, "curr_items"), "Expected single curr_items");
920     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
921
922     // delete the key
923     checkeq(ENGINE_SUCCESS, del(h, h1, key, 0, 0), "Delete failed");
924     wait_for_flusher_to_settle(h, h1);
925     wait_for_stat_to_be(h, h1, "curr_items", 0);
926
927     // get metadata for the key
928     check(get_meta(h, h1, key), "Expected to get meta");
929     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
930     check(last_deleted_flag, "Expected deleted flag to be set");
931     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
932     checkeq(1, get_int_stat(h, h1, "curr_temp_items"), "Expected single temp_items");
933
934     // this is the cas to be used with a subsequent set with meta
935     uint64_t cas_for_set = last_cas;
936     // init some random metadata
937     ItemMetaData itm_meta;
938     itm_meta.revSeqno = 10;
939     itm_meta.cas = 0xdeadbeef;
940     itm_meta.exptime = 1735689600; // expires in 2025
941     itm_meta.flags = 0xdeadbeef;
942
943     // do set_with_meta with an incorrect cas for a deleted item. should fail.
944     set_with_meta(h, h1, key, keylen, newVal, newValLen, 0, &itm_meta, 1229);
945     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(),
946           "Expected key_not_found error");
947     // check the stat
948     checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Failed op does not count");
949     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
950     checkeq(1, get_int_stat(h, h1, "curr_temp_items"), "Expected single temp_items");
951
952     // do set with meta with the correct cas value. should pass.
953     set_with_meta(h, h1, key, keylen, newVal, newValLen, 0, &itm_meta, cas_for_set);
954     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
955     // check the stat
956     checkeq(1, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Expect some ops");
957     checkeq(0, get_int_stat(h, h1, "ep_num_ops_get_meta_on_set_meta"),
958             "Expect some ops");
959     checkeq(1, get_int_stat(h, h1, "curr_items"), "Expected single curr_items");
960     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
961
962     // get metadata again to verify that set with meta was successful
963     check(get_meta(h, h1, key), "Expected to get meta");
964     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
965     ItemMetaData metadata(0xdeadbeef, 10, 0xdeadbeef, 1735689600);
966     verifyLastMetaData(metadata);
967     checkeq(1, get_int_stat(h, h1, "curr_items"), "Expected single curr_items");
968     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
969
970     h1->release(h, NULL, i);
971     return SUCCESS;
972 }
973
974 static enum test_result test_set_with_meta_nonexistent(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
975     const char* key = "set_with_meta_key";
976     size_t keylen = strlen(key);
977     const char* val = "somevalue";
978     size_t valLen = strlen(val);
979
980     // check the stat
981     checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Expect zero ops");
982
983     // get metadata for the key
984     check(!get_meta(h, h1, key), "Expected get meta to return false");
985     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(), "Expected enoent");
986     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
987
988     // this is the cas to be used with a subsequent set with meta
989     uint64_t cas_for_set = last_cas;
990     // init some random metadata
991     ItemMetaData itm_meta;
992     itm_meta.revSeqno = 10;
993     itm_meta.cas = 0xdeadbeef;
994     itm_meta.exptime = 1735689600; // expires in 2025
995     itm_meta.flags = 0xdeadbeef;
996
997     // do set_with_meta with an incorrect cas for a non-existent item. should fail.
998     set_with_meta(h, h1, key, keylen, val, valLen, 0, &itm_meta, 1229);
999     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(),
1000           "Expected key_not_found error");
1001     // check the stat
1002     checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Failed op does not count");
1003     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
1004
1005     // do set with meta with the correct cas value. should pass.
1006     set_with_meta(h, h1, key, keylen, val, valLen, 0, &itm_meta, cas_for_set);
1007     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1008     // check the stat
1009     checkeq(1, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Expect some ops");
1010     checkeq(1, get_int_stat(h, h1, "curr_items"), "Expected single curr_items");
1011     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
1012
1013     // get metadata again to verify that set with meta was successful
1014     check(get_meta(h, h1, key), "Expected to get meta");
1015     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1016     ItemMetaData metadata(0xdeadbeef, 10, 0xdeadbeef, 1735689600);
1017     verifyLastMetaData(metadata);
1018     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
1019     checkeq(1, get_int_stat(h, h1, "curr_items"), "Expected single curr_items");
1020
1021     return SUCCESS;
1022 }
1023
1024 static enum test_result test_set_with_meta_race_with_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
1025 {
1026     char const *key1 = "key1";
1027     size_t keylen1 = strlen(key1);
1028     item *i = NULL;
1029     // check the stat
1030     size_t temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1031     check(temp == 0, "Expect zero ops");
1032
1033     //
1034     // test race with a concurrent set for an existing key. should fail.
1035     //
1036
1037     // create a new key and do get_meta
1038     checkeq(ENGINE_SUCCESS,
1039             store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
1040             "Failed set.");
1041     h1->release(h, NULL, i);
1042     wait_for_flusher_to_settle(h, h1);
1043     check(get_meta(h, h1, key1), "Expected to get meta");
1044     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1045
1046     // do a concurrent set that changes the cas
1047     checkeq(ENGINE_SUCCESS,
1048             store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
1049             "Failed set.");
1050     h1->release(h, NULL, i);
1051
1052     // attempt set_with_meta. should fail since cas is no longer valid.
1053     last_meta.revSeqno += 2;
1054     set_with_meta(h, h1, key1, keylen1, NULL, 0, 0, &last_meta, last_cas);
1055     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(),
1056           "Expected invalid cas error");
1057     // check the stat
1058     temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1059     check(temp == 0, "Failed op does not count");
1060
1061     //
1062     // test race with a concurrent set for a deleted key. should fail.
1063     //
1064
1065     // do get_meta for the deleted key
1066     checkeq(ENGINE_SUCCESS, del(h, h1, key1, 0, 0), "Delete failed");
1067     wait_for_flusher_to_settle(h, h1);
1068     check(get_meta(h, h1, key1), "Expected to get meta");
1069     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1070     check(last_deleted_flag, "Expected deleted flag to be set");
1071
1072     // do a concurrent set that changes the cas
1073     checkeq(ENGINE_SUCCESS,
1074             store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
1075             "Failed set.");
1076     h1->release(h, NULL, i);
1077
1078     // attempt set_with_meta. should fail since cas is no longer valid.
1079     last_meta.revSeqno += 2;
1080     set_with_meta(h, h1, key1, keylen1, NULL, 0, 0, &last_meta, last_cas);
1081     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(),
1082           "Expected invalid cas error");
1083     // check the stat
1084     temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1085     check(temp == 0, "Failed op does not count");
1086
1087     return SUCCESS;
1088 }
1089
1090 static enum test_result test_set_with_meta_race_with_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
1091 {
1092     char const *key1 = "key1";
1093     size_t keylen1 = strlen(key1);
1094     char const *key2 = "key2";
1095     size_t keylen2 = strlen(key2);
1096     item *i = NULL;
1097     // check the stat
1098     size_t temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1099     check(temp == 0, "Expect zero op");
1100
1101     //
1102     // test race with a concurrent delete for an existing key. should fail.
1103     //
1104
1105     // create a new key and do get_meta
1106     checkeq(ENGINE_SUCCESS,
1107             store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
1108             "Failed set.");
1109     wait_for_flusher_to_settle(h, h1);
1110     check(get_meta(h, h1, key1), "Expected to get meta");
1111     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1112
1113     // do a concurrent delete that changes the cas
1114     checkeq(ENGINE_SUCCESS, del(h, h1, key1, 0, 0), "Delete failed");
1115
1116     // attempt set_with_meta. should fail since cas is no longer valid.
1117     set_with_meta(h, h1, key1, keylen1, NULL, 0, 0, &last_meta, last_cas, true);
1118
1119     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(),
1120             (std::string{"Expected invalid cas error (KEY_EXISTS or"
1121                          " KEY_ENOENT), got: "} +
1122              std::to_string(last_status.load())).c_str());
1123
1124     // check the stat
1125     temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1126     check(temp == 0, "Expect zero op");
1127
1128     //
1129     // test race with a concurrent delete for a deleted key. should pass since
1130     // the delete will fail.
1131     //
1132
1133     // do get_meta for the deleted key
1134     wait_for_flusher_to_settle(h, h1);
1135     check(get_meta(h, h1, key1), "Expected to get meta");
1136     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1137     check(last_deleted_flag, "Expected deleted flag to be set");
1138
1139     // do a concurrent delete. should fail.
1140     checkeq(ENGINE_KEY_ENOENT, del(h, h1, key1, 0, 0), "Delete failed");
1141
1142     // attempt set_with_meta. should pass since cas is still valid.
1143     set_with_meta(h, h1, key1, keylen1, NULL, 0, 0, &last_meta, last_cas, true);
1144     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1145     // check the stat
1146     temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1147     check(temp == 1, "Expect some op");
1148
1149     //
1150     // test race with a concurrent delete for a nonexistent key. should pass
1151     // since the delete will fail.
1152     //
1153
1154     // do get_meta for a nonexisting key
1155     check(!get_meta(h, h1, key2), "Expected get meta to return false");
1156     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(), "Expected enoent");
1157
1158     // do a concurrent delete. should fail.
1159     checkeq(ENGINE_KEY_ENOENT, del(h, h1, key2, 0, 0), "Delete failed");
1160
1161     // attempt set_with_meta. should pass since cas is still valid.
1162     set_with_meta(h, h1, key2, keylen2, NULL, 0, 0, &last_meta, last_cas, true);
1163     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1164     // check the stat
1165     temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1166     check(temp == 2, "Expect some ops");
1167
1168     h1->release(h, NULL, i);
1169     return SUCCESS;
1170 }
1171
1172 static enum test_result test_exp_persisted_set_del(ENGINE_HANDLE *h,
1173                                                    ENGINE_HANDLE_V1 *h1) {
1174     check(!get_meta(h, h1, "key3"), "Expected to get meta");
1175
1176     ItemMetaData itm_meta;
1177     itm_meta.revSeqno = 1;
1178     itm_meta.cas = 1;
1179     itm_meta.exptime = 0;
1180     itm_meta.flags = 0;
1181     set_with_meta(h, h1, "key3", 4, "val0", 4, 0, &itm_meta, last_meta.cas);
1182
1183     itm_meta.revSeqno = 2;
1184     itm_meta.cas = 2;
1185     set_with_meta(h, h1, "key3", 4, "val1", 4, 0, &itm_meta, last_meta.cas);
1186     wait_for_stat_to_be(h, h1, "ep_total_persisted", 1);
1187
1188     itm_meta.revSeqno = 3;
1189     itm_meta.cas = 3;
1190     itm_meta.exptime = 1735689600; // expires in 2025
1191     set_with_meta(h, h1, "key3", 4, "val1", 4, 0, &itm_meta, last_meta.cas);
1192
1193     testHarness.time_travel(500000000);
1194     // Wait for the item to be expired, either by the pager,
1195     // or by access (as part of persistence callback from a
1196     // previous set - slow disk), or the compactor (unlikely).
1197     wait_for_expired_items_to_be(h, h1, 1);
1198
1199     wait_for_flusher_to_settle(h, h1);
1200     wait_for_stat_to_be(h, h1, "curr_items", 0);
1201
1202     check(get_meta(h, h1, "key3"), "Expected to get meta");
1203     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1204     check(last_meta.revSeqno == 4, "Expected seqno to match");
1205     check(last_meta.cas != 3, "Expected cas to be different");
1206     check(last_meta.flags == 0, "Expected flags to match");
1207
1208     return SUCCESS;
1209 }
1210
1211 static enum test_result test_temp_item_deletion(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
1212 {
1213     // Do get_meta for an existing key
1214     char const *k1 = "k1";
1215     item *i = NULL;
1216
1217     checkeq(ENGINE_SUCCESS,
1218             store(h, h1, NULL, OPERATION_SET, k1, "somevalue", &i),
1219             "Failed set.");
1220     wait_for_flusher_to_settle(h, h1);
1221
1222     checkeq(ENGINE_SUCCESS, del(h, h1, k1, 0, 0), "Delete failed");
1223     wait_for_flusher_to_settle(h, h1);
1224     wait_for_stat_to_be(h, h1, "curr_items", 0);
1225
1226     // Issue a get_meta for a deleted key. This will need to bring in a temp
1227     // item into the hashtable as a placeholder for the (deleted) metadata
1228     // which needs to be loaded from disk via BG fetch
1229     // We need to temporarily disable the reader threads as to prevent the
1230     // BGfetch from immediately running and removing our temp_item before
1231     // we've had chance to validate its existence.
1232     set_param(h, h1, protocol_binary_engine_param_flush,
1233               "max_num_readers", "0");
1234
1235     // Tell the harness not to handle EWOULDBLOCK for us - we want it to
1236     // be outstanding while we check the below stats.
1237     const void *cookie = testHarness.create_cookie();
1238     testHarness.set_ewouldblock_handling(cookie, false);
1239
1240     checkeq(false, get_meta(h, h1, k1, /*reqExtMeta*/false, cookie),
1241             "Expected get_meta to fail (EWOULDBLOCK)");
1242     checkeq(static_cast<protocol_binary_response_status>(ENGINE_EWOULDBLOCK),
1243             last_status.load(), "Expected EWOULDBLOCK");
1244
1245     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
1246     checkeq(1, get_int_stat(h, h1, "curr_temp_items"), "Expected single temp_items");
1247
1248     // Re-enable EWOULDBLOCK handling (and reader threads), and re-issue.
1249     testHarness.set_ewouldblock_handling(cookie, true);
1250     set_param(h, h1, protocol_binary_engine_param_flush,
1251               "max_num_readers", "1");
1252
1253     check(get_meta(h, h1, k1, /*reqExtMeta*/false, cookie),
1254           "Expected get_meta to succeed");
1255     check(last_deleted_flag, "Expected deleted flag to be set");
1256
1257     // Do get_meta for a non-existing key.
1258     char const *k2 = "k2";
1259     check(!get_meta(h, h1, k2), "Expected get meta to return false");
1260     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, last_status.load(), "Expected enoent");
1261
1262     // Trigger the expiry pager and verify that two temp items are deleted
1263     wait_for_stat_to_be(h, h1, "ep_expired_pager", 1);
1264     checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
1265     checkeq(0, get_int_stat(h, h1, "curr_temp_items"), "Expected zero temp_items");
1266
1267     h1->release(h, NULL, i);
1268     testHarness.destroy_cookie(cookie);
1269
1270     return SUCCESS;
1271 }
1272
1273 static enum test_result test_add_meta_conflict_resolution(ENGINE_HANDLE *h,
1274                                                           ENGINE_HANDLE_V1 *h1) {
1275     // put some random metadata
1276     ItemMetaData itemMeta;
1277     itemMeta.revSeqno = 10;
1278     itemMeta.cas = 0xdeadbeef;
1279     itemMeta.exptime = 0;
1280     itemMeta.flags = 0xdeadbeef;
1281
1282     add_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta);
1283     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1284     checkeq(0, get_int_stat(h, h1, "ep_bg_meta_fetched"),
1285             "Expected no bg meta fetches, thanks to bloom filters");
1286
1287     checkeq(ENGINE_SUCCESS, del(h, h1, "key", 0, 0), "Delete failed");
1288     wait_for_flusher_to_settle(h, h1);
1289     wait_for_stat_to_be(h, h1, "curr_items", 0);
1290
1291     // Check all meta data is the same
1292     itemMeta.revSeqno++;
1293     itemMeta.cas++;
1294     add_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta);
1295     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1296     checkeq(1, get_int_stat(h, h1, "ep_bg_meta_fetched"),
1297           "Expected two be meta fetches");
1298     checkeq(1, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1299           "Expected set meta conflict resolution failure");
1300
1301     // Check has older flags fails
1302     itemMeta.flags = 0xdeadbeee;
1303     add_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta);
1304     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1305     checkeq(2, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1306           "Expected set meta conflict resolution failure");
1307
1308     // Check testing with old seqno
1309     itemMeta.revSeqno--;
1310     add_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta);
1311     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1312     checkeq(3, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1313           "Expected set meta conflict resolution failure");
1314
1315     itemMeta.revSeqno += 10;
1316     add_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta);
1317     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1318     checkeq(3, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1319           "Expected set meta conflict resolution failure");
1320
1321     return SUCCESS;
1322 }
1323
1324 static enum test_result test_set_meta_conflict_resolution(ENGINE_HANDLE *h,
1325                                                           ENGINE_HANDLE_V1 *h1) {
1326     // put some random metadata
1327     ItemMetaData itemMeta;
1328     itemMeta.revSeqno = 10;
1329     itemMeta.cas = 0xdeadbeef;
1330     itemMeta.exptime = 0;
1331     itemMeta.flags = 0xdeadbeef;
1332
1333     checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"),
1334           "Expect zero setMeta ops");
1335
1336     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0);
1337     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1338     checkeq(0, get_int_stat(h, h1, "ep_bg_meta_fetched"),
1339             "Expected no bg meta fetches, thanks to bloom filters");
1340
1341     // Check all meta data is the same
1342     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0);
1343     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1344     checkeq(1, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1345           "Expected set meta conflict resolution failure");
1346
1347     // Check has older flags fails
1348     itemMeta.flags = 0xdeadbeee;
1349     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0);
1350     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1351     checkeq(2, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1352           "Expected set meta conflict resolution failure");
1353
1354     // Check has newer flags passes
1355     itemMeta.flags = 0xdeadbeff;
1356     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0);
1357     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1358
1359     // Check that newer exptime wins
1360     itemMeta.exptime = time(NULL) + 10;
1361     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0);
1362     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1363
1364     // Check that smaller exptime loses
1365     itemMeta.exptime = 0;
1366     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0);
1367     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1368     checkeq(3, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1369           "Expected set meta conflict resolution failure");
1370
1371     // Check testing with old seqno
1372     itemMeta.revSeqno--;
1373     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0);
1374     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1375     checkeq(4, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1376           "Expected set meta conflict resolution failure");
1377
1378     itemMeta.revSeqno += 10;
1379     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0);
1380     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1381     checkeq(4, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1382           "Expected set meta conflict resolution failure");
1383
1384     checkeq(0, get_int_stat(h, h1, "ep_bg_meta_fetched"),
1385             "Expect no bg meta fetches");
1386
1387     return SUCCESS;
1388 }
1389
1390 static enum test_result test_set_meta_lww_conflict_resolution(ENGINE_HANDLE *h,
1391                                                               ENGINE_HANDLE_V1 *h1) {
1392     // put some random metadata
1393     ItemMetaData itemMeta;
1394     itemMeta.revSeqno = 10;
1395     itemMeta.cas = 0xdeadbeef;
1396     itemMeta.exptime = 0;
1397     itemMeta.flags = 0xdeadbeef;
1398
1399     checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"),
1400           "Expect zero setMeta ops");
1401
1402     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0, false,
1403                   PROTOCOL_BINARY_RAW_BYTES, false);
1404     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1405     checkeq(0, get_int_stat(h, h1, "ep_bg_meta_fetched"),
1406             "Expected no bg meta fetchs, thanks to bloom filters");
1407
1408     // Check all meta data is the same
1409     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0, false,
1410                   PROTOCOL_BINARY_RAW_BYTES, false);
1411     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1412     checkeq(1, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1413           "Expected set meta conflict resolution failure");
1414
1415     // Check that an older cas fails
1416     itemMeta.cas = 0xdeadbeee;
1417     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0, false,
1418                   PROTOCOL_BINARY_RAW_BYTES, false);
1419     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1420     checkeq(2, get_int_stat(h, h1, "ep_num_ops_set_meta_res_fail"),
1421           "Expected set meta conflict resolution failure");
1422
1423     // Check that a higher cas passes
1424     itemMeta.cas = 0xdeadbeff;
1425     set_with_meta(h, h1, "key", 3, NULL, 0, 0, &itemMeta, 0, false,
1426                   PROTOCOL_BINARY_RAW_BYTES, false);
1427     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1428
1429     return SUCCESS;
1430 }
1431
1432 static enum test_result test_del_meta_conflict_resolution(ENGINE_HANDLE *h,
1433                                                           ENGINE_HANDLE_V1 *h1) {
1434
1435     item *i = NULL;
1436     checkeq(ENGINE_SUCCESS,
1437             store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1438             "Failed set.");
1439     wait_for_flusher_to_settle(h, h1);
1440     h1->release(h, NULL, i);
1441
1442     // put some random metadata
1443     ItemMetaData itemMeta;
1444     itemMeta.revSeqno = 10;
1445     itemMeta.cas = 0xdeadbeef;
1446     itemMeta.exptime = 0;
1447     itemMeta.flags = 0xdeadbeef;
1448
1449     del_with_meta(h, h1, "key", 3, 0, &itemMeta);
1450     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1451     wait_for_flusher_to_settle(h, h1);
1452     wait_for_stat_to_be(h, h1, "curr_items", 0);
1453
1454     // Check all meta data is the same
1455     del_with_meta(h, h1, "key", 3, 0, &itemMeta);
1456     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1457     checkeq(1, get_int_stat(h, h1, "ep_num_ops_del_meta_res_fail"),
1458           "Expected delete meta conflict resolution failure");
1459
1460     // Check has older flags fails
1461     itemMeta.flags = 0xdeadbeee;
1462     del_with_meta(h, h1, "key", 3, 0, &itemMeta);
1463     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1464     checkeq(2, get_int_stat(h, h1, "ep_num_ops_del_meta_res_fail"),
1465           "Expected delete meta conflict resolution failure");
1466
1467     // Check that smaller exptime loses
1468     itemMeta.exptime = 0;
1469     del_with_meta(h, h1, "key", 3, 0, &itemMeta);
1470     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1471     checkeq(3, get_int_stat(h, h1, "ep_num_ops_del_meta_res_fail"),
1472           "Expected delete meta conflict resolution failure");
1473
1474     // Check testing with old seqno
1475     itemMeta.revSeqno--;
1476     del_with_meta(h, h1, "key", 3, 0, &itemMeta);
1477     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1478     check(get_int_stat(h, h1, "ep_num_ops_del_meta_res_fail") == 4,
1479           "Expected delete meta conflict resolution failure");
1480
1481     itemMeta.revSeqno += 10;
1482     del_with_meta(h, h1, "key", 3, 0, &itemMeta);
1483     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1484     check(get_int_stat(h, h1, "ep_num_ops_del_meta_res_fail") == 4,
1485           "Expected delete meta conflict resolution failure");
1486
1487     return SUCCESS;
1488 }
1489
1490 static enum test_result test_del_meta_lww_conflict_resolution(ENGINE_HANDLE *h,
1491                                                               ENGINE_HANDLE_V1 *h1) {
1492
1493     item *i = NULL;
1494     item_info info;
1495
1496     checkeq(ENGINE_SUCCESS,
1497             store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1498             "Failed set.");
1499
1500     info.nvalue = 1;
1501     h1->get_item_info(h, NULL, i, &info);
1502     wait_for_flusher_to_settle(h, h1);
1503     h1->release(h, NULL, i);
1504
1505     // put some random metadata
1506     ItemMetaData itemMeta;
1507     itemMeta.revSeqno = 10;
1508     itemMeta.cas = info.cas + 1;
1509     itemMeta.exptime = 0;
1510     itemMeta.flags = 0xdeadbeef;
1511
1512     del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, false, true);
1513     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1514     wait_for_flusher_to_settle(h, h1);
1515     wait_for_stat_to_be(h, h1, "curr_items", 0);
1516
1517     // Check all meta data is the same
1518     del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, false, true);
1519     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1520     checkeq(1, get_int_stat(h, h1, "ep_num_ops_del_meta_res_fail"),
1521           "Expected delete meta conflict resolution failure");
1522
1523     // Check that higher rev seqno but lower cas fails
1524     itemMeta.cas = info.cas;
1525     itemMeta.revSeqno = 11;
1526     del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, false, true);
1527     checkeq(PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, last_status.load(), "Expected exists");
1528     checkeq(2, get_int_stat(h, h1, "ep_num_ops_del_meta_res_fail"),
1529           "Expected delete meta conflict resolution failure");
1530
1531     // Check that a higher cas and lower rev seqno passes
1532     itemMeta.cas = info.cas + 2;
1533     itemMeta.revSeqno = 9;
1534     del_with_meta(h, h1, "key", 3, 0, &itemMeta, 0, false, true);
1535     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected sucess");
1536
1537     return SUCCESS;
1538 }
1539
1540 static enum test_result test_getMeta_with_item_eviction(ENGINE_HANDLE *h,
1541                                                         ENGINE_HANDLE_V1 *h1)
1542 {
1543     char const *key = "test_get_meta";
1544     item *i = NULL;
1545     checkeq(ENGINE_SUCCESS,
1546             store(h, h1, NULL, OPERATION_SET, key, "somevalue", &i),
1547             "Failed set.");
1548     wait_for_flusher_to_settle(h, h1);
1549     evict_key(h, h1, key, 0, "Ejected.");
1550
1551     Item *it = reinterpret_cast<Item*>(i);
1552
1553     check(get_meta(h, h1, key), "Expected to get meta");
1554     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
1555     ItemMetaData metadata(it->getCas(), it->getRevSeqno(),
1556                           it->getFlags(), it->getExptime());
1557     verifyLastMetaData(metadata);
1558
1559     h1->release(h, NULL, i);
1560     return SUCCESS;
1561 }
1562
1563 static enum test_result test_set_with_meta_and_check_drift_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1564     // Activate n vbuckets (vb 0 is already)
1565     const int n_vbuckets = 10;
1566     for (int ii = 1; ii < n_vbuckets; ii++) {
1567         check(set_vbucket_state(h, h1, ii, vbucket_state_active),
1568               "Failed to set vbucket state.");
1569     }
1570
1571     // Let's make vbucket n/2 be the one who is ahead, n/3 is behind
1572     const int aheadVb = n_vbuckets/2;
1573     const int behindVb = n_vbuckets/3;
1574     checkne(aheadVb, behindVb, "Cannot have the same VB as ahead/behind");
1575
1576     HLC hlc(0/*init HLC*/,
1577             std::chrono::microseconds(0)/*ahead threshold*/,
1578             std::chrono::microseconds(0)/*behind threshold*/);
1579
1580     // grab the drift behind threshold
1581     uint64_t driftBehindThreshold = get_ull_stat(h, h1,
1582                                                  "ep_hlc_ahead_threshold_us",
1583                                                  nullptr);
1584     // Create n keys
1585     const int n_keys = 5;
1586     for (int ii = 0 ; ii < n_vbuckets; ii++) {
1587         for (int k = 0; k < n_keys; k++) {
1588             std::string key = "key_" + std::to_string(k);
1589             ItemMetaData itm_meta;
1590             itm_meta.cas = hlc.nextHLC();
1591             if (ii == aheadVb) {
1592                 // Push this guy *far* ahead (1 year)
1593                 itm_meta.cas += 3154E10;
1594             } else if(ii == behindVb) {
1595                 // just be sure it was already greater then 1 + driftthreshold
1596                 checkge(itm_meta.cas, uint64_t(1) + driftBehindThreshold,
1597                         "HLC was already zero");
1598                 // set to be way way behind...
1599                 itm_meta.cas = 1;
1600             }
1601             set_with_meta(h, h1, key.data(), key.size(), NULL, 0, ii, &itm_meta,
1602                           0, false, PROTOCOL_BINARY_RAW_BYTES, true, 0);
1603             checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
1604                     "Expected success");
1605         }
1606     }
1607
1608     // Bucket stats should report drift
1609     checkge(get_ull_stat(h, h1, "ep_active_hlc_drift"), uint64_t(0),
1610             "Expected drift above zero");
1611     checkeq(uint64_t(n_keys*n_vbuckets), get_ull_stat(h, h1, "ep_active_hlc_drift_count"),
1612             "Expected ahead counter to match mutations");
1613
1614     // Victim VBs should have exceptions
1615     {
1616         std::string vbAheadName = "vb_" + std::to_string(aheadVb);
1617         std::string ahead_threshold_exceeded = vbAheadName + ":drift_ahead_threshold_exceeded";
1618         std::string behind_threshold_exceeded = vbAheadName + ":drift_behind_threshold_exceeded";
1619         std::string total_abs_drift = vbAheadName + ":total_abs_drift";
1620         std::string details = "vbucket-details " + std::to_string(aheadVb);
1621             checkeq(uint64_t(n_keys), get_ull_stat(h, h1, ahead_threshold_exceeded.data(), details.data()),
1622                 "Expected ahead threshold to match mutations");
1623         checkeq(uint64_t(0), get_ull_stat(h, h1, behind_threshold_exceeded.data(), details.data()),
1624                 "Expected no behind exceptions");
1625         checkge(get_ull_stat(h, h1, total_abs_drift.data(), details.data()), uint64_t(0),
1626                 "Expected some drift");
1627     }
1628
1629     {
1630         std::string vbBehindName = "vb_" + std::to_string(behindVb);
1631         std::string ahead_threshold_exceeded = vbBehindName + ":drift_ahead_threshold_exceeded";
1632         std::string behind_threshold_exceeded = vbBehindName + ":drift_behind_threshold_exceeded";
1633         std::string total_abs_drift = vbBehindName + ":total_abs_drift";
1634         std::string details = "vbucket-details " + std::to_string(behindVb);
1635         checkeq(uint64_t(n_keys), get_ull_stat(h, h1, behind_threshold_exceeded.data(), details.data()),
1636                 "Expected behind threshold to match mutations");
1637         checkeq(uint64_t(0), get_ull_stat(h, h1, ahead_threshold_exceeded.data(), details.data()),
1638                 "Expected no ahead exceptions");
1639         checkge(get_ull_stat(h, h1, total_abs_drift.data(), details.data()), uint64_t(0),
1640                 "Expected some drift");
1641     }
1642
1643
1644     return SUCCESS;
1645 }
1646
1647 static enum test_result test_del_with_meta_and_check_drift_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1648     // Activate n vbuckets (vb 0 is already)
1649     const int n_vbuckets = 10;
1650     for (int ii = 1; ii < n_vbuckets; ii++) {
1651         check(set_vbucket_state(h, h1, ii, vbucket_state_active),
1652               "Failed to set vbucket state.");
1653     }
1654
1655     // Let's make vbucket n/2 be the one who is ahead, n/3 is behind
1656     const int aheadVb = n_vbuckets/2;
1657     const int behindVb = n_vbuckets/3;
1658     checkne(aheadVb, behindVb, "Cannot have the same VB as ahead/behind");
1659
1660     HLC hlc(0/*init HLC*/,
1661             std::chrono::microseconds(0)/*ahead threshold*/,
1662             std::chrono::microseconds(0)/*behind threshold*/);
1663
1664     // grab the drift behind threshold
1665     uint64_t driftBehindThreshold = get_ull_stat(h, h1,
1666                                                  "ep_hlc_ahead_threshold_us",
1667                                                  nullptr);
1668     // Create n keys * n_vbuckets
1669     const int n_keys = 5;
1670     for (int ii = 0 ; ii < n_vbuckets; ii++) {
1671         for (int k = 0; k < n_keys; k++) {
1672             std::string key = "key_" + std::to_string(k);
1673
1674             // In the del_with_meta test we want to pretend a del_wm came from
1675             // the past, so we want to ensure a delete doesn't get rejected
1676             // by LWW conflict resolution, thus write all documents that are
1677             // going to be deleted with set_with_meta, and write them way in the past.
1678             // This will trigger threshold and increment drift stats... so we
1679             // account for these later
1680             ItemMetaData itm_meta;
1681             itm_meta.cas = 1; // set to 1
1682             set_with_meta(h, h1, key.data(), key.size(), NULL, 0, ii, &itm_meta,
1683                           0, false, PROTOCOL_BINARY_RAW_BYTES, true, 0);
1684             checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
1685                     "Expected success");
1686         }
1687     }
1688
1689     checkeq(uint64_t(0), get_ull_stat(h, h1, "ep_active_ahead_exceptions"),
1690             "Expected ahead counter to match mutations");
1691     checkeq(uint64_t(n_keys*n_vbuckets), get_ull_stat(h, h1, "ep_active_behind_exceptions"),
1692             "Expected behind counter to match mutations");
1693
1694     // Del_with_meta n_keys to n_vbuckets
1695     for (int ii = 0 ; ii < n_vbuckets; ii++) {
1696         for (int k = 0; k < n_keys; k++) {
1697             std::string key = "key_" + std::to_string(k);
1698             ItemMetaData itm_meta;
1699             itm_meta.cas = hlc.nextHLC();
1700             if (ii == aheadVb) {
1701                 // Push this guy *far* ahead (1 year)
1702                 itm_meta.cas += 3154E10;
1703             } else if(ii == behindVb) {
1704                 // just be sure it was already greater than 1 + driftthreshold
1705                 checkge(itm_meta.cas, uint64_t(1) + driftBehindThreshold,
1706                         "HLC was already zero");
1707                 // set to be way way behind, but ahead of the documents we have set
1708                 itm_meta.cas = 2;
1709             }
1710             del_with_meta(h, h1, key.data(), key.size(), ii, &itm_meta,
1711                           1, false, PROTOCOL_BINARY_RAW_BYTES);
1712             checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
1713                     "Expected success");
1714         }
1715     }
1716
1717     // Bucket stats should report drift
1718     checkge(get_ull_stat(h, h1, "ep_active_hlc_drift"), uint64_t(0),
1719             "Expected drift above zero");
1720     checkeq(2*uint64_t(n_keys*n_vbuckets), get_ull_stat(h, h1, "ep_active_hlc_drift_count"),
1721             "Expected ahead counter to match mutations");
1722
1723     // and should report total exception of all VBs
1724     checkeq(uint64_t(n_keys), get_ull_stat(h, h1, "ep_active_ahead_exceptions"),
1725             "Expected ahead counter to match mutations");
1726     checkeq(uint64_t(n_keys + (n_keys*n_vbuckets)), get_ull_stat(h, h1, "ep_active_behind_exceptions"),
1727             "Expected behind counter to match mutations");
1728
1729     // Victim VBs should have exceptions
1730     {
1731         std::string vbAheadName = "vb_" + std::to_string(aheadVb);
1732         std::string ahead_threshold_exceeded = vbAheadName + ":drift_ahead_threshold_exceeded";
1733         std::string behind_threshold_exceeded = vbAheadName + ":drift_behind_threshold_exceeded";
1734         std::string total_abs_drift = vbAheadName + ":total_abs_drift";
1735         std::string details = "vbucket-details " + std::to_string(aheadVb);
1736
1737         checkeq(uint64_t(n_keys),
1738                 get_ull_stat(h, h1, ahead_threshold_exceeded.data(), details.data()),
1739                 "Expected ahead threshold to match mutations");
1740         checkge(get_ull_stat(h, h1, total_abs_drift.data(), details.data()), uint64_t(0),
1741                 "Expected some drift");
1742     }
1743
1744     {
1745         std::string vbBehindName = "vb_" + std::to_string(behindVb);
1746         std::string ahead_threshold_exceeded = vbBehindName + ":drift_ahead_threshold_exceeded";
1747         std::string behind_threshold_exceeded = vbBehindName + ":drift_behind_threshold_exceeded";
1748         std::string total_abs_drift = vbBehindName + ":total_abs_drift";
1749         std::string details = "vbucket-details " + std::to_string(behindVb);
1750
1751         // *2 behind due to the initial set_with_meta
1752         checkeq(uint64_t(n_keys*2), get_ull_stat(h, h1, behind_threshold_exceeded.data(), details.data()),
1753                 "Expected behind threshold to match mutations");
1754         checkeq(uint64_t(0), get_ull_stat(h, h1, ahead_threshold_exceeded.data(), details.data()),
1755                 "Expected no ahead exceptions");
1756         checkge(get_ull_stat(h, h1, total_abs_drift.data(), details.data()), uint64_t(0),
1757                 "Expected some drift");
1758     }
1759
1760
1761     return SUCCESS;
1762 }
1763
1764 static enum test_result test_setting_drift_threshold(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1765
1766     std::vector<std::pair<std::string, std::string> > configData =
1767         {{"ep_hlc_ahead_threshold_us", "hlc_drift_ahead_threshold_us"},
1768          {"ep_hlc_behind_threshold_us", "hlc_drift_behind_threshold_us"}};
1769
1770     std::vector<std::pair<std::string, uint64_t> > values =
1771         {{"0", 0}, {"1", 1}, {"-1", -1}, {"-0", 0},
1772          {"18446744073709551615", 18446744073709551615ull}};
1773
1774     for (auto data : values) {
1775         for (auto conf : configData) {
1776             check(set_param(h, h1, protocol_binary_engine_param_vbucket,
1777                     conf.second.data(), data.first.data()),
1778                 "Expected set_param success");
1779
1780             checkeq(data.second,
1781                     get_ull_stat(h, h1, conf.first.data(), nullptr),
1782                     "Expected the stat to change to the new value");
1783         }
1784     }
1785     return SUCCESS;
1786 }
1787
1788 // Test manifest //////////////////////////////////////////////////////////////
1789
1790 const char *default_dbname = "./ep_testsuite_xdcr";
1791
1792 BaseTestCase testsuite_testcases[] = {
1793
1794         // XDCR unit tests
1795         TestCase("get meta", test_get_meta, test_setup,
1796                  teardown, NULL, prepare, cleanup),
1797         TestCase("get meta with extras", test_get_meta_with_extras,
1798                  test_setup, teardown, NULL, prepare, cleanup),
1799         TestCase("get meta deleted", test_get_meta_deleted,
1800                  test_setup, teardown, NULL, prepare, cleanup),
1801         TestCase("get meta nonexistent", test_get_meta_nonexistent,
1802                  test_setup, teardown, NULL, prepare, cleanup),
1803         TestCase("get meta followed by get", test_get_meta_with_get,
1804                  test_setup, teardown, NULL, prepare, cleanup),
1805         TestCase("get meta followed by set", test_get_meta_with_set,
1806                  test_setup, teardown, NULL, prepare, cleanup),
1807         TestCase("get meta followed by delete", test_get_meta_with_delete,
1808                  test_setup, teardown, NULL, prepare, cleanup),
1809         TestCase("add with meta", test_add_with_meta, test_setup,
1810                  teardown, NULL, prepare, cleanup),
1811         TestCase("delete with meta", test_delete_with_meta,
1812                  test_setup, teardown, NULL, prepare, cleanup),
1813         TestCase("delete with meta deleted", test_delete_with_meta_deleted,
1814                  test_setup, teardown, NULL, prepare, cleanup),
1815         TestCase("delete with meta nonexistent",
1816                  test_delete_with_meta_nonexistent, test_setup,
1817                  teardown, NULL, prepare, cleanup),
1818         TestCase("delete with meta nonexistent no temp",
1819                  test_delete_with_meta_nonexistent_no_temp, test_setup,
1820                  teardown, NULL, prepare, cleanup),
1821         TestCase("delete_with_meta race with concurrent delete",
1822                  test_delete_with_meta_race_with_delete, test_setup,
1823                  teardown, NULL, prepare, cleanup),
1824         TestCase("delete_with_meta race with concurrent delete",
1825                  test_delete_with_meta_race_with_delete, test_setup,
1826                  teardown, "item_eviction_policy=full_eviction",
1827                  prepare, cleanup),
1828         TestCase("delete_with_meta race with concurrent set",
1829                  test_delete_with_meta_race_with_set, test_setup,
1830                  teardown, NULL, prepare, cleanup),
1831         TestCase("set with meta", test_set_with_meta, test_setup,
1832                  teardown, NULL, prepare, cleanup),
1833         TestCase("set with meta by force", test_set_with_meta_by_force,
1834                  test_setup, teardown, NULL, prepare, cleanup),
1835         TestCase("set with meta deleted", test_set_with_meta_deleted,
1836                  test_setup, teardown, NULL, prepare, cleanup),
1837         TestCase("set with meta nonexistent", test_set_with_meta_nonexistent,
1838                  test_setup, teardown, NULL, prepare, cleanup),
1839         TestCase("set_with_meta race with concurrent set",
1840                  test_set_with_meta_race_with_set, test_setup,
1841                  teardown, NULL, prepare, cleanup),
1842         TestCase("set_with_meta race with concurrent delete",
1843                  test_set_with_meta_race_with_delete, test_setup,
1844                  teardown, NULL, prepare, cleanup),
1845         TestCase("test set_with_meta exp persisted", test_exp_persisted_set_del,
1846                  test_setup, teardown, "exp_pager_stime=3", prepare, cleanup),
1847         TestCase("test del meta conflict resolution",
1848                  test_del_meta_conflict_resolution, test_setup, teardown, NULL,
1849                  prepare, cleanup),
1850         TestCase("test add meta conflict resolution",
1851                  test_add_meta_conflict_resolution, test_setup, teardown, NULL,
1852                  prepare, cleanup),
1853         TestCase("test set meta conflict resolution",
1854                  test_set_meta_conflict_resolution, test_setup, teardown, NULL,
1855                  prepare, cleanup),
1856         TestCase("test del meta lww conflict resolution",
1857                  test_del_meta_lww_conflict_resolution, test_setup, teardown,
1858                  "conflict_resolution_type=lww",prepare, cleanup),
1859         TestCase("test set meta lww conflict resolution",
1860                  test_set_meta_lww_conflict_resolution, test_setup, teardown,
1861                  "conflict_resolution_type=lww",prepare, cleanup),
1862         TestCase("temp item deletion", test_temp_item_deletion,
1863                  test_setup, teardown,
1864                  "exp_pager_stime=1", prepare, cleanup),
1865         TestCase("test get_meta with item_eviction",
1866                  test_getMeta_with_item_eviction, test_setup, teardown,
1867                  "item_eviction_policy=full_eviction", prepare, cleanup),
1868
1869         TestCase("test set_with_meta and drift stats",
1870                  test_set_with_meta_and_check_drift_stats, test_setup,
1871                  teardown, "hlc_ahead_threshold_us=5000000;hlc_behind_threshold_us=0;conflict_resolution_type=lww",
1872                  prepare, cleanup),
1873         TestCase("test del_with_meta and drift stats",
1874                  test_del_with_meta_and_check_drift_stats, test_setup,
1875                  teardown, "hlc_ahead_threshold_us=0;hlc_behind_threshold_us=5000000;conflict_resolution_type=lww",
1876                  prepare, cleanup),
1877         TestCase("test setting drift threshold",
1878                  test_setting_drift_threshold, test_setup,
1879                  teardown, nullptr,
1880                  prepare, cleanup),
1881
1882         TestCase(NULL, NULL, NULL, NULL, NULL, prepare, cleanup)
1883 };