1 /* -*- MODE: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 2016 Couchbase, Inc
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * Testsuite for XDCR-related functionality in ep-engine.
24 #include "ep_test_apis.h"
25 #include "ep_testsuite_common.h"
28 #include <platform/cb_malloc.h>
30 // Helper functions ///////////////////////////////////////////////////////////
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");
39 // Testcases //////////////////////////////////////////////////////////////////
41 static enum test_result test_get_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
43 char const *key = "test_get_meta";
45 checkeq(ENGINE_SUCCESS,
46 store(h, h1, NULL, OPERATION_SET, key, "somevalue", &i),
48 Item *it = reinterpret_cast<Item*>(i);
50 size_t temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
51 check(temp == 0, "Expect zero getMeta ops");
53 check(get_meta(h, h1, key), "Expected to get meta");
54 checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
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);
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");
66 h1->release(h, NULL, i);
70 static enum test_result test_get_meta_with_extras(ENGINE_HANDLE *h,
73 const char *key1 = "test_getm_one";
75 checkeq(ENGINE_SUCCESS,
76 store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
79 wait_for_flusher_to_settle(h, h1);
81 Item *it1 = reinterpret_cast<Item*>(i);
83 size_t temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
84 check(temp == 0, "Expect zero getMeta ops");
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);
97 testHarness.reload_engine(&h, &h1,
98 testHarness.engine_path,
99 testHarness.get_current_testcase()->cfg,
101 wait_for_warmup_complete(h, h1);
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);
110 static enum test_result test_get_meta_deleted(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
112 char const *key = "k1";
115 checkeq(ENGINE_SUCCESS,
116 store(h, h1, NULL, OPERATION_SET, key, "somevalue", &i),
118 h1->release(h, NULL, i);
119 checkeq(ENGINE_SUCCESS,
120 store(h, h1, NULL, OPERATION_SET, key, "somevalue", &i),
123 Item *it = reinterpret_cast<Item*>(i);
124 wait_for_flusher_to_settle(h, h1);
126 checkeq(ENGINE_SUCCESS, del(h, h1, key, it->getCas(), 0), "Delete failed");
127 wait_for_flusher_to_settle(h, h1);
130 int temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
131 check(temp == 0, "Expect zero getMeta ops");
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");
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");
144 h1->release(h, NULL, i);
148 static enum test_result test_get_meta_nonexistent(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
150 char const *key = "k1";
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(),
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");
165 static enum test_result test_get_meta_with_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
167 char const *key1 = "key1";
168 char const *key2 = "key2";
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),
175 h1->release(h, NULL, i);
176 wait_for_flusher_to_settle(h, h1);
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");
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(),
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");
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(),
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");
216 static enum test_result test_get_meta_with_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
218 char const *key1 = "key1";
219 char const *key2 = "key2";
222 ItemMetaData itm_meta;
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),
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);
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(),
237 checkeq(ENGINE_SUCCESS,
238 store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
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);
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");
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);
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");
259 checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
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),
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");
270 checkeq(2, get_int_stat(h, h1, "ep_num_ops_get_meta"), "Expect more getMeta ops");
271 h1->release(h, NULL, i);
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),
279 // check the stat again
280 checkeq(3, get_int_stat(h, h1, "ep_num_ops_get_meta"),
281 "Expected one extra getMeta ops");
283 h1->release(h, NULL, i);
287 static enum test_result test_get_meta_with_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
289 char const *key1 = "key1";
290 char const *key2 = "key2";
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),
298 h1->release(h, NULL, i);
299 wait_for_flusher_to_settle(h, h1);
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");
307 temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
308 check(temp == 1, "Expect one getMeta op");
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");
317 temp = get_int_stat(h, h1, "ep_num_ops_get_meta");
318 checkeq(2, temp, "Expect more getMeta op");
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");
331 static enum test_result test_add_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
333 const char *key = "mykey";
334 const size_t keylen = strlen(key);
335 ItemMetaData itemMeta;
338 // put some random metadata
339 itemMeta.revSeqno = 10;
340 itemMeta.cas = 0xdeadbeef;
341 itemMeta.exptime = 0;
342 itemMeta.flags = 0xdeadbeef;
344 temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
345 check(temp == 0, "Expect zero setMeta ops");
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");
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");
356 temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
357 check(temp == 1, "Failed op does not count");
362 static enum test_result test_delete_with_meta(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
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;
372 size_t temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
373 check(temp == 0, "Expect zero setMeta ops");
375 // put some random meta data
376 itemMeta.revSeqno = 10;
377 itemMeta.cas = 0xdeadbeef;
378 itemMeta.exptime = 0;
379 itemMeta.flags = 0xdeadbeef;
383 checkeq(ENGINE_SUCCESS,
384 store(h, h1, NULL, OPERATION_SET, key1,
387 h1->release(h, NULL, i);
389 checkeq(ENGINE_SUCCESS,
390 store(h, h1, NULL, OPERATION_SET, key2,
393 h1->release(h, NULL, i);
395 checkeq(ENGINE_SUCCESS,
396 store(h, h1, NULL, OPERATION_SET, key3,
397 "somevalue3", &i), "Failed set.");
398 h1->release(h, NULL, i);
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");
403 const void *cookie = testHarness.create_cookie();
405 // delete an item with meta data
406 del_with_meta(h, h1, key1, keylen, 0, &itemMeta, 0, false, false, cookie);
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");
412 temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
413 check(temp == 1, "Expect more setMeta ops");
415 testHarness.set_mutation_extras_handling(cookie, false);
417 // delete an item with meta data
418 del_with_meta(h, h1, key2, keylen, 0, &itemMeta, 0, false, false, cookie);
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");
424 // delete an item with meta data
425 del_with_meta(h, h1, key3, keylen, 0, &itemMeta);
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");
431 testHarness.destroy_cookie(cookie);
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);
442 checkeq(0, get_int_stat(h, h1, "ep_num_ops_del_meta"),
443 "Expect zero setMeta ops");
446 checkeq(ENGINE_SUCCESS,
447 store(h, h1, NULL, OPERATION_SET, key, "somevalue", &i),
449 wait_for_flusher_to_settle(h, h1);
452 checkeq(ENGINE_SUCCESS, del(h, h1, key, 0, 0),
454 wait_for_flusher_to_settle(h, h1);
455 wait_for_stat_to_be(h, h1, "curr_items", 0);
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(),
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");
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;
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");
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);
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");
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");
502 h1->release(h, NULL, i);
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;
513 checkeq(0, get_int_stat(h, h1, "ep_num_ops_del_meta"),
514 "Expect zero setMeta ops");
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(),
520 checkeq(0, get_int_stat(h, h1, "curr_items"), "Expected zero curr_items");
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;
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;
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");
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");
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);
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");
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");
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;
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);
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;
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);
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");
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;
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;
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);
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");
617 static enum test_result test_delete_with_meta_race_with_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
619 char const *key1 = "key1";
620 const size_t keylen1 = strlen(key1);
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;
629 size_t temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
630 check(temp == 0, "Expect zero ops");
633 // test race with a concurrent set for an existing key. should fail.
636 // create a new key and do get_meta
637 checkeq(ENGINE_SUCCESS,
638 store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
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");
645 // do a concurrent set that changes the cas
646 checkeq(ENGINE_SUCCESS,
647 store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
649 h1->release(h, NULL, i);
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");
656 temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
657 check(temp == 0, "Failed op does not count");
660 // test race with a concurrent set for a deleted key. should fail.
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);
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");
671 // do a concurrent set that changes the cas
672 checkeq(ENGINE_SUCCESS,
673 store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
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");
680 temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
681 check(temp == 0, "Failed op does not count");
686 static enum test_result test_delete_with_meta_race_with_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
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);
693 ItemMetaData itm_meta;
696 size_t temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
697 check(temp == 0, "Expect zero ops");
700 // test race with a concurrent delete for an existing key. should fail.
703 // create a new key and do get_meta
704 checkeq(ENGINE_SUCCESS,
705 store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
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");
711 // do a concurrent delete
712 checkeq(ENGINE_SUCCESS, del(h, h1, key1, 0, 0), "Delete failed");
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");
719 temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
720 check(temp == 0, "Failed op does not count");
723 // test race with a concurrent delete for a deleted key. should pass since
724 // the delete itself will fail.
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");
733 // do a concurrent delete
734 checkeq(ENGINE_KEY_ENOENT, del(h, h1, key1, 0, 0), "Delete failed");
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");
741 temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
742 check(temp == 1, "Expect some ops");
745 // test race with a concurrent delete for a nonexistent key. should pass
746 // since the delete itself will fail.
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");
753 // do a concurrent delete
754 checkeq(ENGINE_KEY_ENOENT, del(h, h1, key1, 0, 0), "Delete failed");
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");
761 temp = get_int_stat(h, h1, "ep_num_ops_del_meta");
762 check(temp == 2, "Expect some ops");
764 h1->release(h, NULL, i);
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);
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"),
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");
786 checkeq(ENGINE_SUCCESS,
787 store(h, h1, NULL, OPERATION_SET, key, val, &i),
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");
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;
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");
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");
817 checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Failed op does not count");
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");
822 const void *cookie = testHarness.create_cookie();
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");
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");
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");
843 //disable getting vb uuid and seqno as extras
844 testHarness.set_mutation_extras_handling(cookie, false);
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");
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");
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.");
865 h1->release(h, NULL, i);
866 testHarness.destroy_cookie(cookie);
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";
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;
883 // Pass true to force SetWithMeta.
884 set_with_meta(h, h1, key, keylen, val, strlen(val), 0, &itm_meta,
886 checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Expected success");
887 wait_for_flusher_to_settle(h, h1);
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");
896 check_key_value(h, h1, key, val, strlen(val));
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);
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"),
915 checkeq(ENGINE_SUCCESS,
916 store(h, h1, NULL, OPERATION_SET, key, val, &i),
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");
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);
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");
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;
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");
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");
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");
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"),
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");
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");
970 h1->release(h, NULL, i);
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);
981 checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"), "Expect zero ops");
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");
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;
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");
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");
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");
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");
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");
1024 static enum test_result test_set_with_meta_race_with_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
1026 char const *key1 = "key1";
1027 size_t keylen1 = strlen(key1);
1030 size_t temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1031 check(temp == 0, "Expect zero ops");
1034 // test race with a concurrent set for an existing key. should fail.
1037 // create a new key and do get_meta
1038 checkeq(ENGINE_SUCCESS,
1039 store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
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");
1046 // do a concurrent set that changes the cas
1047 checkeq(ENGINE_SUCCESS,
1048 store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
1050 h1->release(h, NULL, i);
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");
1058 temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1059 check(temp == 0, "Failed op does not count");
1062 // test race with a concurrent set for a deleted key. should fail.
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");
1072 // do a concurrent set that changes the cas
1073 checkeq(ENGINE_SUCCESS,
1074 store(h, h1, NULL, OPERATION_SET, key1, "someothervalue", &i),
1076 h1->release(h, NULL, i);
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");
1084 temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1085 check(temp == 0, "Failed op does not count");
1090 static enum test_result test_set_with_meta_race_with_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
1092 char const *key1 = "key1";
1093 size_t keylen1 = strlen(key1);
1094 char const *key2 = "key2";
1095 size_t keylen2 = strlen(key2);
1098 size_t temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1099 check(temp == 0, "Expect zero op");
1102 // test race with a concurrent delete for an existing key. should fail.
1105 // create a new key and do get_meta
1106 checkeq(ENGINE_SUCCESS,
1107 store(h, h1, NULL, OPERATION_SET, key1, "somevalue", &i),
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");
1113 // do a concurrent delete that changes the cas
1114 checkeq(ENGINE_SUCCESS, del(h, h1, key1, 0, 0), "Delete failed");
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);
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());
1125 temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1126 check(temp == 0, "Expect zero op");
1129 // test race with a concurrent delete for a deleted key. should pass since
1130 // the delete will fail.
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");
1139 // do a concurrent delete. should fail.
1140 checkeq(ENGINE_KEY_ENOENT, del(h, h1, key1, 0, 0), "Delete failed");
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");
1146 temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1147 check(temp == 1, "Expect some op");
1150 // test race with a concurrent delete for a nonexistent key. should pass
1151 // since the delete will fail.
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");
1158 // do a concurrent delete. should fail.
1159 checkeq(ENGINE_KEY_ENOENT, del(h, h1, key2, 0, 0), "Delete failed");
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");
1165 temp = get_int_stat(h, h1, "ep_num_ops_set_meta");
1166 check(temp == 2, "Expect some ops");
1168 h1->release(h, NULL, i);
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");
1176 ItemMetaData itm_meta;
1177 itm_meta.revSeqno = 1;
1179 itm_meta.exptime = 0;
1181 set_with_meta(h, h1, "key3", 4, "val0", 4, 0, &itm_meta, last_meta.cas);
1183 itm_meta.revSeqno = 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);
1188 itm_meta.revSeqno = 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);
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);
1199 wait_for_flusher_to_settle(h, h1);
1200 wait_for_stat_to_be(h, h1, "curr_items", 0);
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");
1211 static enum test_result test_temp_item_deletion(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1)
1213 // Do get_meta for an existing key
1214 char const *k1 = "k1";
1217 checkeq(ENGINE_SUCCESS,
1218 store(h, h1, NULL, OPERATION_SET, k1, "somevalue", &i),
1220 wait_for_flusher_to_settle(h, h1);
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);
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");
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);
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");
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");
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");
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");
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");
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");
1267 h1->release(h, NULL, i);
1268 testHarness.destroy_cookie(cookie);
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;
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");
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);
1291 // Check all meta data is the same
1292 itemMeta.revSeqno++;
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");
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");
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");
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");
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;
1333 checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"),
1334 "Expect zero setMeta ops");
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");
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");
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");
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");
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");
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");
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");
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");
1384 checkeq(0, get_int_stat(h, h1, "ep_bg_meta_fetched"),
1385 "Expect no bg meta fetches");
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;
1399 checkeq(0, get_int_stat(h, h1, "ep_num_ops_set_meta"),
1400 "Expect zero setMeta ops");
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");
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");
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");
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");
1432 static enum test_result test_del_meta_conflict_resolution(ENGINE_HANDLE *h,
1433 ENGINE_HANDLE_V1 *h1) {
1436 checkeq(ENGINE_SUCCESS,
1437 store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1439 wait_for_flusher_to_settle(h, h1);
1440 h1->release(h, NULL, i);
1442 // put some random metadata
1443 ItemMetaData itemMeta;
1444 itemMeta.revSeqno = 10;
1445 itemMeta.cas = 0xdeadbeef;
1446 itemMeta.exptime = 0;
1447 itemMeta.flags = 0xdeadbeef;
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);
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");
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");
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");
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");
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");
1490 static enum test_result test_del_meta_lww_conflict_resolution(ENGINE_HANDLE *h,
1491 ENGINE_HANDLE_V1 *h1) {
1496 checkeq(ENGINE_SUCCESS,
1497 store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1501 h1->get_item_info(h, NULL, i, &info);
1502 wait_for_flusher_to_settle(h, h1);
1503 h1->release(h, NULL, i);
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;
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);
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");
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");
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");
1540 static enum test_result test_getMeta_with_item_eviction(ENGINE_HANDLE *h,
1541 ENGINE_HANDLE_V1 *h1)
1543 char const *key = "test_get_meta";
1545 checkeq(ENGINE_SUCCESS,
1546 store(h, h1, NULL, OPERATION_SET, key, "somevalue", &i),
1548 wait_for_flusher_to_settle(h, h1);
1549 evict_key(h, h1, key, 0, "Ejected.");
1551 Item *it = reinterpret_cast<Item*>(i);
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);
1559 h1->release(h, NULL, i);
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.");
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");
1576 HLC hlc(0/*init HLC*/,
1577 std::chrono::microseconds(0)/*ahead threshold*/,
1578 std::chrono::microseconds(0)/*behind threshold*/);
1580 // grab the drift behind threshold
1581 uint64_t driftBehindThreshold = get_ull_stat(h, h1,
1582 "ep_hlc_ahead_threshold_us",
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...
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");
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");
1614 // Victim VBs should have exceptions
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");
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");
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.");
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");
1660 HLC hlc(0/*init HLC*/,
1661 std::chrono::microseconds(0)/*ahead threshold*/,
1662 std::chrono::microseconds(0)/*behind threshold*/);
1664 // grab the drift behind threshold
1665 uint64_t driftBehindThreshold = get_ull_stat(h, h1,
1666 "ep_hlc_ahead_threshold_us",
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);
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");
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");
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
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");
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");
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");
1729 // Victim VBs should have exceptions
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);
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");
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);
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");
1764 static enum test_result test_setting_drift_threshold(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
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"}};
1770 std::vector<std::pair<std::string, uint64_t> > values =
1771 {{"0", 0}, {"1", 1}, {"-1", -1}, {"-0", 0},
1772 {"18446744073709551615", 18446744073709551615ull}};
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");
1780 checkeq(data.second,
1781 get_ull_stat(h, h1, conf.first.data(), nullptr),
1782 "Expected the stat to change to the new value");
1788 // Test manifest //////////////////////////////////////////////////////////////
1790 const char *default_dbname = "./ep_testsuite_xdcr";
1792 BaseTestCase testsuite_testcases[] = {
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",
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,
1850 TestCase("test add meta conflict resolution",
1851 test_add_meta_conflict_resolution, test_setup, teardown, NULL,
1853 TestCase("test set meta conflict resolution",
1854 test_set_meta_conflict_resolution, test_setup, teardown, NULL,
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),
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",
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",
1877 TestCase("test setting drift threshold",
1878 test_setting_drift_threshold, test_setup,
1882 TestCase(NULL, NULL, NULL, NULL, NULL, prepare, cleanup)