1 /* -*- MODE: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 2010 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.
18 // Usage: (to repeatedly run just a single test case)
19 // make engine_tests IS_LOOP=-L EP_TEST_NUM=3
30 #define mkdir(a, b) _mkdir(a)
44 #include <platform/dirutils.h>
47 #include "ep-engine/command_ids.h"
48 #include "ep_test_apis.h"
49 #include "ep_testsuite.h"
51 #include <libcouchstore/couch_db.h>
52 #include "mock/mock_dcp.h"
56 #include <JSON_checker.h>
59 /* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
60 * optimize the conversion functions, but the prototypes generate warnings
61 * from gcc. The conversion methods isn't the bottleneck for my app, so
62 * just remove the warnings by undef'ing the optimization ..
70 #undef THREAD_SANITIZER
72 # if defined(__has_feature) && __has_feature(thread_sanitizer)
73 #define THREAD_SANITIZER
77 // ptr_fun don't like the extern "C" thing for unlock cookie.. cast it
79 typedef void (*UNLOCK_COOKIE_T)(const void *cookie);
82 static void checknefn(T exp, T got, const char *msg, const char *file, const int linenum) {
85 ss << "Expected `" << exp << "' to not equal `" << got << "' - " << msg;
86 abort_msg(ss.str().c_str(), file, linenum);
90 #define checkne(a, b, c) checknefn(a, b, c, __FILE__, __LINE__)
93 #define check(expr, msg) \
94 static_cast<void>((expr) ? 0 : abort_msg(#expr, msg, __LINE__))
96 #define WHITESPACE_DB "whitespace sucks.db"
97 #define MULTI_DISPATCHER_CONFIG \
98 "ht_size=129;ht_locks=3;chk_remover_stime=1;chk_period=60"
100 struct test_harness testHarness;
104 ThreadData(ENGINE_HANDLE *eh, ENGINE_HANDLE_V1 *ehv1,
105 int e=0) : h(eh), h1(ehv1), extra(e) {}
107 ENGINE_HANDLE_V1 *h1;
111 bool abort_msg(const char *expr, const char *msg, int line) {
112 fprintf(stderr, "%s:%d Test failed: `%s' (%s)\n",
113 __FILE__, line, msg, expr);
119 static const char *dbname_env;
120 static enum test_result rmdb(void)
122 const char *files[] = { WHITESPACE_DB,
128 while (files[ii] != NULL) {
129 CouchbaseDirectoryUtilities::rmrf(files[ii]);
130 if (access(files[ii], F_OK) != -1) {
131 std::cerr << "Failed to remove: " << files[ii] << " " << std::endl;
140 static enum test_result skipped_test_function(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
146 static bool teardown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
152 static const void* createTapConn(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
154 const void *cookie = testHarness.create_cookie();
155 testHarness.lock_cookie(cookie);
156 TAP_ITERATOR iter = h1->get_tap_iterator(h, cookie, name,
158 TAP_CONNECT_FLAG_DUMP, NULL,
160 check(iter != NULL, "Failed to create a tap iterator");
164 static void check_key_value(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
165 const char* key, const char* val, size_t vlen,
166 uint16_t vbucket = 0) {
168 check(get_item_info(h, h1, &info, key, vbucket), "checking key and value");
169 check(info.nvalue == 1, "info.nvalue != 1");
170 check(vlen == info.value[0].iov_len, "Value length mismatch");
171 check(memcmp(info.value[0].iov_base, val, vlen) == 0, "Data mismatch");
174 // Fetches the CAS of the specified key.
175 static uint64_t get_CAS(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
176 const std::string& key) {
178 checkeq(ENGINE_SUCCESS,
179 h1->get(h, NULL, &i, key.c_str(), key.size(), /*vBucket*/0),
180 "Failed to get key");
184 check(h1->get_item_info(h, NULL, i, &info),
185 "Failed to get item info for key");
186 h1->release(h, NULL, i);
191 static void check_observe_seqno(bool failover, uint8_t format_type, uint16_t vb_id,
192 uint64_t vb_uuid, uint64_t last_persisted_seqno,
193 uint64_t current_seqno, uint64_t failover_vbuuid = 0,
194 uint64_t failover_seqno = 0) {
195 uint8_t recv_format_type;
197 uint64_t recv_vb_uuid;
198 uint64_t recv_last_persisted_seqno;
199 uint64_t recv_current_seqno;
200 uint64_t recv_failover_vbuuid;
201 uint64_t recv_failover_seqno;
203 memcpy(&recv_format_type, last_body.data(), sizeof(uint8_t));
204 check(recv_format_type == format_type, "Wrong format type in result");
205 memcpy(&recv_vb_id, last_body.data() + 1, sizeof(uint16_t));
206 check(ntohs(recv_vb_id) == vb_id, "Wrong vbucket id in result");
207 memcpy(&recv_vb_uuid, last_body.data() + 3, sizeof(uint64_t));
208 check(ntohll(recv_vb_uuid) == vb_uuid, "Wrong vbucket uuid in result");
209 memcpy(&recv_last_persisted_seqno, last_body.data() + 11, sizeof(uint64_t));
210 check(ntohll(recv_last_persisted_seqno) == last_persisted_seqno,
211 "Wrong persisted seqno in result");
212 memcpy(&recv_current_seqno, last_body.data() + 19, sizeof(uint64_t));
213 check(ntohll(recv_current_seqno) == current_seqno, "Wrong current seqno in result");
216 memcpy(&recv_failover_vbuuid, last_body.data() + 27, sizeof(uint64_t));
217 check(ntohll(recv_failover_vbuuid) == failover_vbuuid, "Wrong failover uuid in result");
218 memcpy(&recv_failover_seqno, last_body.data() + 35, sizeof(uint64_t));
219 check(ntohll(recv_failover_seqno) == failover_seqno, "Wrong failover seqno in result");
223 static bool test_setup(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
224 wait_for_warmup_complete(h, h1);
226 check(h1->get_stats(h, NULL, "prev-vbucket", 12, add_stats) == ENGINE_SUCCESS,
227 "Failed to get the previous state of vbuckets");
228 if (vals.find("vb_0") == vals.end()) {
229 check(set_vbucket_state(h, h1, 0, vbucket_state_active),
230 "Failed to set VB0 state.");
233 // Wait for vb0's state (active) to be persisted to disk, that way
234 // we know the KVStore files exist on disk.
235 wait_for_stat_to_be(h, h1, "ep_persist_vbstate_total", 1);
237 // warmup is complete, notify ep engine that it must now enable
239 protocol_binary_request_header *pkt = createPacket(PROTOCOL_BINARY_CMD_ENABLE_TRAFFIC);
240 check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
241 "Failed to enable data traffic");
247 static enum test_result test_getl(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
248 const char *key = "k1";
249 uint16_t vbucketId = 0;
250 uint32_t expiration = 25;
252 getl(h, h1, key, vbucketId, expiration);
253 check(last_status == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT,
254 "expected the key to be missing...");
255 if (!last_body.empty() && last_body != "NOT_FOUND") {
256 fprintf(stderr, "Should have returned NOT_FOUND. Getl Failed");
261 check(store(h, h1, NULL, OPERATION_SET, key, "{\"lock\":\"data\"}",
262 &i, 0, vbucketId, 3600, PROTOCOL_BINARY_DATATYPE_JSON)
263 == ENGINE_SUCCESS, "Failed to store an item.");
264 h1->release(h, NULL, i);
266 /* retry getl, should succeed */
267 getl(h, h1, key, vbucketId, expiration);
268 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
269 "Expected to be able to getl on first try");
270 check(last_body == "{\"lock\":\"data\"}", "Body was malformed.");
271 check(last_datatype == PROTOCOL_BINARY_DATATYPE_JSON,
272 "Expected datatype to be JSON");
274 /* wait 16 seconds */
275 testHarness.time_travel(16);
277 /* lock's taken so this should fail */
278 getl(h, h1, key, vbucketId, expiration);
279 check(last_status == PROTOCOL_BINARY_RESPONSE_ETMPFAIL,
280 "Expected to fail getl on second try");
282 if (!last_body.empty() && last_body != "LOCK_ERROR") {
283 fprintf(stderr, "Should have returned LOCK_ERROR. Getl Failed");
287 check(store(h, h1, NULL, OPERATION_SET, key, "lockdata2", &i, 0, vbucketId)
288 != ENGINE_SUCCESS, "Should have failed to store an item.");
289 h1->release(h, NULL, i);
291 /* wait another 10 seconds */
292 testHarness.time_travel(10);
294 /* retry set, should succeed */
295 check(store(h, h1, NULL, OPERATION_SET, key, "lockdata", &i, 0, vbucketId)
296 == ENGINE_SUCCESS, "Failed to store an item.");
297 h1->release(h, NULL, i);
299 /* point to wrong vbucket, to test NOT_MY_VB response */
300 getl(h, h1, key, 10, expiration);
301 check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
302 "Should have received not my vbucket response");
304 /* acquire lock, should succeed */
305 getl(h, h1, key, vbucketId, expiration);
306 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
307 "Aquire lock should have succeeded");
308 check(last_datatype == PROTOCOL_BINARY_RAW_BYTES,
309 "Expected datatype to be RAW BYTES");
311 /* try an incr operation followed by a delete, both of which should fail */
315 check(h1->arithmetic(h, NULL, key, 2, true, false, 1, 1, 0,
316 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
317 0) == ENGINE_TMPFAIL, "Incr failed");
318 h1->release(h, NULL, i);
320 check(del(h, h1, key, 0, 0) == ENGINE_TMPFAIL, "Delete failed");
323 /* bug MB 2699 append after getl should fail with ENGINE_TMPFAIL */
325 testHarness.time_travel(26);
327 char binaryData1[] = "abcdefg\0gfedcba";
328 char binaryData2[] = "abzdefg\0gfedcba";
330 check(storeCasVb11(h, h1, NULL, OPERATION_SET, key,
331 binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
334 h1->release(h, NULL, i);
336 /* acquire lock, should succeed */
337 getl(h, h1, key, vbucketId, expiration);
338 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
339 "Aquire lock should have succeeded");
341 /* append should fail */
342 check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, key,
343 binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
345 "Append should fail.");
346 h1->release(h, NULL, i);
348 /* bug MB 3252 & MB 3354.
349 * 1. Set a key with an expiry value.
350 * 2. Take a lock on the item before it expires
351 * 3. Wait for the item to expire
352 * 4. Perform a CAS operation, should fail
353 * 5. Perform a set operation, should succeed
355 const char *ekey = "test_expiry";
356 const char *edata = "some test data here.";
360 check(h1->allocate(h, NULL, &it, ekey, strlen(ekey), strlen(edata), 0, 2,
361 PROTOCOL_BINARY_RAW_BYTES) == ENGINE_SUCCESS, "Allocation Failed");
365 if (!h1->get_item_info(h, NULL, it, &info)) {
368 memcpy(info.value[0].iov_base, edata, strlen(edata));
370 check(h1->store(h, NULL, it, &cas, OPERATION_SET, 0) ==
371 ENGINE_SUCCESS, "Failed to Store item");
372 check_key_value(h, h1, ekey, edata, strlen(edata));
373 h1->release(h, NULL, it);
375 testHarness.time_travel(3);
378 /* cas should fail */
379 check(storeCasVb11(h, h1, NULL, OPERATION_CAS, ekey,
380 binaryData1, sizeof(binaryData1) - 1, 82758, &i, cas, 0)
383 h1->release(h, NULL, i);
385 /* but a simple store should succeed */
386 check(store(h, h1, NULL, OPERATION_SET, ekey, edata, &i, 0, vbucketId)
387 == ENGINE_SUCCESS, "Failed to store an item.");
388 h1->release(h, NULL, i);
392 static enum test_result test_unl(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
394 const char *key = "k2";
395 uint16_t vbucketId = 0;
397 unl(h, h1, key, vbucketId);
398 check(last_status != PROTOCOL_BINARY_RESPONSE_SUCCESS,
399 "expected the key to be missing...");
402 check(store(h, h1, NULL, OPERATION_SET, key, "lockdata", &i, 0, vbucketId)
403 == ENGINE_SUCCESS, "Failed to store an item.");
404 h1->release(h, NULL, i);
406 /* getl, should succeed */
407 getl(h, h1, key, vbucketId, 0);
408 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
409 "Expected to be able to getl on first try");
411 /* save the returned cas value for later */
412 uint64_t cas = last_cas;
414 /* lock's taken unlocking with a random cas value should fail */
415 unl(h, h1, key, vbucketId);
416 check(last_status == PROTOCOL_BINARY_RESPONSE_ETMPFAIL,
417 "Expected to fail getl on second try");
419 if (!last_body.empty() && last_body != "UNLOCK_ERROR") {
420 fprintf(stderr, "Should have returned UNLOCK_ERROR. Unl Failed");
424 unl(h, h1, key, vbucketId, cas);
425 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
426 "Expected to succed unl with correct cas");
428 /* acquire lock, should succeed */
429 getl(h, h1, key, vbucketId, 0);
431 /* wait 16 seconds */
432 testHarness.time_travel(16);
434 /* lock has expired, unl should fail */
435 unl(h, h1, key, vbucketId, last_cas);
436 check(last_status == PROTOCOL_BINARY_RESPONSE_ETMPFAIL,
437 "Expected to fail unl on lock timeout");
442 static enum test_result test_wrong_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
443 ENGINE_STORE_OPERATION op) {
445 int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
447 if (op == OPERATION_ADD) {
448 // Add operation with cas != 0 doesn't make sense
451 check(store(h, h1, NULL, op,
452 "key", "somevalue", &i, cas, 1) == ENGINE_NOT_MY_VBUCKET,
453 "Expected not_my_vbucket");
454 h1->release(h, NULL, i);
455 wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
459 static enum test_result test_pending_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
460 ENGINE_STORE_OPERATION op) {
461 const void *cookie = testHarness.create_cookie();
462 testHarness.set_ewouldblock_handling(cookie, false);
464 check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
465 check(verify_vbucket_state(h, h1, 1, vbucket_state_pending), "Bucket state was not set to pending.");
467 if (op == OPERATION_ADD) {
468 // Add operation with cas != 0 doesn't make sense..
471 check(store(h, h1, cookie, op,
472 "key", "somevalue", &i, cas, 1) == ENGINE_EWOULDBLOCK,
473 "Expected woodblock");
474 h1->release(h, NULL, i);
475 testHarness.destroy_cookie(cookie);
479 static enum test_result test_replica_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
480 ENGINE_STORE_OPERATION op) {
482 check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
483 check(verify_vbucket_state(h, h1, 1, vbucket_state_replica), "Bucket state was not set to replica.");
484 int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
487 if (op == OPERATION_ADD) {
488 // performing add with a CAS != 0 doesn't make sense...
491 check(store(h, h1, NULL, op,
492 "key", "somevalue", &i, cas, 1) == ENGINE_NOT_MY_VBUCKET,
493 "Expected not my vbucket");
494 wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
495 h1->release(h, NULL, i);
500 // ----------------------------------------------------------------------
501 // The actual tests are below.
502 // ----------------------------------------------------------------------
505 static enum test_result test_get_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
506 check(verify_key(h, h1, "k") == ENGINE_KEY_ENOENT, "Expected miss.");
510 static enum test_result test_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
513 uint64_t vb_uuid = 0, high_seqno = 0;
514 const int num_sets = 5, num_keys = 4;
516 std::string key_arr[num_keys] = { "dummy_key",
522 for (int k = 0; k < num_keys; k++) {
523 for (int j = 0; j < num_sets; j++) {
524 memset(&info, 0, sizeof(info));
525 vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
526 high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno",
529 std::string err_str_store("Error setting " + key_arr[k]);
530 checkeq(ENGINE_SUCCESS,
531 store(h, h1, NULL, OPERATION_SET, key_arr[k].c_str(),
533 err_str_store.c_str());
534 h1->release(h, NULL, i);
536 std::string err_str_get_item_info("Error getting " + key_arr[k]);
537 checkeq(true, get_item_info(h, h1, &info, key_arr[k].c_str()),
538 err_str_get_item_info.c_str());
540 std::string err_str_vb_uuid("Expected valid vbucket uuid for " +
542 checkeq(vb_uuid, info.vbucket_uuid, err_str_vb_uuid.c_str());
544 std::string err_str_seqno("Expected valid sequence number for " +
546 checkeq(high_seqno + 1, info.seqno, err_str_seqno.c_str());
550 wait_for_flusher_to_settle(h, h1);
551 std::stringstream error1, error2;
552 error1 << "Expected ep_total_persisted >= num_keys (" << num_keys << ")";
553 error2 << "Expected ep_total_persisted <= num_sets*num_keys ("
554 << num_sets*num_keys << ")";
556 // The flusher could of ran > 1 times. We can only assert
557 // that we persisted between num_keys and upto num_keys*num_sets
558 check(get_int_stat(h, h1, "ep_total_persisted") >= num_keys,
559 error1.str().c_str());
560 check(get_int_stat(h, h1, "ep_total_persisted") <= num_sets*num_keys,
561 error2.str().c_str());
568 ENGINE_HANDLE_V1 *h1;
572 static void conc_del_set_thread(void *arg) {
573 struct handle_pair *hp = static_cast<handle_pair *>(arg);
576 for (int i = 0; i < 5000; ++i) {
577 store(hp->h, hp->h1, NULL, OPERATION_ADD,
578 "key", "somevalue", &it);
579 hp->h1->release(hp->h, NULL, it);
581 checkeq(ENGINE_SUCCESS,
582 store(hp->h, hp->h1, NULL, OPERATION_SET,
583 "key", "somevalue", &it),
585 hp->h1->release(hp->h, NULL, it);
587 // Ignoring the result here -- we're racing.
588 del(hp->h, hp->h1, "key", 0, 0);
593 static void conc_incr_thread(void *arg) {
594 struct handle_pair *hp = static_cast<handle_pair *>(arg);
597 for (int i = 0; i < 10; i++) {
599 check(hp->h1->arithmetic(hp->h, NULL, "key", 3, true, true, 1, 1, 0,
600 &it, PROTOCOL_BINARY_RAW_BYTES, &result,
601 0) == ENGINE_SUCCESS,
602 "Failed arithmetic operation");
603 hp->h1->release(hp->h, NULL, it);
608 static enum test_result test_conc_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
610 const int n_threads = 8;
611 cb_thread_t threads[n_threads];
612 struct handle_pair hp = {h, h1};
614 wait_for_persisted_value(h, h1, "key", "value1");
616 for (int i = 0; i < n_threads; i++) {
617 int r = cb_create_thread(&threads[i], conc_del_set_thread, &hp, 0);
621 for (int i = 0; i < n_threads; i++) {
622 int r = cb_join_thread(threads[i]);
626 wait_for_flusher_to_settle(h, h1);
628 testHarness.reload_engine(&h, &h1,
629 testHarness.engine_path,
630 testHarness.get_current_testcase()->cfg,
632 wait_for_warmup_complete(h, h1);
634 cb_assert(0 == get_int_stat(h, h1, "ep_warmed_dups"));
639 static enum test_result test_conc_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
640 const int n_threads = 10;
641 cb_thread_t threads[n_threads];
642 struct handle_pair hp = {h, h1};
644 check(store(h, h1, NULL, OPERATION_SET, "key", "0", &i) == ENGINE_SUCCESS,
646 h1->release(h, NULL, i);
648 for (int i = 0; i < n_threads; i++) {
649 int r = cb_create_thread(&threads[i], conc_incr_thread, &hp, 0);
653 for (int i = 0; i < n_threads; i++) {
654 int r = cb_join_thread(threads[i]);
658 check_key_value(h, h1, "key", "100", 3);
663 static enum test_result test_conc_incr_new_itm (ENGINE_HANDLE *h,
664 ENGINE_HANDLE_V1 *h1) {
665 const int n_threads = 10;
666 cb_thread_t threads[n_threads];
667 struct handle_pair hp = {h, h1};
669 for (int i = 0; i < n_threads; i++) {
670 int r = cb_create_thread(&threads[i], conc_incr_thread, &hp, 0);
674 for (int i = 0; i < n_threads; i++) {
675 int r = cb_join_thread(threads[i]);
679 check_key_value(h, h1, "key", "100", 3);
684 struct multi_set_args {
686 ENGINE_HANDLE_V1 *h1;
692 static void multi_set_thread(void *arg) {
693 struct multi_set_args *msa = static_cast<multi_set_args *>(arg);
695 for (int i = 0; i < msa->count; i++) {
698 s << msa->prefix << i;
699 std::string key(s.str());
700 check(ENGINE_SUCCESS == store(msa->h, msa->h1, NULL, OPERATION_SET,
701 key.c_str(), "somevalue", &it), "Set failure!");
702 msa->h1->release(msa->h, NULL, it);
707 static enum test_result test_multi_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
709 cb_thread_t thread1, thread2;
710 struct multi_set_args msa1, msa2;
713 msa1.prefix = "ONE_";
715 cb_assert(cb_create_thread(&thread1, multi_set_thread, &msa1, 0) == 0);
719 msa2.prefix = "TWO_";
721 cb_assert(cb_create_thread(&thread2, multi_set_thread, &msa2, 0) == 0);
723 cb_assert(cb_join_thread(thread1) == 0);
724 cb_assert(cb_join_thread(thread2) == 0);
726 wait_for_flusher_to_settle(h, h1);
728 check(get_int_stat(h, h1, "curr_items") == 100000,
729 "Mismatch in number of items inserted");
730 check(get_int_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno") == 100000,
731 "Unexpected high sequence number");
736 static enum test_result test_set_get_hit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
738 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
740 check_key_value(h, h1, "key", "somevalue", 9);
741 h1->release(h, NULL, i);
745 static enum test_result test_set_get_hit_bin(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
746 char binaryData[] = "abcdefg\0gfedcba";
747 cb_assert(sizeof(binaryData) != strlen(binaryData));
750 check(ENGINE_SUCCESS ==
751 storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
752 binaryData, sizeof(binaryData), 82758, &i, 0, 0),
754 h1->release(h, NULL, i);
755 check_key_value(h, h1, "key", binaryData, sizeof(binaryData));
759 static enum test_result test_set_with_cas_non_existent(ENGINE_HANDLE *h,
760 ENGINE_HANDLE_V1 *h1) {
761 const char *key = "test_expiry_flush";
764 check(h1->allocate(h, NULL, &i, key, strlen(key), 10, 0, 0,
765 PROTOCOL_BINARY_RAW_BYTES) == ENGINE_SUCCESS, "Allocation failed.");
767 Item *it = reinterpret_cast<Item*>(i);
771 check(h1->store(h, NULL, i, &cas, OPERATION_SET, 0) == ENGINE_KEY_ENOENT,
772 "Expected not found");
773 h1->release(h, NULL, i);
778 static enum test_result test_set_change_flags(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
780 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
782 h1->release(h, NULL, i);
785 uint32_t flags = 828258;
786 check(get_item_info(h, h1, &info, "key"), "Failed to get value.");
787 cb_assert(info.flags != flags);
789 check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
790 "newvalue", strlen("newvalue"), flags, &i, 0, 0) == ENGINE_SUCCESS,
791 "Failed to set again.");
792 h1->release(h, NULL, i);
794 check(get_item_info(h, h1, &info, "key"), "Failed to get value.");
796 return info.flags == flags ? SUCCESS : FAIL;
799 static enum test_result test_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
801 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
802 "Failed to do initial set.");
803 h1->release(h, NULL, i);
804 check(store(h, h1, NULL, OPERATION_CAS, "key", "failcas", &i) != ENGINE_SUCCESS,
805 "Failed to fail initial CAS.");
806 h1->release(h, NULL, i);
807 check_key_value(h, h1, "key", "somevalue", 9);
809 check(h1->get(h, NULL, &i, "key", 3, 0) == ENGINE_SUCCESS,
810 "Failed to get value.");
814 check(h1->get_item_info(h, NULL, i, &info), "Failed to get item info.");
815 h1->release(h, NULL, i);
817 check(store(h, h1, NULL, OPERATION_CAS, "key", "winCas", &i,
818 info.cas) == ENGINE_SUCCESS,
819 "Failed to store CAS");
820 h1->release(h, NULL, i);
821 check_key_value(h, h1, "key", "winCas", 6);
823 uint64_t cval = 99999;
824 check(store(h, h1, NULL, OPERATION_CAS, "non-existing", "winCas", &i,
825 cval) == ENGINE_KEY_ENOENT,
826 "CAS for non-existing key returned the wrong error code");
827 h1->release(h, NULL, i);
831 static enum test_result test_add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
834 uint64_t vb_uuid = 0;
835 uint32_t high_seqno = 0;
837 memset(&info, 0, sizeof(info));
839 vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
840 high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
842 check(store(h, h1, NULL, OPERATION_ADD,"key", "somevalue", &i) == ENGINE_SUCCESS,
843 "Failed to add value.");
844 h1->release(h, NULL, i);
846 check(get_item_info(h, h1, &info, "key"), "Error getting item info");
847 check(vb_uuid == info.vbucket_uuid, "Expected valid vbucket uuid");
848 check(high_seqno + 1 == info.seqno, "Expected valid sequence number");
850 check(store(h, h1, NULL, OPERATION_ADD,"key", "somevalue", &i) == ENGINE_NOT_STORED,
851 "Failed to fail to re-add value.");
852 h1->release(h, NULL, i);
854 // This aborts on failure.
855 check_key_value(h, h1, "key", "somevalue", 9);
857 // Expiration above was an hour, so let's go to The Future
858 testHarness.time_travel(3800);
860 check(store(h, h1, NULL, OPERATION_ADD,"key", "newvalue", &i) == ENGINE_SUCCESS,
861 "Failed to add value again.");
863 h1->release(h, NULL, i);
864 check_key_value(h, h1, "key", "newvalue", 8);
868 static enum test_result test_add_add_with_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
870 check(store(h, h1, NULL, OPERATION_ADD, "key",
871 "somevalue", &i) == ENGINE_SUCCESS,
873 check_key_value(h, h1, "key", "somevalue", 9);
877 check(h1->get_item_info(h, NULL, i, &info) == true,
878 "Should be able to get info");
881 ENGINE_ERROR_CODE ret;
882 check((ret = store(h, h1, NULL, OPERATION_ADD, "key",
883 "somevalue", &i2, info.cas)) == ENGINE_KEY_EEXISTS,
884 "Should not be able to add the key two times");
886 h1->release(h, NULL, i);
887 h1->release(h, NULL, i2);
891 static enum test_result test_replace(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
894 uint64_t vb_uuid = 0;
895 uint32_t high_seqno = 0;
897 memset(&info, 0, sizeof(info));
899 check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue", &i) != ENGINE_SUCCESS,
900 "Failed to fail to replace non-existing value.");
902 h1->release(h, NULL, i);
903 check(store(h, h1, NULL, OPERATION_SET,"key", "somevalue", &i) == ENGINE_SUCCESS,
904 "Failed to set value.");
905 h1->release(h, NULL, i);
907 vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
908 high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
910 check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue", &i) == ENGINE_SUCCESS,
911 "Failed to replace existing value.");
912 h1->release(h, NULL, i);
914 check(get_item_info(h, h1, &info, "key"), "Error getting item info");
916 check(vb_uuid == info.vbucket_uuid, "Expected valid vbucket uuid");
917 check(high_seqno + 1 == info.seqno, "Expected valid sequence number");
919 check_key_value(h, h1, "key", "somevalue", 9);
923 static enum test_result test_replace_with_eviction(ENGINE_HANDLE *h,
924 ENGINE_HANDLE_V1 *h1) {
926 check(store(h, h1, NULL, OPERATION_SET,"key", "somevalue", &i) == ENGINE_SUCCESS,
927 "Failed to set value.");
928 h1->release(h, NULL, i);
929 wait_for_flusher_to_settle(h, h1);
930 evict_key(h, h1, "key");
931 int numBgFetched = get_int_stat(h, h1, "ep_bg_fetched");
933 check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue1", &i) == ENGINE_SUCCESS,
934 "Failed to replace existing value.");
936 check(h1->get_stats(h, NULL, NULL, 0, add_stats) == ENGINE_SUCCESS,
937 "Failed to get stats.");
938 std::string eviction_policy = vals.find("ep_item_eviction_policy")->second;
939 if (eviction_policy == "full_eviction") {
943 check(get_int_stat(h, h1, "ep_bg_fetched") == numBgFetched,
944 "Bg fetched value didn't match");
946 h1->release(h, NULL, i);
947 check_key_value(h, h1, "key", "somevalue1", 10);
951 static enum test_result test_incr_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
954 h1->arithmetic(h, NULL, "key", 3, true, false, 1, 0, 0,
955 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
957 h1->release(h, NULL, i);
958 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected to not find key");
962 static enum test_result test_incr_full_eviction(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
965 check(h1->arithmetic(h, NULL, "key", 3, true, true, 1, 1, 0,
966 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
967 0) == ENGINE_SUCCESS,
968 "Failed arithmetic operation");
969 h1->release(h, NULL, i);
970 check(result == 1, "Failed to set initial value in arithmetic operation");
974 static enum test_result test_incr_default(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
975 const void *cookie = testHarness.create_cookie();
976 testHarness.set_datatype_support(cookie, false);
980 check(h1->arithmetic(h, cookie, "key", 3, true, true, 1, 1, 0,
981 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
982 0) == ENGINE_SUCCESS,
983 "Failed first arith");
984 h1->release(h, cookie, i);
985 check(result == 1, "Failed result verification.");
987 // Check datatype of counter
988 check(h1->get(h, cookie, &i, "key", 3, 0) == ENGINE_SUCCESS,
989 "Unable to get stored item");
992 h1->get_item_info(h, cookie, i, &info);
993 h1->release(h, cookie, i);
994 check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
996 check(h1->arithmetic(h, cookie, "key", 3, true, false, 1, 1, 0,
997 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
998 0) == ENGINE_SUCCESS,
999 "Failed second arith.");
1000 h1->release(h, cookie, i);
1001 check(result == 2, "Failed second result verification.");
1003 check(h1->arithmetic(h, cookie, "key", 3, true, true, 1, 1, 0,
1004 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
1005 0) == ENGINE_SUCCESS,
1006 "Failed third arith.");
1007 h1->release(h, cookie, i);
1008 check(result == 3, "Failed third result verification.");
1010 check_key_value(h, h1, "key", "3", 1);
1012 // Check datatype of counter
1013 check(h1->get(h, cookie, &i, "key", 3, 0) == ENGINE_SUCCESS,
1014 "Unable to get stored item");
1016 h1->get_item_info(h, cookie, i, &info);
1017 h1->release(h, cookie, i);
1018 check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
1020 testHarness.destroy_cookie(cookie);
1024 static enum test_result test_append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1027 uint64_t vb_uuid = 0;
1028 uint32_t high_seqno = 0;
1030 memset(&info, 0, sizeof(info));
1032 // MB-11332: append on non-existing key should return NOT_STORED
1033 check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1034 "foo\r\n", 5, 82758, &i, 0, 0)
1035 == ENGINE_NOT_STORED,
1036 "MB-11332: Failed append.");
1037 h1->release(h, NULL, i);
1039 check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1040 "\r\n", 2, 82758, &i, 0, 0)
1044 h1->release(h, NULL, i);
1046 vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
1047 high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
1049 check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1050 "foo\r\n", 5, 82758, &i, 0, 0)
1053 h1->release(h, NULL, i);
1055 check(get_item_info(h, h1, &info, "key"), "Error in getting item info");
1057 check(vb_uuid == info.vbucket_uuid, "Expected valid vbucket uuid");
1058 check(high_seqno + 1 == info.seqno, "Expected valid sequence number");
1060 check_key_value(h, h1, "key", "\r\nfoo\r\n", 7);
1062 char binaryData1[] = "abcdefg\0gfedcba\r\n";
1063 char binaryData2[] = "abzdefg\0gfedcba\r\n";
1064 size_t dataSize = 20*1024*1024;
1065 char *bigBinaryData3 = new char[dataSize];
1066 memset(bigBinaryData3, '\0', dataSize);
1068 check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1069 binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
1072 h1->release(h, NULL, i);
1074 check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1075 bigBinaryData3, dataSize, 82758, &i, 0, 0)
1077 "Expected append failure.");
1078 h1->release(h, NULL, i);
1079 delete[] bigBinaryData3;
1081 check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1082 binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
1085 h1->release(h, NULL, i);
1087 std::string expected;
1088 expected.append(binaryData1, sizeof(binaryData1) - 1);
1089 expected.append(binaryData2, sizeof(binaryData2) - 1);
1091 check_key_value(h, h1, "key", expected.data(), expected.length());
1095 static enum test_result test_prepend(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1098 uint64_t vb_uuid = 0;
1099 uint32_t high_seqno = 0;
1101 memset(&info, 0, sizeof(info));
1103 // MB-11332: prepend on non-existing key should return NOT_STORED
1104 check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1105 "foo\r\n", 5, 82758, &i, 0, 0)
1106 == ENGINE_NOT_STORED,
1107 "MB-11332: Failed prepend.");
1108 h1->release(h, NULL, i);
1110 check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1111 "\r\n", 2, 82758, &i, 0, 0)
1114 h1->release(h, NULL, i);
1116 vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
1117 high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
1119 check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1120 "foo\r\n", 5, 82758, &i, 0, 0)
1123 h1->release(h, NULL, i);
1125 check(get_item_info(h, h1, &info, "key"), "Error getting item info");
1126 check(vb_uuid == info.vbucket_uuid, "Expected valid vbucket uuid");
1127 check(high_seqno + 1 == info.seqno, "Expected valid sequence number");
1129 check_key_value(h, h1, "key", "foo\r\n\r\n", 7);
1131 char binaryData1[] = "abcdefg\0gfedcba\r\n";
1132 char binaryData2[] = "abzdefg\0gfedcba\r\n";
1133 size_t dataSize = 20*1024*1024;
1134 char *bigBinaryData3 = new char[dataSize];
1135 memset(bigBinaryData3, '\0', dataSize);
1137 check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1138 binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
1141 h1->release(h, NULL, i);
1143 check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1144 bigBinaryData3, dataSize, 82758, &i, 0, 0)
1146 "Expected prepend failure.");
1147 h1->release(h, NULL, i);
1148 delete[] bigBinaryData3;
1150 check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1151 binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
1154 h1->release(h, NULL, i);
1156 std::string expected;
1157 expected.append(binaryData2, sizeof(binaryData2) - 1);
1158 expected.append(binaryData1, sizeof(binaryData1) - 1);
1160 check_key_value(h, h1, "key", expected.data(), expected.length());
1164 static enum test_result test_append_compressed(ENGINE_HANDLE *h,
1165 ENGINE_HANDLE_V1 *h1) {
1169 size_t len = snappy_max_compressed_length(2);
1170 char *newBuf = (char *) malloc (len);
1171 snappy_compress("\r\n", 2, newBuf, &len);
1172 check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key1",
1173 (const char *)newBuf, len, 82758, &i, 0, 0, 3600,
1174 PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1175 == ENGINE_SUCCESS, "Failed set.");
1176 h1->release(h, NULL, i);
1179 check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key1",
1180 "foo\r\n", 5, 82758, &i, 0, 0)
1182 "Failed append uncompressed to compressed.");
1183 h1->release(h, NULL, i);
1185 size_t len1 = snappy_max_compressed_length(7);
1186 char *newBuf1 = (char *) malloc (len1);
1187 snappy_compress("\r\nfoo\r\n", 7, newBuf1, &len1);
1190 check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
1191 check(info.nvalue == 1, "info.nvalue != 1");
1192 check(len1 == info.value[0].iov_len, "Value length mismatch");
1193 check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
1194 check(info.datatype == 0x02, "Datatype mismatch");
1197 len = snappy_max_compressed_length(3);
1198 newBuf = (char *) malloc (len);
1199 snappy_compress("bar", 3, newBuf, &len);
1200 check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key1",
1201 (const char*)newBuf, len, 82758, &i, 0, 0, 3600,
1202 PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1204 "Failed append compressed to compressed.");
1205 h1->release(h, NULL, i);
1208 len1 = snappy_max_compressed_length(10);
1209 newBuf1 = (char *) malloc (len1);
1210 snappy_compress("\r\nfoo\r\nbar", 10, newBuf1, &len1);
1212 check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
1213 check(info.nvalue == 1, "info.nvalue != 1");
1214 check(len1 == info.value[0].iov_len, "Value length mismatch");
1215 check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
1216 check(info.datatype == 0x02, "Datatype mismatch");
1219 check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key2",
1220 "foo", 3, 82758, &i, 0, 0, 3600,
1221 PROTOCOL_BINARY_RAW_BYTES)
1222 == ENGINE_SUCCESS, "Failed set.");
1223 h1->release(h, NULL, i);
1225 len = snappy_max_compressed_length(3);
1226 newBuf = (char *) malloc (len);
1227 snappy_compress("bar", 3, newBuf, &len);
1228 check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key2",
1229 newBuf, len, 82758, &i, 0, 0, 3600,
1230 PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1232 "Failed append compressed to uncompressed.");
1233 h1->release(h, NULL, i);
1236 check(get_item_info(h, h1, &info, "key2", 0), "checking key and value");
1237 check(info.nvalue == 1, "info.nvalue != 1");
1238 check(info.value[0].iov_len == 6, "Value length mismatch");
1239 check(memcmp(info.value[0].iov_base, "foobar", 6) == 0, "Data mismatch");
1240 check(info.datatype == 0x00, "Datatype mismatch");
1245 static enum test_result test_prepend_compressed(ENGINE_HANDLE *h,
1246 ENGINE_HANDLE_V1 *h1) {
1250 size_t len = snappy_max_compressed_length(2);
1251 char *newBuf = (char *) malloc (len);
1252 snappy_compress("\r\n", 2, newBuf, &len);
1253 check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key1",
1254 (const char *)newBuf, len, 82758, &i, 0, 0, 3600,
1255 PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1256 == ENGINE_SUCCESS, "Failed set.");
1257 h1->release(h, NULL, i);
1260 check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key1",
1261 "foo\r\n", 5, 82758, &i, 0, 0)
1263 "Failed prepend uncompressed to compressed.");
1264 h1->release(h, NULL, i);
1266 size_t len1 = snappy_max_compressed_length(7);
1267 char *newBuf1 = (char *) malloc (len1);
1268 snappy_compress("foo\r\n\r\n", 7, newBuf1, &len1);
1271 check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
1272 check(info.nvalue == 1, "info.nvalue != 1");
1273 check(len1 == info.value[0].iov_len, "Value length mismatch");
1274 check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
1275 check(info.datatype == 0x02, "Datatype mismatch");
1278 len = snappy_max_compressed_length(3);
1279 newBuf = (char *) malloc (len);
1280 snappy_compress("bar", 3, newBuf, &len);
1281 check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key1",
1282 (const char*)newBuf, len, 82758, &i, 0, 0, 3600,
1283 PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1285 "Failed prepend compressed to compressed.");
1286 h1->release(h, NULL, i);
1289 len1 = snappy_max_compressed_length(10);
1290 newBuf1 = (char *) malloc (len1);
1291 snappy_compress("barfoo\r\n\r\n", 10, newBuf1, &len1);
1293 check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
1294 check(info.nvalue == 1, "info.nvalue != 1");
1295 check(len1 == info.value[0].iov_len, "Value length mismatch");
1296 check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
1297 check(info.datatype == 0x02, "Datatype mismatch");
1300 check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key2",
1301 "foo", 3, 82758, &i, 0, 0, 3600,
1302 PROTOCOL_BINARY_RAW_BYTES)
1303 == ENGINE_SUCCESS, "Failed set.");
1304 h1->release(h, NULL, i);
1306 len = snappy_max_compressed_length(3);
1307 newBuf = (char *) malloc (len);
1308 snappy_compress("bar", 3, newBuf, &len);
1309 check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key2",
1310 newBuf, len, 82758, &i, 0, 0, 3600,
1311 PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1313 "Failed prepend compressed to uncompressed.");
1314 h1->release(h, NULL, i);
1317 check(get_item_info(h, h1, &info, "key2", 0), "checking key and value");
1318 check(info.nvalue == 1, "info.nvalue != 1");
1319 check(info.value[0].iov_len == 6, "Value length mismatch");
1320 check(memcmp(info.value[0].iov_base, "barfoo", 6) == 0, "Data mismatch");
1321 check(info.datatype == 0x00, "Datatype mismatch");
1326 static enum test_result test_append_prepend_to_json(ENGINE_HANDLE *h,
1327 ENGINE_HANDLE_V1 *h1) {
1331 const char* key1 = "foo1";
1332 const char* key2 = "foo2";
1333 const char* value1 = "{\"foo1\":\"bar1\"}";
1334 const char* value2 = "{\"foo2\":\"bar2\"}";
1337 check(storeCasVb11(h, h1, NULL, OPERATION_SET, key1,
1338 value1, strlen(value1), 82758, &i, 0, 0,
1339 3600, PROTOCOL_BINARY_DATATYPE_JSON)
1340 == ENGINE_SUCCESS, "Failed set.");
1341 h1->release(h, NULL, i);
1343 check(h1->get(h, NULL, &i, key1, strlen(key1), 0) == ENGINE_SUCCESS,
1344 "Unable to get stored item");
1346 h1->get_item_info(h, NULL, i, &info);
1347 check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1348 (int)info.value[0].iov_len) == 1, "Expected JSON");
1349 check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
1350 h1->release(h, NULL, i);
1352 check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, key1,
1353 value2, strlen(value2), 82758, &i, 0, 0)
1356 h1->release(h, NULL, i);
1358 check(h1->get(h, NULL, &i, key1, strlen(key1), 0) == ENGINE_SUCCESS,
1359 "Unable to get stored item");
1361 h1->get_item_info(h, NULL, i, &info);
1362 check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1363 (int)info.value[0].iov_len) == 0, "Expected Binary");
1364 check(info.datatype == PROTOCOL_BINARY_RAW_BYTES,
1365 "Invalid datatype after append");
1366 h1->release(h, NULL, i);
1369 check(storeCasVb11(h, h1, NULL, OPERATION_SET, key2,
1370 value1, strlen(value1), 82758, &i, 0, 0,
1371 3600, PROTOCOL_BINARY_DATATYPE_JSON)
1372 == ENGINE_SUCCESS, "Failed set.");
1373 h1->release(h, NULL, i);
1375 check(h1->get(h, NULL, &i, key2, strlen(key2), 0) == ENGINE_SUCCESS,
1376 "Unable to get stored item");
1378 h1->get_item_info(h, NULL, i, &info);
1379 check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1380 (int)info.value[0].iov_len) == 1, "Expected JSON");
1381 check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
1382 h1->release(h, NULL, i);
1384 check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, key2,
1385 value2, strlen(value2), 82758, &i, 0, 0)
1388 h1->release(h, NULL, i);
1390 check(h1->get(h, NULL, &i, key2, strlen(key2), 0) == ENGINE_SUCCESS,
1391 "Unable to get stored item");
1393 h1->get_item_info(h, NULL, i, &info);
1394 check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1395 (int)info.value[0].iov_len) == 0, "Expected Binary");
1396 check(info.datatype == PROTOCOL_BINARY_RAW_BYTES,
1397 "Invalid datatype after prepend");
1398 h1->release(h, NULL, i);
1403 static enum test_result test_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1404 const void *cookie = testHarness.create_cookie();
1405 testHarness.set_datatype_support(cookie, true);
1407 uint64_t result = 0;
1409 const char *key = "key";
1410 const char *val = "1";
1411 check(store(h, h1, NULL, OPERATION_ADD,key, val, &i,
1413 checkUTF8JSON((const unsigned char *)val, 1))
1415 "Failed to add value.");
1416 h1->release(h, NULL, i);
1418 check(h1->arithmetic(h, NULL, key, 3, true, false, 1, 1, 0,
1419 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
1420 0) == ENGINE_SUCCESS,
1421 "Failed to incr value.");
1422 h1->release(h, NULL, i);
1424 check_key_value(h, h1, key, "2", 1);
1426 // Check datatype of counter
1427 check(h1->get(h, cookie, &i, key, 3, 0) == ENGINE_SUCCESS,
1428 "Unable to get stored item");
1431 h1->get_item_info(h, cookie, i, &info);
1432 h1->release(h, cookie, i);
1433 check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
1435 testHarness.destroy_cookie(cookie);
1440 static enum test_result test_bug2799(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1441 uint64_t result = 0;
1443 check(store(h, h1, NULL, OPERATION_ADD, "key", "1", &i) == ENGINE_SUCCESS,
1444 "Failed to add value.");
1445 h1->release(h, NULL, i);
1447 check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
1448 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
1449 0) == ENGINE_SUCCESS,
1450 "Failed to incr value.");
1451 h1->release(h, NULL, i);
1453 check_key_value(h, h1, "key", "2", 1);
1455 testHarness.time_travel(3617);
1457 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1461 static enum test_result test_flush(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1464 if (get_int_stat(h, h1, "ep_flushall_enabled") == 0) {
1465 check(set_param(h, h1, protocol_binary_engine_param_flush,
1466 "flushall_enabled", "true"),
1467 "Set flushall_enabled should have worked");
1469 check(get_int_stat(h, h1, "ep_flushall_enabled") == 1,
1470 "flushall wasn't enabled");
1472 // First try to delete something we know to not be there.
1473 check(del(h, h1, "key", 0, 0) == ENGINE_KEY_ENOENT, "Failed to fail initial delete.");
1474 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1476 h1->release(h, NULL, i);
1477 check_key_value(h, h1, "key", "somevalue", 9);
1479 set_degraded_mode(h, h1, NULL, true);
1480 check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1482 set_degraded_mode(h, h1, NULL, false);
1484 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1486 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1487 "Failed post-flush set.");
1488 h1->release(h, NULL, i);
1489 check_key_value(h, h1, "key", "somevalue", 9);
1495 * The following struct: flush_args and function run_flush(),
1496 * will be used by the test that follows: test_multiple_flush
1500 ENGINE_HANDLE_V1 *h1;
1501 ENGINE_ERROR_CODE expect;
1506 static void run_flush_all(void *arguments) {
1507 const void *cookie = testHarness.create_cookie();
1508 testHarness.set_ewouldblock_handling(cookie, true);
1509 struct flush_args *args = (struct flush_args *)arguments;
1511 check((args->h1)->flush(args->h, cookie, args->when) == args->expect,
1512 "Return code is not what is expected");
1514 testHarness.destroy_cookie(cookie);
1518 static enum test_result test_multiple_flush(ENGINE_HANDLE *h,
1519 ENGINE_HANDLE_V1 *h1) {
1521 if (get_int_stat(h, h1, "ep_flushall_enabled") == 0) {
1522 check(set_param(h, h1, protocol_binary_engine_param_flush,
1523 "flushall_enabled", "true"),
1524 "Set flushall_enabled should have worked");
1526 check(get_int_stat(h, h1, "ep_flushall_enabled") == 1,
1527 "flushall wasn't enabled");
1530 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1532 h1->release(h, NULL, i);
1533 wait_for_flusher_to_settle(h, h1);
1534 check(get_int_stat(h, h1, "curr_items") == 1,
1535 "Expected curr_items equals 1");
1537 set_degraded_mode(h, h1, NULL, true);
1539 struct flush_args args1,args2;
1542 args1.expect = ENGINE_SUCCESS;
1544 check(cb_create_thread(&t1, run_flush_all, &args1, 0) == 0,
1545 "cb_create_thread failed!");
1551 args2.expect = ENGINE_TMPFAIL;
1553 check(cb_create_thread(&t2, run_flush_all, &args2, 0) == 0,
1554 "cb_create_thread failed!");
1556 cb_assert(cb_join_thread(t1) == 0);
1557 cb_assert(cb_join_thread(t2) == 0);
1559 set_degraded_mode(h, h1, NULL, false);
1561 testHarness.reload_engine(&h, &h1,
1562 testHarness.engine_path,
1563 testHarness.get_current_testcase()->cfg,
1565 wait_for_warmup_complete(h, h1);
1566 check(get_int_stat(h, h1, "curr_items") == 0,
1567 "Expected curr_items equals 0");
1572 static enum test_result test_flush_disabled(ENGINE_HANDLE *h,
1573 ENGINE_HANDLE_V1 *h1) {
1575 // start an engine with disabled flush, the flush() should be noop and
1576 // we expect to see the key after flush()
1578 // store a key and check its existence
1579 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1581 h1->release(h, NULL, i);
1582 check_key_value(h, h1, "key", "somevalue", 9);
1583 // expect error msg engine does not support operation
1584 check(h1->flush(h, NULL, 0) == ENGINE_ENOTSUP, "Flush should be disabled");
1586 check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1588 // restart engine with flush enabled and redo the test, we expect flush to succeed
1589 std::string param = "flushall_enabled=false";
1590 std::string config = testHarness.get_current_testcase()->cfg;
1591 size_t found = config.find(param);
1592 if(found != config.npos) {
1593 config.replace(found, param.size(), "flushall_enabled=true");
1595 testHarness.reload_engine(&h, &h1,
1596 testHarness.engine_path,
1599 wait_for_warmup_complete(h, h1);
1602 set_degraded_mode(h, h1, NULL, true);
1603 check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS, "Flush should be enabled");
1604 set_degraded_mode(h, h1, NULL, false);
1606 //expect missing key
1607 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1612 static enum test_result test_flush_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1614 int overhead = get_int_stat(h, h1, "ep_overhead");
1615 int cacheSize = get_int_stat(h, h1, "ep_total_cache_size");
1616 int nonResident = get_int_stat(h, h1, "ep_num_non_resident");
1618 int itemsRemoved = get_int_stat(h, h1, "ep_items_rm_from_checkpoints");
1619 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1621 h1->release(h, NULL, i);
1622 check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i) == ENGINE_SUCCESS,
1624 h1->release(h, NULL, i);
1625 testHarness.time_travel(65);
1626 wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
1628 check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1629 check(ENGINE_SUCCESS == verify_key(h, h1, "key2"), "Expected key2");
1631 check_key_value(h, h1, "key", "somevalue", 9);
1632 check_key_value(h, h1, "key2", "somevalue", 9);
1634 int overhead2 = get_int_stat(h, h1, "ep_overhead");
1635 int cacheSize2 = get_int_stat(h, h1, "ep_total_cache_size");
1637 set_degraded_mode(h, h1, NULL, true);
1638 check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS, "Failed to flush");
1639 set_degraded_mode(h, h1, NULL, false);
1640 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1641 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key2"), "Expected missing key");
1643 wait_for_flusher_to_settle(h, h1);
1645 overhead2 = get_int_stat(h, h1, "ep_overhead");
1646 cacheSize2 = get_int_stat(h, h1, "ep_total_cache_size");
1647 int nonResident2 = get_int_stat(h, h1, "ep_num_non_resident");
1649 cb_assert(overhead2 == overhead);
1650 cb_assert(nonResident2 == nonResident);
1651 cb_assert(cacheSize2 == cacheSize);
1656 static enum test_result test_flush_multiv(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1658 check(set_vbucket_state(h, h1, 2, vbucket_state_active), "Failed to set vbucket state.");
1659 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1661 h1->release(h, NULL, i);
1662 check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i,
1663 0, 2) == ENGINE_SUCCESS,
1664 "Failed set in vb2.");
1665 h1->release(h, NULL, i);
1667 check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1668 check(ENGINE_SUCCESS == verify_key(h, h1, "key2", 2), "Expected key2");
1670 check_key_value(h, h1, "key", "somevalue", 9);
1671 check_key_value(h, h1, "key2", "somevalue", 9, 2);
1673 set_degraded_mode(h, h1, NULL, true);
1674 check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS, "Failed to flush");
1675 set_degraded_mode(h, h1, NULL, false);
1678 check(h1->get_stats(h, NULL, NULL, 0, add_stats) == ENGINE_SUCCESS,
1679 "Failed to get stats.");
1680 check(vals.find("ep_flush_all") != vals.end(), "Failed to get the status of flush_all");
1682 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1683 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key2", 2), "Expected missing key");
1688 static int checkCurrItemsAfterShutdown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
1689 int numItems2Load, bool shutdownForce) {
1690 std::vector<std::string> keys;
1691 for (int index = 0; index < numItems2Load; ++index) {
1692 std::stringstream s;
1693 s << "keys_2_load-" << index;
1694 std::string key(s.str());
1695 keys.push_back(key);
1698 check(get_int_stat(h, h1, "ep_total_persisted") == 0,
1699 "Expected ep_total_persisted equals 0");
1700 check(get_int_stat(h, h1, "curr_items") == 0,
1701 "Expected curr_items equals 0");
1703 // stop flusher before loading new items
1704 protocol_binary_request_header *pkt = createPacket(PROTOCOL_BINARY_CMD_STOP_PERSISTENCE);
1705 check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
1706 "CMD_STOP_PERSISTENCE failed!");
1707 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
1708 "Failed to stop persistence!");
1711 std::vector<std::string>::iterator itr;
1712 for (itr = keys.begin(); itr != keys.end(); ++itr) {
1714 check(store(h, h1, NULL, OPERATION_SET, itr->c_str(), "oracle", &i, 0, 0)
1715 == ENGINE_SUCCESS, "Failed to store a value");
1716 h1->release(h, NULL, i);
1719 check(get_int_stat(h, h1, "ep_total_persisted") == 0,
1720 "Incorrect ep_total_persisted, expected 0");
1721 std::stringstream ss;
1722 ss << "Incorrect curr_items, expected " << numItems2Load;
1723 std::string errmsg(ss.str());
1724 check(get_int_stat(h, h1, "curr_items") == numItems2Load,
1727 // resume flusher before shutdown + warmup
1728 pkt = createPacket(PROTOCOL_BINARY_CMD_START_PERSISTENCE);
1729 check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
1730 "CMD_START_PERSISTENCE failed!");
1731 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
1732 "Failed to start persistence!");
1735 // shutdown engine force and restart
1736 testHarness.reload_engine(&h, &h1,
1737 testHarness.engine_path,
1738 testHarness.get_current_testcase()->cfg,
1739 true, shutdownForce);
1740 wait_for_warmup_complete(h, h1);
1741 return get_int_stat(h, h1, "curr_items");
1744 static enum test_result test_flush_shutdown_force(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1745 int numItems2load = 3000;
1746 bool shutdownForce = true;
1747 int currItems = checkCurrItemsAfterShutdown(h, h1, numItems2load, shutdownForce);
1748 check (currItems <= numItems2load,
1749 "Number of curr items should be <= 3000, unless previous "
1750 "shutdown force had to wait for the flusher");
1754 static enum test_result test_flush_shutdown_noforce(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1755 int numItems2load = 3000;
1756 bool shutdownForce = false;
1757 int currItems = checkCurrItemsAfterShutdown(h, h1, numItems2load, shutdownForce);
1758 check (currItems == numItems2load,
1759 "Number of curr items should be equal to 3000, unless previous "
1760 "shutdown did not wait for the flusher");
1764 static enum test_result test_flush_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1766 // First try to delete something we know to not be there.
1767 check(del(h, h1, "key", 0, 0) == ENGINE_KEY_ENOENT, "Failed to fail initial delete.");
1768 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1770 h1->release(h, NULL, i);
1771 check_key_value(h, h1, "key", "somevalue", 9);
1773 // Restart once to ensure written to disk.
1774 testHarness.reload_engine(&h, &h1,
1775 testHarness.engine_path,
1776 testHarness.get_current_testcase()->cfg,
1778 wait_for_warmup_complete(h, h1);
1780 // Read value from disk.
1781 check_key_value(h, h1, "key", "somevalue", 9);
1784 set_degraded_mode(h, h1, NULL, true);
1785 check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1787 set_degraded_mode(h, h1, NULL, false);
1789 check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i) == ENGINE_SUCCESS,
1790 "Failed post-flush set.");
1791 h1->release(h, NULL, i);
1792 check_key_value(h, h1, "key2", "somevalue", 9);
1794 // Restart again, ensure written to disk.
1795 testHarness.reload_engine(&h, &h1,
1796 testHarness.engine_path,
1797 testHarness.get_current_testcase()->cfg,
1799 wait_for_warmup_complete(h, h1);
1801 check(store(h, h1, NULL, OPERATION_SET, "key3", "somevalue", &i) == ENGINE_SUCCESS,
1802 "Failed post-flush, post-restart set.");
1803 h1->release(h, NULL, i);
1804 check_key_value(h, h1, "key3", "somevalue", 9);
1806 // Read value again, should not be there.
1807 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1811 static enum test_result test_flush_multiv_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1813 check(set_vbucket_state(h, h1, 2, vbucket_state_active), "Failed to set vbucket state.");
1814 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1816 h1->release(h, NULL, i);
1817 check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i,
1818 0, 2) == ENGINE_SUCCESS,
1819 "Failed set in vb2.");
1820 h1->release(h, NULL, i);
1822 // Restart once to ensure written to disk.
1823 testHarness.reload_engine(&h, &h1,
1824 testHarness.engine_path,
1825 testHarness.get_current_testcase()->cfg,
1827 wait_for_warmup_complete(h, h1);
1829 // Read value from disk.
1830 check_key_value(h, h1, "key", "somevalue", 9);
1833 set_degraded_mode(h, h1, NULL, true);
1834 check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1836 set_degraded_mode(h, h1, NULL, false);
1838 // Restart again, ensure written to disk.
1839 testHarness.reload_engine(&h, &h1,
1840 testHarness.engine_path,
1841 testHarness.get_current_testcase()->cfg,
1843 wait_for_warmup_complete(h, h1);
1845 // Read value again, should not be there.
1846 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1847 check(verify_vbucket_missing(h, h1, 2), "Bucket 2 came back.");
1851 static enum test_result test_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1853 // First try to delete something we know to not be there.
1854 check(del(h, h1, "key", 0, 0) == ENGINE_KEY_ENOENT, "Failed to fail initial delete.");
1855 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1857 Item *it = reinterpret_cast<Item*>(i);
1858 uint64_t orig_cas = it->getCas();
1859 h1->release(h, NULL, i);
1860 check_key_value(h, h1, "key", "somevalue", 9);
1863 uint64_t vb_uuid = 0;
1864 mutation_descr_t mut_info;
1865 uint32_t high_seqno = 0;
1867 memset(&mut_info, 0, sizeof(mut_info));
1869 vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
1870 high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
1871 check(h1->remove(h, NULL, "key", 3, &cas, 0, &mut_info) == ENGINE_SUCCESS,
1872 "Failed remove with value.");
1873 check(orig_cas + 1 == cas, "Cas mismatch on delete");
1874 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1875 check(vb_uuid == mut_info.vbucket_uuid, "Expected valid vbucket uuid");
1876 check(high_seqno + 1 == mut_info.seqno, "Expected valid sequence number");
1878 // Can I time travel to an expired object and delete it?
1879 checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1881 h1->release(h, NULL, i);
1882 testHarness.time_travel(3617);
1883 checkeq(ENGINE_KEY_ENOENT, del(h, h1, "key", 0, 0),
1884 "Did not get ENOENT removing an expired object.");
1885 checkeq(ENGINE_KEY_ENOENT, verify_key(h, h1, "key"), "Expected missing key");
1890 static enum test_result test_set_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1892 checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1894 h1->release(h, NULL, i);
1895 check_key_value(h, h1, "key", "somevalue", 9);
1896 checkeq(ENGINE_SUCCESS, del(h, h1, "key", 0, 0),
1897 "Failed remove with value.");
1898 checkeq(ENGINE_KEY_ENOENT, verify_key(h, h1, "key"), "Expected missing key");
1899 wait_for_flusher_to_settle(h, h1);
1900 wait_for_stat_to_be(h, h1, "curr_items", 0);
1904 static enum test_result test_set_delete_invalid_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1906 check(store(h, h1, NULL, OPERATION_SET, "key",
1907 "somevalue", &i) == ENGINE_SUCCESS,
1909 check_key_value(h, h1, "key", "somevalue", 9);
1912 check(h1->get_item_info(h, NULL, i, &info) == true,
1913 "Should be able to get info");
1914 h1->release(h, NULL, i);
1916 check(del(h, h1, "key", info.cas + 1, 0) == ENGINE_KEY_EEXISTS,
1917 "Didn't expect to be able to remove the item with wrong cas");
1921 static enum test_result test_bug2509(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1922 for (int j = 0; j < 10000; ++j) {
1924 checkeq(ENGINE_SUCCESS,
1925 store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &itm),
1927 h1->release(h, NULL, itm);
1929 checkeq(ENGINE_SUCCESS, del(h, h1, "key", 0, 0), "Failed remove with value.");
1933 // Restart again, to verify we don't have any duplicates.
1934 testHarness.reload_engine(&h, &h1,
1935 testHarness.engine_path,
1936 testHarness.get_current_testcase()->cfg,
1938 wait_for_warmup_complete(h, h1);
1940 return get_int_stat(h, h1, "ep_warmup_dups") == 0 ? SUCCESS : FAIL;
1943 static enum test_result test_bug7023(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1944 std::vector<std::string> keys;
1945 // Make a vbucket mess.
1946 for (int j = 0; j < 10000; ++j) {
1947 std::stringstream ss;
1949 std::string key(ss.str());
1950 keys.push_back(key);
1953 std::vector<std::string>::iterator it;
1954 for (int j = 0; j < 5; ++j) {
1955 check(set_vbucket_state(h, h1, 0, vbucket_state_dead), "Failed set set vbucket 0 dead.");
1956 vbucketDelete(h, h1, 0);
1957 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
1958 "Expected vbucket deletion to work.");
1959 check(set_vbucket_state(h, h1, 0, vbucket_state_active), "Failed set set vbucket 0 active.");
1960 for (it = keys.begin(); it != keys.end(); ++it) {
1962 check(store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(), &i)
1963 == ENGINE_SUCCESS, "Failed to store a value");
1964 h1->release(h, NULL, i);
1968 wait_for_flusher_to_settle(h, h1);
1970 // Restart again, to verify no data loss.
1971 testHarness.reload_engine(&h, &h1,
1972 testHarness.engine_path,
1973 testHarness.get_current_testcase()->cfg,
1975 wait_for_warmup_complete(h, h1);
1976 return get_int_stat(h, h1, "ep_warmup_value_count", "warmup") == 10000 ? SUCCESS : FAIL;
1979 static enum test_result test_delete_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1980 wait_for_persisted_value(h, h1, "key", "value1");
1982 check(del(h, h1, "key", 0, 0) == ENGINE_SUCCESS, "Failed remove with value.");
1984 wait_for_persisted_value(h, h1, "key", "value2");
1986 testHarness.reload_engine(&h, &h1,
1987 testHarness.engine_path,
1988 testHarness.get_current_testcase()->cfg,
1990 wait_for_warmup_complete(h, h1);
1992 check_key_value(h, h1, "key", "value2", 6);
1993 check(del(h, h1, "key", 0, 0) == ENGINE_SUCCESS, "Failed remove with value.");
1994 wait_for_flusher_to_settle(h, h1);
1996 testHarness.reload_engine(&h, &h1,
1997 testHarness.engine_path,
1998 testHarness.get_current_testcase()->cfg,
2000 wait_for_warmup_complete(h, h1);
2002 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
2007 static enum test_result test_get_delete_missing_file(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2008 const char *key = "key";
2009 wait_for_persisted_value(h, h1, key, "value2delete");
2011 // whack the db file and directory where the key is stored
2015 int errorCode = h1->get(h, NULL, &i, key, strlen(key), 0);
2016 h1->release(h, NULL, i);
2018 // ep engine must be unaware of well-being of the db file as long as
2019 // the item is still in the memory
2020 check(errorCode == ENGINE_SUCCESS, "Expected success for get");
2023 evict_key(h, h1, key);
2024 errorCode = h1->get(h, NULL, &i, key, strlen(key), 0);
2025 h1->release(h, NULL, i);
2027 // ep engine must be now aware of the ill-fated db file where
2028 // the item is supposedly stored
2029 check(errorCode == ENGINE_TMPFAIL, "Expected tmp fail for get");
2035 static enum test_result test_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2037 static const char val[] = "somevalue";
2038 ENGINE_ERROR_CODE ret;
2039 check((ret = store(h, h1, NULL, OPERATION_SET, "key", val, &i)) == ENGINE_SUCCESS,
2041 h1->release(h, NULL, i);
2043 testHarness.reload_engine(&h, &h1,
2044 testHarness.engine_path,
2045 testHarness.get_current_testcase()->cfg,
2047 wait_for_warmup_complete(h, h1);
2048 check_key_value(h, h1, "key", val, strlen(val));
2052 static enum test_result test_restart_session_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2053 createTapConn(h, h1, "tap_client_thread");
2055 testHarness.reload_engine(&h, &h1,
2056 testHarness.engine_path,
2057 testHarness.get_current_testcase()->cfg,
2059 wait_for_warmup_complete(h, h1);
2060 createTapConn(h, h1, "tap_client_thread");
2062 check(h1->get_stats(h, NULL, "tap", 3, add_stats) == ENGINE_SUCCESS,
2063 "Failed to get stats.");
2064 std::string val = vals["eq_tapq:tap_client_thread:backfill_completed"];
2065 check(strcmp(val.c_str(), "true") == 0, "Don't expect the backfill upon restart");
2069 static enum test_result test_specialKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2071 ENGINE_ERROR_CODE ret;
2073 // Simplified Chinese "Couchbase"
2074 static const char key0[] = "沙发数据库";
2075 static const char val0[] = "some Chinese value";
2076 check((ret = store(h, h1, NULL, OPERATION_SET, key0, val0, &i)) == ENGINE_SUCCESS,
2077 "Failed set Chinese key");
2078 check_key_value(h, h1, key0, val0, strlen(val0));
2079 h1->release(h, NULL, i);
2080 // Traditional Chinese "Couchbase"
2081 static const char key1[] = "沙發數據庫";
2082 static const char val1[] = "some Traditional Chinese value";
2083 check((ret = store(h, h1, NULL, OPERATION_SET, key1, val1, &i)) == ENGINE_SUCCESS,
2084 "Failed set Traditional Chinese key");
2085 h1->release(h, NULL, i);
2086 // Korean "couch potato"
2087 static const char key2[] = "쇼파감자";
2088 static const char val2[] = "some Korean value";
2089 check((ret = store(h, h1, NULL, OPERATION_SET, key2, val2, &i)) == ENGINE_SUCCESS,
2090 "Failed set Korean key");
2091 h1->release(h, NULL, i);
2092 // Russian "couch potato"
2093 static const char key3[] = "лодырь, лентяй";
2094 static const char val3[] = "some Russian value";
2095 check((ret = store(h, h1, NULL, OPERATION_SET, key3, val3, &i)) == ENGINE_SUCCESS,
2096 "Failed set Russian key");
2097 h1->release(h, NULL, i);
2098 // Japanese "couch potato"
2099 static const char key4[] = "カウチポテト";
2100 static const char val4[] = "some Japanese value";
2101 check((ret = store(h, h1, NULL, OPERATION_SET, key4, val4, &i)) == ENGINE_SUCCESS,
2102 "Failed set Japanese key");
2103 h1->release(h, NULL, i);
2104 // Indian char key, and no idea what it is
2105 static const char key5[] = "हरियानवी";
2106 static const char val5[] = "some Indian value";
2107 check((ret = store(h, h1, NULL, OPERATION_SET, key5, val5, &i)) == ENGINE_SUCCESS,
2108 "Failed set Indian key");
2109 h1->release(h, NULL, i);
2110 // Portuguese translation "couch potato"
2111 static const char key6[] = "sedentário";
2112 static const char val6[] = "some Portuguese value";
2113 check((ret = store(h, h1, NULL, OPERATION_SET, key6, val6, &i)) == ENGINE_SUCCESS,
2114 "Failed set Portuguese key");
2115 h1->release(h, NULL, i);
2116 // Arabic translation "couch potato"
2117 static const char key7[] = "الحافلةالبطاطة";
2118 static const char val7[] = "some Arabic value";
2119 check((ret = store(h, h1, NULL, OPERATION_SET, key7, val7, &i)) == ENGINE_SUCCESS,
2120 "Failed set Arabic key");
2121 h1->release(h, NULL, i);
2123 testHarness.reload_engine(&h, &h1,
2124 testHarness.engine_path,
2125 testHarness.get_current_testcase()->cfg,
2127 wait_for_warmup_complete(h, h1);
2128 check_key_value(h, h1, key0, val0, strlen(val0));
2129 check_key_value(h, h1, key1, val1, strlen(val1));
2130 check_key_value(h, h1, key2, val2, strlen(val2));
2131 check_key_value(h, h1, key3, val3, strlen(val3));
2132 check_key_value(h, h1, key4, val4, strlen(val4));
2133 check_key_value(h, h1, key5, val5, strlen(val5));
2134 check_key_value(h, h1, key6, val6, strlen(val6));
2135 check_key_value(h, h1, key7, val7, strlen(val7));
2139 static enum test_result test_binKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2141 ENGINE_ERROR_CODE ret;
2143 // binary key with char values beyond 0x7F
2144 static const char key0[] = "\xe0\xed\xf1\x6f\x7f\xf8\xfa";
2145 static const char val0[] = "some value val8";
2146 check((ret = store(h, h1, NULL, OPERATION_SET, key0, val0, &i)) == ENGINE_SUCCESS,
2147 "Failed set binary key0");
2148 check_key_value(h, h1, key0, val0, strlen(val0));
2149 h1->release(h, NULL, i);
2150 // binary keys with char values beyond 0x7F
2151 static const char key1[] = "\xf1\xfd\xfe\xff\xf0\xf8\xef";
2152 static const char val1[] = "some value val9";
2153 check((ret = store(h, h1, NULL, OPERATION_SET, key1, val1, &i)) == ENGINE_SUCCESS,
2154 "Failed set binary key1");
2155 check_key_value(h, h1, key1, val1, strlen(val1));
2156 h1->release(h, NULL, i);
2157 // binary keys with special utf-8 BOM (Byte Order Mark) values 0xBB 0xBF 0xEF
2158 static const char key2[] = "\xff\xfe\xbb\xbf\xef";
2159 static const char val2[] = "some utf-8 bom value";
2160 check((ret = store(h, h1, NULL, OPERATION_SET, key2, val2, &i)) == ENGINE_SUCCESS,
2161 "Failed set binary utf-8 bom key");
2162 check_key_value(h, h1, key2, val2, strlen(val2));
2163 h1->release(h, NULL, i);
2164 // binary keys with special utf-16BE BOM values "U+FEFF"
2165 static const char key3[] = "U+\xfe\xff\xefU+\xff\xfe";
2166 static const char val3[] = "some utf-16 bom value";
2167 check((ret = store(h, h1, NULL, OPERATION_SET, key3, val3, &i)) == ENGINE_SUCCESS,
2168 "Failed set binary utf-16 bom key");
2169 check_key_value(h, h1, key3, val3, strlen(val3));
2170 h1->release(h, NULL, i);
2172 testHarness.reload_engine(&h, &h1,
2173 testHarness.engine_path,
2174 testHarness.get_current_testcase()->cfg,
2176 wait_for_warmup_complete(h, h1);
2177 check_key_value(h, h1, key0, val0, strlen(val0));
2178 check_key_value(h, h1, key1, val1, strlen(val1));
2179 check_key_value(h, h1, key2, val2, strlen(val2));
2180 check_key_value(h, h1, key3, val3, strlen(val3));
2184 static enum test_result test_restart_bin_val(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2188 char binaryData[] = "abcdefg\0gfedcba";
2189 cb_assert(sizeof(binaryData) != strlen(binaryData));
2192 check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
2193 binaryData, sizeof(binaryData), 82758, &i, 0, 0)
2196 h1->release(h, NULL, i);
2198 testHarness.reload_engine(&h, &h1,
2199 testHarness.engine_path,
2200 testHarness.get_current_testcase()->cfg,
2202 wait_for_warmup_complete(h, h1);
2204 check_key_value(h, h1, "key", binaryData, sizeof(binaryData));
2208 static enum test_result test_wrong_vb_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2209 int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2210 check(ENGINE_NOT_MY_VBUCKET == verify_key(h, h1, "key", 1),
2211 "Expected wrong bucket.");
2212 wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2216 static enum test_result test_vb_get_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2217 check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
2218 const void *cookie = testHarness.create_cookie();
2219 testHarness.set_ewouldblock_handling(cookie, false);
2222 check(ENGINE_EWOULDBLOCK == h1->get(h, cookie, &i, "key", strlen("key"), 1),
2223 "Expected woodblock.");
2224 h1->release(h, NULL, i);
2226 testHarness.destroy_cookie(cookie);
2230 static enum test_result test_vb_get_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2231 check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
2232 int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2233 check(ENGINE_NOT_MY_VBUCKET == verify_key(h, h1, "key", 1),
2234 "Expected not my bucket.");
2235 wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2239 static enum test_result test_wrong_vb_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2242 int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2243 check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
2244 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
2245 1) == ENGINE_NOT_MY_VBUCKET,
2246 "Expected not my vbucket.");
2247 h1->release(h, NULL, i);
2248 wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2252 static enum test_result test_vb_incr_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2253 const void *cookie = testHarness.create_cookie();
2254 testHarness.set_ewouldblock_handling(cookie, false);
2257 check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
2258 check(h1->arithmetic(h, cookie, "key", 3, true, false, 1, 1, 0,
2259 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
2260 1) == ENGINE_EWOULDBLOCK,
2261 "Expected wouldblock.");
2262 h1->release(h, NULL, i);
2263 testHarness.destroy_cookie(cookie);
2267 static enum test_result test_vb_incr_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2270 check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
2271 int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2272 check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
2273 &i, PROTOCOL_BINARY_RAW_BYTES, &result,
2274 1) == ENGINE_NOT_MY_VBUCKET,
2275 "Expected not my bucket.");
2276 h1->release(h, NULL, i);
2277 wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2281 static enum test_result test_wrong_vb_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2282 return test_wrong_vb_mutation(h, h1, OPERATION_SET);
2285 static enum test_result test_wrong_vb_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2286 return test_wrong_vb_mutation(h, h1, OPERATION_CAS);
2289 static enum test_result test_wrong_vb_add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2290 return test_wrong_vb_mutation(h, h1, OPERATION_ADD);
2293 static enum test_result test_wrong_vb_replace(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2294 return test_wrong_vb_mutation(h, h1, OPERATION_REPLACE);
2297 static enum test_result test_wrong_vb_append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2298 return test_wrong_vb_mutation(h, h1, OPERATION_APPEND);
2301 static enum test_result test_wrong_vb_prepend(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2302 return test_wrong_vb_mutation(h, h1, OPERATION_PREPEND);
2305 static enum test_result test_wrong_vb_del(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2306 int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2307 check(ENGINE_NOT_MY_VBUCKET == del(h, h1, "key", 0, 1), "Expected wrong bucket.");
2308 wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2312 static enum test_result test_expiry(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2313 const char *key = "test_expiry";
2314 const char *data = "some test data here.";
2318 ENGINE_ERROR_CODE rv;
2319 rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 2,
2320 PROTOCOL_BINARY_RAW_BYTES);
2321 check(rv == ENGINE_SUCCESS, "Allocation failed.");
2325 if (!h1->get_item_info(h, NULL, it, &info)) {
2328 memcpy(info.value[0].iov_base, data, strlen(data));
2331 rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2332 check(rv == ENGINE_SUCCESS, "Set failed.");
2333 check_key_value(h, h1, key, data, strlen(data));
2334 h1->release(h, NULL, it);
2336 testHarness.time_travel(5);
2337 check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
2338 "Item didn't expire");
2340 int expired_access = get_int_stat(h, h1, "ep_expired_access");
2341 int expired_pager = get_int_stat(h, h1, "ep_expired_pager");
2342 int active_expired = get_int_stat(h, h1, "vb_active_expired");
2343 check(expired_pager == 0, "Expected zero expired item by pager");
2344 check(expired_access == 1, "Expected an expired item on access");
2345 check(active_expired == 1, "Expected an expired active item");
2346 checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, key, data, &it),
2348 h1->release(h, NULL, it);
2350 std::stringstream ss;
2351 ss << "curr_items stat should be still 1 after ";
2352 ss << "overwriting the key that was expired, but not purged yet";
2353 checkeq(1, get_int_stat(h, h1, "curr_items"), ss.str().c_str());
2358 static enum test_result test_expiry_loader(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2359 const char *key = "test_expiry_loader";
2360 const char *data = "some test data here.";
2364 ENGINE_ERROR_CODE rv;
2365 rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 2,
2366 PROTOCOL_BINARY_RAW_BYTES);
2367 check(rv == ENGINE_SUCCESS, "Allocation failed.");
2371 if (!h1->get_item_info(h, NULL, it, &info)) {
2374 memcpy(info.value[0].iov_base, data, strlen(data));
2377 rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2378 check(rv == ENGINE_SUCCESS, "Set failed.");
2379 check_key_value(h, h1, key, data, strlen(data));
2380 h1->release(h, NULL, it);
2382 testHarness.time_travel(3);
2384 check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
2385 "Item didn't expire");
2387 // Restart the engine to ensure the above expired item is not loaded
2388 testHarness.reload_engine(&h, &h1,
2389 testHarness.engine_path,
2390 testHarness.get_current_testcase()->cfg,
2392 wait_for_warmup_complete(h, h1);
2393 cb_assert(0 == get_int_stat(h, h1, "ep_warmup_value_count", "warmup"));
2398 static enum test_result test_expiration_on_warmup(ENGINE_HANDLE *h,
2399 ENGINE_HANDLE_V1 *h1) {
2400 const char *key = "KEY";
2401 const char *data = "VALUE";
2405 ENGINE_ERROR_CODE rv;
2406 rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 3,
2407 PROTOCOL_BINARY_RAW_BYTES);
2408 check(rv == ENGINE_SUCCESS, "Allocation failed.");
2412 if (!h1->get_item_info(h, NULL, it, &info)) {
2415 memcpy(info.value[0].iov_base, data, strlen(data));
2418 rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2419 check(rv == ENGINE_SUCCESS, "Set failed.");
2420 check_key_value(h, h1, key, data, strlen(data));
2421 h1->release(h, NULL, it);
2422 wait_for_flusher_to_settle(h, h1);
2424 check(get_int_stat(h, h1, "curr_items") == 1, "Failed store item");
2425 testHarness.time_travel(5);
2427 // Restart the engine to ensure the above item is expired
2428 testHarness.reload_engine(&h, &h1,
2429 testHarness.engine_path,
2430 testHarness.get_current_testcase()->cfg,
2432 wait_for_warmup_complete(h, h1);
2433 int pager_runs = get_int_stat(h, h1, "ep_num_expiry_pager_runs");
2434 wait_for_stat_change(h, h1, "ep_num_expiry_pager_runs", pager_runs);
2435 wait_for_flusher_to_settle(h, h1);
2436 check(get_int_stat(h, h1, "curr_items") == 0,
2437 "The item should have been expired.");
2443 static enum test_result test_bug3454(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2444 const char *key = "test_expiry_duplicate_warmup";
2445 const char *data = "some test data here.";
2449 ENGINE_ERROR_CODE rv;
2450 rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 5,
2451 PROTOCOL_BINARY_RAW_BYTES);
2452 check(rv == ENGINE_SUCCESS, "Allocation failed.");
2456 if (!h1->get_item_info(h, NULL, it, &info)) {
2459 memcpy(info.value[0].iov_base, data, strlen(data));
2462 rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2463 check(rv == ENGINE_SUCCESS, "Set failed.");
2464 check_key_value(h, h1, key, data, strlen(data));
2465 h1->release(h, NULL, it);
2466 wait_for_flusher_to_settle(h, h1);
2468 // Advance the ep_engine time by 10 sec for the above item to be expired.
2469 testHarness.time_travel(10);
2470 check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
2471 "Item didn't expire");
2473 rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 0,
2474 PROTOCOL_BINARY_RAW_BYTES);
2475 check(rv == ENGINE_SUCCESS, "Allocation failed.");
2478 if (!h1->get_item_info(h, NULL, it, &info)) {
2481 memcpy(info.value[0].iov_base, data, strlen(data));
2484 // Add a new item with the same key.
2485 rv = h1->store(h, NULL, it, &cas, OPERATION_ADD, 0);
2486 check(rv == ENGINE_SUCCESS, "Add failed.");
2487 check_key_value(h, h1, key, data, strlen(data));
2488 h1->release(h, NULL, it);
2490 check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_SUCCESS,
2491 "Item shouldn't expire");
2492 h1->release(h, NULL, it);
2494 // Restart the engine to ensure the above unexpired new item is loaded
2495 testHarness.reload_engine(&h, &h1,
2496 testHarness.engine_path,
2497 testHarness.get_current_testcase()->cfg,
2499 wait_for_warmup_complete(h, h1);
2500 cb_assert(1 == get_int_stat(h, h1, "ep_warmup_value_count", "warmup"));
2501 cb_assert(0 == get_int_stat(h, h1, "ep_warmup_dups", "warmup"));
2506 static enum test_result test_bug3522(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2507 const char *key = "test_expiry_no_items_warmup";
2508 const char *data = "some test data here.";
2512 ENGINE_ERROR_CODE rv;
2513 rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 0,
2514 PROTOCOL_BINARY_RAW_BYTES);
2515 check(rv == ENGINE_SUCCESS, "Allocation failed.");
2519 if (!h1->get_item_info(h, NULL, it, &info)) {
2522 memcpy(info.value[0].iov_base, data, strlen(data));
2525 rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2526 check(rv == ENGINE_SUCCESS, "Set failed.");
2527 check_key_value(h, h1, key, data, strlen(data));
2528 h1->release(h, NULL, it);
2529 wait_for_flusher_to_settle(h, h1);
2531 // Add a new item with the same key and 2 sec of expiration.
2532 const char *new_data = "new data here.";
2533 rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(new_data), 0, 2,
2534 PROTOCOL_BINARY_RAW_BYTES);
2535 check(rv == ENGINE_SUCCESS, "Allocation failed.");
2538 if (!h1->get_item_info(h, NULL, it, &info)) {
2541 memcpy(info.value[0].iov_base, new_data, strlen(new_data));
2543 int pager_runs = get_int_stat(h, h1, "ep_num_expiry_pager_runs");
2545 rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2546 check(rv == ENGINE_SUCCESS, "Set failed.");
2547 check_key_value(h, h1, key, new_data, strlen(new_data));
2548 h1->release(h, NULL, it);
2549 testHarness.time_travel(3);
2550 wait_for_stat_change(h, h1, "ep_num_expiry_pager_runs", pager_runs);
2551 wait_for_flusher_to_settle(h, h1);
2553 // Restart the engine.
2554 testHarness.reload_engine(&h, &h1,
2555 testHarness.engine_path,
2556 testHarness.get_current_testcase()->cfg,
2558 wait_for_warmup_complete(h, h1);
2559 // TODO: modify this for a better test case
2560 cb_assert(0 == get_int_stat(h, h1, "ep_warmup_dups", "warmup"));
2565 static enum test_result test_get_replica_active_state(ENGINE_HANDLE *h,
2566 ENGINE_HANDLE_V1 *h1) {
2567 protocol_binary_request_header *pkt;
2568 pkt = prepare_get_replica(h, h1, vbucket_state_active);
2569 check(h1->unknown_command(h, NULL, pkt, add_response) ==
2570 ENGINE_SUCCESS, "Get Replica Failed");
2571 check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2572 "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
2577 static enum test_result test_get_replica_pending_state(ENGINE_HANDLE *h,
2578 ENGINE_HANDLE_V1 *h1) {
2579 protocol_binary_request_header *pkt;
2581 const void *cookie = testHarness.create_cookie();
2582 testHarness.set_ewouldblock_handling(cookie, false);
2583 pkt = prepare_get_replica(h, h1, vbucket_state_pending);
2584 check(h1->unknown_command(h, cookie, pkt, add_response) ==
2585 ENGINE_EWOULDBLOCK, "Should have returned error for pending state");
2586 testHarness.destroy_cookie(cookie);
2590 static enum test_result test_get_replica_dead_state(ENGINE_HANDLE *h,
2591 ENGINE_HANDLE_V1 *h1) {
2592 protocol_binary_request_header *pkt;
2593 pkt = prepare_get_replica(h, h1, vbucket_state_dead);
2594 check(h1->unknown_command(h, NULL, pkt, add_response) ==
2595 ENGINE_SUCCESS, "Get Replica Failed");
2596 check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2597 "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
2602 static enum test_result test_get_replica(ENGINE_HANDLE *h,
2603 ENGINE_HANDLE_V1 *h1) {
2604 protocol_binary_request_header *pkt;
2605 pkt = prepare_get_replica(h, h1, vbucket_state_replica);
2606 check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
2607 "Get Replica Failed");
2608 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
2609 "Expected PROTOCOL_BINARY_RESPONSE_SUCCESS response.");
2610 check(last_body == "replicadata",
2611 "Should have returned identical value");
2616 static enum test_result test_get_replica_non_resident(ENGINE_HANDLE *h,
2617 ENGINE_HANDLE_V1 *h1) {
2620 check(store(h, h1, NULL, OPERATION_SET, "key", "value", &i, 0, 0)
2621 == ENGINE_SUCCESS, "Store Failed");
2622 h1->release(h, NULL, i);
2623 wait_for_flusher_to_settle(h, h1);
2624 wait_for_stat_to_be(h, h1, "ep_total_persisted", 1);
2626 evict_key(h, h1, "key", 0, "Ejected.");
2627 check(set_vbucket_state(h, h1, 0, vbucket_state_replica),
2628 "Failed to set vbucket to replica");
2630 get_replica(h, h1, "key", 0);
2631 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "Expected success");
2636 static enum test_result test_get_replica_invalid_key(ENGINE_HANDLE *h,
2637 ENGINE_HANDLE_V1 *h1) {
2638 protocol_binary_request_header *pkt;
2639 bool makeinvalidkey = true;
2640 pkt = prepare_get_replica(h, h1, vbucket_state_replica, makeinvalidkey);
2641 check(h1->unknown_command(h, NULL, pkt, add_response) ==
2642 ENGINE_SUCCESS, "Get Replica Failed");
2643 check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2644 "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
2648 static enum test_result test_vb_del_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2649 const void *cookie = testHarness.create_cookie();
2650 testHarness.set_ewouldblock_handling(cookie, false);
2651 check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
2652 check(ENGINE_EWOULDBLOCK == del(h, h1, "key", 0, 1, cookie),
2653 "Expected woodblock.");
2654 testHarness.destroy_cookie(cookie);
2658 static enum test_result test_vb_del_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2659 check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
2660 int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2661 check(ENGINE_NOT_MY_VBUCKET == del(h, h1, "key", 0, 1),
2662 "Expected not my vbucket.");
2663 wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2667 static enum test_result test_touch(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2668 // key is a mandatory field!
2669 touch(h, h1, NULL, 0, (time(NULL) + 10));
2670 check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2672 // extlen is a mandatory field!
2673 protocol_binary_request_header *request;
2674 request = createPacket(PROTOCOL_BINARY_CMD_TOUCH, 0, 0, NULL, 0, "akey", 4);
2675 check(h1->unknown_command(h, NULL, request, add_response) == ENGINE_SUCCESS,
2676 "Failed to call touch");
2677 check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2680 // Try to touch an unknown item...
2681 touch(h, h1, "mykey", 0, (time(NULL) + 10));
2682 check(last_status == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, "Testing unknown key");
2685 touch(h, h1, "mykey", 5, (time(NULL) + 10));
2686 check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, "Testing illegal vbucket");
2690 check(store(h, h1, NULL, OPERATION_SET, "mykey", "somevalue", &itm) == ENGINE_SUCCESS,
2692 h1->release(h, NULL, itm);
2694 check_key_value(h, h1, "mykey", "somevalue", strlen("somevalue"));
2696 touch(h, h1, "mykey", 0, (time(NULL) + 10));
2697 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch mykey");
2699 // time-travel 9 secs..
2700 testHarness.time_travel(9);
2702 // The item should still exist
2703 check_key_value(h, h1, "mykey", "somevalue", 9);
2705 // time-travel 2 secs..
2706 testHarness.time_travel(2);
2708 // The item should have expired now...
2709 check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2713 static enum test_result test_touch_mb7342(ENGINE_HANDLE *h,
2714 ENGINE_HANDLE_V1 *h1) {
2715 const char *key = "MB-7342";
2718 check(store(h, h1, NULL, OPERATION_SET, key, "v", &itm) == ENGINE_SUCCESS,
2720 h1->release(h, NULL, itm);
2722 touch(h, h1, key, 0, 0);
2723 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch key");
2725 check_key_value(h, h1, key, "v", 1);
2727 // Travel a loong time to see if the object is still there (the default
2728 // store sets an exp time of 3600
2729 testHarness.time_travel(3700);
2731 check_key_value(h, h1, key, "v", 1);
2736 static enum test_result test_touch_mb10277(ENGINE_HANDLE *h,
2737 ENGINE_HANDLE_V1 *h1) {
2738 const char *key = "MB-10277";
2741 check(store(h, h1, NULL, OPERATION_SET, key, "v", &itm) == ENGINE_SUCCESS,
2743 h1->release(h, NULL, itm);
2744 wait_for_flusher_to_settle(h, h1);
2745 evict_key(h, h1, key, 0, "Ejected.");
2747 touch(h, h1, key, 0, 3600); // A new expiration time remains in the same.
2748 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch key");
2753 static enum test_result test_gat(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2754 // key is a mandatory field!
2755 gat(h, h1, NULL, 0, 10);
2756 check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2758 // extlen is a mandatory field!
2759 protocol_binary_request_header *request;
2760 request = createPacket(PROTOCOL_BINARY_CMD_GAT, 0, 0, NULL, 0, "akey", 4);
2761 check(h1->unknown_command(h, NULL, request, add_response) == ENGINE_SUCCESS,
2762 "Failed to call gat");
2763 check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2766 // Try to gat an unknown item...
2767 gat(h, h1, "mykey", 0, 10);
2768 check(last_status == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, "Testing unknown key");
2771 gat(h, h1, "mykey", 5, 10);
2772 check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, "Testing illegal vbucket");
2776 check(store(h, h1, NULL, OPERATION_SET, "mykey", "{\"some\":\"value\"}",
2777 &itm, 0, 0, 3600, PROTOCOL_BINARY_DATATYPE_JSON) == ENGINE_SUCCESS,
2779 h1->release(h, NULL, itm);
2781 check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2782 strlen("{\"some\":\"value\"}"));
2784 gat(h, h1, "mykey", 0, 10);
2785 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "gat mykey");
2786 check(last_datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Expected datatype to be JSON");
2787 check(last_body.compare(0, sizeof("{\"some\":\"value\"}"),
2788 "{\"some\":\"value\"}") == 0,
2789 "Invalid data returned");
2791 // time-travel 9 secs..
2792 testHarness.time_travel(9);
2794 // The item should still exist
2795 check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2796 strlen("{\"some\":\"value\"}"));
2798 // time-travel 2 secs..
2799 testHarness.time_travel(2);
2801 // The item should have expired now...
2802 check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2806 static enum test_result test_gatq(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2807 // key is a mandatory field!
2808 gat(h, h1, NULL, 0, 10, true);
2809 check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2811 // extlen is a mandatory field!
2812 protocol_binary_request_header *request;
2813 request = createPacket(PROTOCOL_BINARY_CMD_GATQ, 0, 0, NULL, 0, "akey", 4);
2814 check(h1->unknown_command(h, NULL, request, add_response) == ENGINE_SUCCESS,
2815 "Failed to call gatq");
2816 check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2819 // Try to gatq an unknown item...
2820 last_status = static_cast<protocol_binary_response_status>(0xffff);
2821 gat(h, h1, "mykey", 0, 10, true);
2823 // We should not have sent any response!
2824 check(last_status == (protocol_binary_response_status)0xffff, "Testing unknown key");
2827 gat(h, h1, "mykey", 5, 10, true);
2828 check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2829 "Testing illegal vbucket");
2833 check(store(h, h1, NULL, OPERATION_SET, "mykey", "{\"some\":\"value\"}",
2834 &itm, 0, 0, 3600, PROTOCOL_BINARY_DATATYPE_JSON) == ENGINE_SUCCESS,
2836 h1->release(h, NULL, itm);
2838 check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2839 strlen("{\"some\":\"value\"}"));
2841 gat(h, h1, "mykey", 0, 10, true);
2842 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "gat mykey");
2843 check(last_datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Expected datatype to be JSON");
2844 check(last_body.compare(0, sizeof("{\"some\":\"value\"}"),
2845 "{\"some\":\"value\"}") == 0,
2846 "Invalid data returned");
2848 // time-travel 9 secs..
2849 testHarness.time_travel(9);
2851 // The item should still exist
2852 check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2853 strlen("{\"some\":\"value\"}"));
2855 // time-travel 2 secs..
2856 testHarness.time_travel(2);
2858 // The item should have expired now...
2859 check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2863 static enum test_result test_mb5215(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2865 check(store(h, h1, NULL, OPERATION_SET, "coolkey", "cooler", &itm)
2866 == ENGINE_SUCCESS, "Failed set.");
2867 h1->release(h, NULL, itm);
2869 check_key_value(h, h1, "coolkey", "cooler", strlen("cooler"));
2871 // set new exptime to 111
2872 int expTime = time(NULL) + 111;
2874 touch(h, h1, "coolkey", 0, expTime);
2875 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch coolkey");
2878 testHarness.reload_engine(&h, &h1,
2879 testHarness.engine_path,
2880 testHarness.get_current_testcase()->cfg,
2883 wait_for_warmup_complete(h, h1);
2885 //verify persisted expiration time
2886 const char *statkey = "key coolkey 0";
2888 check(h1->get(h, NULL, &itm, "coolkey", 7, 0) == ENGINE_SUCCESS,
2890 h1->release(h, NULL, itm);
2891 newExpTime = get_int_stat(h, h1, "key_exptime", statkey);
2892 check(newExpTime == expTime, "Failed to persist new exptime");
2894 // evict key, touch expiration time, and verify
2895 evict_key(h, h1, "coolkey", 0, "Ejected.");
2897 expTime = time(NULL) + 222;
2898 touch(h, h1, "coolkey", 0, expTime);
2899 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch coolkey");
2901 testHarness.reload_engine(&h, &h1,
2902 testHarness.engine_path,
2903 testHarness.get_current_testcase()->cfg,
2905 wait_for_warmup_complete(h, h1);
2907 check(h1->get(h, NULL, &itm, "coolkey", 7, 0) == ENGINE_SUCCESS,
2909 h1->release(h, NULL, itm);
2910 newExpTime = get_int_stat(h, h1, "key_exptime", statkey);
2911 check(newExpTime == expTime, "Failed to persist new exptime");
2916 static enum test_result test_alloc_limit(ENGINE_HANDLE *h,
2917 ENGINE_HANDLE_V1 *h1) {
2919 ENGINE_ERROR_CODE rv;
2921 rv = h1->allocate(h, NULL, &it, "key", 3, 20 * 1024 * 1024, 0, 0,
2922 PROTOCOL_BINARY_RAW_BYTES);
2923 check(rv == ENGINE_SUCCESS, "Allocated 20MB item");
2924 h1->release(h, NULL, it);
2926 rv = h1->allocate(h, NULL, &it, "key", 3, (20 * 1024 * 1024) + 1, 0, 0,
2927 PROTOCOL_BINARY_RAW_BYTES);
2928 check(rv == ENGINE_E2BIG, "Object too big");
2933 static enum test_result test_whitespace_db(ENGINE_HANDLE *h,
2934 ENGINE_HANDLE_V1 *h1) {
2936 check(h1->get_stats(h, NULL, NULL, 0, add_stats) == ENGINE_SUCCESS,
2937 "Failed to get stats.");
2938 if (vals["ep_dbname"] != std::string(WHITESPACE_DB)) {
2939 std::cerr << "Expected dbname = ``" << WHITESPACE_DB << "''"
2940 << ", got ``" << vals["ep_dbname"] << "''" << std::endl;
2944 check(access(WHITESPACE_DB, F_OK) != -1, "I expected the whitespace db to exist");
2948 static enum test_result test_memory_tracking(ENGINE_HANDLE *h,
2949 ENGINE_HANDLE_V1 *h1) {
2950 // Need memory tracker to be able to check our memory usage.
2951 std::string tracker = get_str_stat(h, h1, "ep_mem_tracker_enabled");
2952 if (tracker == "true") {
2955 std::cerr << "Memory tracker not enabled" << std::endl;
2960 static enum test_result test_memory_limit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2961 set_param(h, h1, protocol_binary_engine_param_flush, "mutation_mem_threshold", "95");
2962 wait_for_stat_change(h, h1,"ep_db_data_size", 0);
2963 int used = get_int_stat(h, h1, "mem_used");
2964 double mem_threshold =
2965 static_cast<double>(get_int_stat(h, h1, "ep_mutation_mem_threshold")) / 100;
2966 int max = static_cast<int>(get_int_stat(h, h1, "ep_max_size") * mem_threshold);
2967 check(get_int_stat(h, h1, "ep_oom_errors") == 0 &&
2968 get_int_stat(h, h1, "ep_tmp_oom_errors") == 0, "Expected no OOM errors.");
2969 cb_assert(used < max);
2971 char *data = new char[2 * 1024 * 1024];
2973 memset(data, 'x', 2 * 1024 * 1024);
2975 // Calculate the length of document to set - we want to ensure we can only
2976 // store one document before TEMP_OOM is hit.
2977 size_t vlen = (max - used) * 0.95;
2981 // So if we add an item,
2982 check(store(h, h1, NULL, OPERATION_SET, "key", data, &i) == ENGINE_SUCCESS,
2984 check_key_value(h, h1, "key", data, vlen);
2985 h1->release(h, NULL, i);
2988 // There should be no room for another.
2989 ENGINE_ERROR_CODE second = store(h, h1, NULL, OPERATION_SET, "key2", data, &i);
2990 check(second == ENGINE_ENOMEM || second == ENGINE_TMPFAIL,
2991 "should have failed second set");
2993 h1->release(h, NULL, i);
2996 check(get_int_stat(h, h1, "ep_oom_errors") == 1 ||
2997 get_int_stat(h, h1, "ep_tmp_oom_errors") == 1, "Expected an OOM error.");
2999 ENGINE_ERROR_CODE overwrite = store(h, h1, NULL, OPERATION_SET, "key", data, &i);
3000 check(overwrite == ENGINE_ENOMEM || overwrite == ENGINE_TMPFAIL,
3001 "should have failed second override");
3003 h1->release(h, NULL, i);
3006 check(get_int_stat(h, h1, "ep_oom_errors") == 2 ||
3007 get_int_stat(h, h1, "ep_tmp_oom_errors") == 2, "Expected another OOM error.");
3008 check_key_value(h, h1, "key", data, vlen);
3009 check(ENGINE_SUCCESS != verify_key(h, h1, "key2"), "Expected a failure in GET");
3010 int itemsRemoved = get_int_stat(h, h1, "ep_items_rm_from_checkpoints");
3011 // Until we remove that item
3012 check(del(h, h1, "key", 0, 0) == ENGINE_SUCCESS, "Failed remove with value.");
3013 check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
3014 testHarness.time_travel(65);
3015 wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
3017 check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue2", &i) == ENGINE_SUCCESS,
3018 "should have succeded on the last set");
3019 check_key_value(h, h1, "key2", "somevalue2", 10);
3020 h1->release(h, NULL, i);
3025 static enum test_result test_vbucket_get_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3026 return verify_vbucket_missing(h, h1, 1) ? SUCCESS : FAIL;
3029 static enum test_result test_vbucket_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3030 return verify_vbucket_state(h, h1, 0, vbucket_state_active) ? SUCCESS : FAIL;
3033 static enum test_result test_vbucket_create(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3034 if (!verify_vbucket_missing(h, h1, 1)) {
3035 fprintf(stderr, "vbucket wasn't missing.\n");
3039 if (!set_vbucket_state(h, h1, 1, vbucket_state_active)) {
3040 fprintf(stderr, "set state failed.\n");
3044 return verify_vbucket_state(h, h1, 1, vbucket_state_active) ? SUCCESS : FAIL;
3047 static enum test_result test_vbucket_compact(ENGINE_HANDLE *h,
3048 ENGINE_HANDLE_V1 *h1) {
3049 const char *key = "Carss";
3050 const char *value = "pollute";
3051 if (!verify_vbucket_missing(h, h1, 0)) {
3052 fprintf(stderr, "vbucket wasn't missing.\n");
3056 if (!set_vbucket_state(h, h1, 0, vbucket_state_active)) {
3057 fprintf(stderr, "set state failed.\n");
3061 check(verify_vbucket_state(h, h1, 0, vbucket_state_active),
3062 "VBucket state not active");
3064 // Set two keys - one to be expired and other to remain...
3066 check(store(h, h1, NULL, OPERATION_SET, key, value, &itm)
3067 == ENGINE_SUCCESS, "Failed set.");
3068 h1->release(h, NULL, itm);
3070 check_key_value(h, h1, key, value, strlen(value));
3072 // Set a non-expiring key...
3073 check(store(h, h1, NULL, OPERATION_SET, "trees", "cleanse", &itm)
3074 == ENGINE_SUCCESS, "Failed set.");
3075 h1->release(h, NULL, itm);
3077 check_key_value(h, h1, "trees", "cleanse", strlen("cleanse"));
3079 touch(h, h1, key, 0, 11);
3080 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch Carss");
3082 testHarness.time_travel(12);
3083 wait_for_flusher_to_settle(h, h1);
3085 // Store a dummy item since we do not purge the item with highest seqno
3086 check(ENGINE_SUCCESS ==
3087 store(h, h1, NULL, OPERATION_SET, "dummykey", "dummyvalue", &itm,
3088 0, 0, 0), "Error setting.");
3090 wait_for_flusher_to_settle(h, h1);
3092 check(get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno") == 0,
3093 "purge_seqno not found to be zero before compaction");
3095 // Compaction on VBucket
3096 compact_db(h, h1, 0, 2, 3, 1);
3098 check(get_int_stat(h, h1, "ep_pending_compactions") == 0,
3099 "ep_pending_compactions stat did not tick down after compaction command");
3101 // the key tree and its value should be intact...
3102 check(verify_key(h, h1, "trees") == ENGINE_SUCCESS,
3103 "key trees should be found.");
3104 // the key Carrs should have disappeared...
3105 int val = verify_key(h, h1, "Carss");
3106 check(val == ENGINE_KEY_ENOENT, "Key Carss has not expired.");
3108 check(get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno") == 4,
3109 "purge_seqno didn't match expected value");
3114 /* This test case checks the purge seqno validity when no items are actually
3115 purged in a compaction call */
3116 static enum test_result test_vbucket_compact_no_purge(ENGINE_HANDLE *h,
3117 ENGINE_HANDLE_V1 *h1) {
3118 const int num_items = 2;
3119 const char* key[num_items] = {"k1", "k2"};
3120 const char* value = "somevalue";
3123 for (int count = 0; count < num_items; count++){
3124 checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, key[count],
3125 value, NULL, 0, 0, 0),
3129 /* Delete one key */
3130 checkeq(ENGINE_SUCCESS, del(h, h1, key[0], 0, 0),
3131 "Failed remove with value.");
3133 /* Store a dummy item since we do not purge the item with highest seqno */
3134 checkeq(ENGINE_SUCCESS,
3135 store(h, h1, NULL, OPERATION_SET, "dummy_key", value, NULL,
3138 wait_for_flusher_to_settle(h, h1);
3141 int exp_purge_seqno = get_int_stat(h, h1, "vb_0:high_seqno",
3142 "vbucket-seqno") - 1;
3143 compact_db(h, h1, 0, 2,
3144 get_int_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno"), 1);
3145 wait_for_stat_to_be(h, h1, "ep_pending_compactions", 0);
3146 checkeq(exp_purge_seqno,
3147 get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno"),
3148 "purge_seqno didn't match expected value");
3150 /* Compact again, this time we don't expect to purge any items */
3151 compact_db(h, h1, 0, 2,
3152 get_int_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno"), 1);
3153 wait_for_stat_to_be(h, h1, "ep_pending_compactions", 0);
3154 checkeq(exp_purge_seqno,
3155 get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno"),
3156 "purge_seqno didn't match expected value after another compaction");
3158 /* Reload the engine */
3159 testHarness.reload_engine(&h, &h1,
3160 testHarness.engine_path,
3161 testHarness.get_current_testcase()->cfg,
3163 wait_for_warmup_complete(h, h1);
3165 /* Purge seqno should not change after reload */
3166 checkeq(exp_purge_seqno,
3167 get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno"),
3168 "purge_seqno didn't match expected value after reload");
3173 static enum test_result test_compaction_config(ENGINE_HANDLE *h,
3174 ENGINE_HANDLE_V1 *h1) {
3176 check(get_int_stat(h, h1, "ep_compaction_write_queue_cap") == 10000,
3177 "Expected compaction queue cap to be 10000");
3178 set_param(h, h1, protocol_binary_engine_param_flush,
3179 "compaction_write_queue_cap", "100000");
3180 check(get_int_stat(h, h1, "ep_compaction_write_queue_cap") == 100000,
3181 "Expected compaction queue cap to be 100000");
3185 struct comp_thread_ctx {
3187 ENGINE_HANDLE_V1 *h1;
3192 static void compaction_thread(void *arg) {
3193 struct comp_thread_ctx *ctx = static_cast<comp_thread_ctx *>(arg);
3194 compact_db(ctx->h, ctx->h1, ctx->vbid, 0, 0, 0);
3198 static enum test_result test_multiple_vb_compactions(ENGINE_HANDLE *h,
3199 ENGINE_HANDLE_V1 *h1) {
3200 for (uint16_t i = 0; i < 4; ++i) {
3201 if (!set_vbucket_state(h, h1, i, vbucket_state_active)) {
3202 fprintf(stderr, "set state failed for vbucket %d.\n", i);
3205 check(verify_vbucket_state(h, h1, i, vbucket_state_active),
3206 "VBucket state not active");
3209 std::vector<std::string> keys;
3210 for (int j = 0; j < 20000; ++j) {
3211 std::stringstream ss;
3213 std::string key(ss.str());
3214 keys.push_back(key);
3218 std::vector<std::string>::iterator it;
3219 for (it = keys.begin(); it != keys.end(); ++it) {
3220 uint16_t vbid = count % 4;
3222 check(store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(), &i, 0, vbid)
3223 == ENGINE_SUCCESS, "Failed to store a value");
3224 h1->release(h, NULL, i);
3228 // Compact multiple vbuckets.
3229 const int n_threads = 4;
3230 cb_thread_t threads[n_threads];
3231 struct comp_thread_ctx ctx[n_threads];
3233 for (int i = 0; i < n_threads; i++) {
3236 ctx[i].vbid = static_cast<uint16_t>(i);
3237 int r = cb_create_thread(&threads[i], compaction_thread, &ctx[i], 0);
3241 for (int i = 0; i < n_threads; i++) {
3242 int r = cb_join_thread(threads[i]);
3246 check(get_int_stat(h, h1, "ep_pending_compactions") == 0,
3247 "ep_pending_compactions stat did not tick down after compaction command");
3252 static enum test_result
3253 test_multi_vb_compactions_with_workload(ENGINE_HANDLE *h,
3254 ENGINE_HANDLE_V1 *h1) {
3255 for (uint16_t i = 0; i < 4; ++i) {
3256 if (!set_vbucket_state(h, h1, i, vbucket_state_active)) {
3257 fprintf(stderr, "set state failed for vbucket %d.\n", i);
3260 check(verify_vbucket_state(h, h1, i, vbucket_state_active),
3261 "VBucket state not active");
3264 std::vector<std::string> keys;
3265 for (int j = 0; j < 10000; ++j) {
3266 std::stringstream ss;
3268 std::string key(ss.str());
3269 keys.push_back(key);
3273 std::vector<std::string>::iterator it;
3274 for (it = keys.begin(); it != keys.end(); ++it) {
3275 uint16_t vbid = count % 4;
3277 check(store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(), &i, 0, vbid)
3278 == ENGINE_SUCCESS, "Failed to store a value");
3279 h1->release(h, NULL, i);
3282 wait_for_flusher_to_settle(h, h1);
3284 for (int i = 0; i < 2; ++i) {
3286 for (it = keys.begin(); it != keys.end(); ++it) {
3287 uint16_t vbid = count % 4;
3289 check(h1->get(h, NULL, &i, it->c_str(), strlen(it->c_str()), vbid) ==
3290 ENGINE_SUCCESS, "Unable to get stored item");
3291 h1->release(h, NULL, i);
3295 wait_for_str_stat_to_be(h, h1, "ep_workload_pattern", "read_heavy", NULL);
3297 // Compact multiple vbuckets.
3298 const int n_threads = 4;
3299 cb_thread_t threads[n_threads];
3300 struct comp_thread_ctx ctx[n_threads];
3302 for (int i = 0; i < n_threads; i++) {
3305 ctx[i].vbid = static_cast<uint16_t>(i);
3306 int r = cb_create_thread(&threads[i], compaction_thread, &ctx[i], 0);
3310 for (int i = 0; i < n_threads; i++) {
3311 int r = cb_join_thread(threads[i]);
3315 check(get_int_stat(h, h1, "ep_pending_compactions") == 0,
3316 "ep_pending_compactions stat did not tick down after compaction command");
3321 static enum test_result vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
3322 const char* value = NULL) {
3323 check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed to set vbucket state.");
3325 vbucketDelete(h, h1, 2, value);
3326 check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
3327 "Expected failure deleting non-existent bucket.");
3329 check(set_vbucket_state(h, h1, 1, vbucket_state_dead), "Failed set set vbucket 1 state.");
3331 vbucketDelete(h, h1, 1, value);
3332 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
3333 "Expected failure deleting non-existent bucket.");
3335 check(verify_vbucket_missing(h, h1, 1),
3336 "vbucket 0 was not missing after deleting it.");
3341 static enum test_result test_vbucket_destroy_stats(ENGINE_HANDLE *h,
3342 ENGINE_HANDLE_V1 *h1) {
3344 int cacheSize = get_int_stat(h, h1, "ep_total_cache_size");
3345 int overhead = get_int_stat(h, h1, "ep_overhead");
3346 int nonResident = get_int_stat(h, h1, "ep_num_non_resident");
3348 check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed to set vbucket state.");
3350 std::vector<std::string> keys;
3351 for (int j = 0; j < 2000; ++j) {
3352 std::stringstream ss;
3354 std::string key(ss.str());
3355 keys.push_back(key);
3358 int itemsRemoved = get_int_stat(h, h1, "ep_items_rm_from_checkpoints");
3359 std::vector<std::string>::iterator it;
3360 for (it = keys.begin(); it != keys.end(); ++it) {
3362 check(store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(), &i, 0, 1)
3363 == ENGINE_SUCCESS, "Failed to store a value");
3364 h1->release(h, NULL, i);
3366 wait_for_flusher_to_settle(h, h1);
3367 testHarness.time_travel(65);
3368 wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
3370 check(set_vbucket_state(h, h1, 1, vbucket_state_dead), "Failed set set vbucket 1 state.");
3372 int vbucketDel = get_int_stat(h, h1, "ep_vbucket_del");
3373 vbucketDelete(h, h1, 1);
3374 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
3375 "Expected failure deleting non-existent bucket.");
3377 check(verify_vbucket_missing(h, h1, 1),
3378 "vbucket 1 was not missing after deleting it.");
3380 wait_for_stat_change(h, h1, "ep_vbucket_del", vbucketDel);
3382 wait_for_stat_to_be(h, h1, "ep_total_cache_size", cacheSize);
3383 wait_for_stat_to_be(h, h1, "ep_overhead", overhead);
3384 wait_for_stat_to_be(h, h1, "ep_num_non_resident", nonResident);
3389 static enum test_result vbucket_destroy_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
3390 const char* value = NULL) {
3391 check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed to set vbucket state.");
3393 // Store a value so the restart will try to resurrect it.
3395 check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i, 0, 1)
3396 == ENGINE_SUCCESS, "Failed to set a value");
3397 check_key_value(h, h1, "key", "somevalue", 9, 1);
3398 h1->release(h, NULL, i);
3400 // Reload to get a flush forced.
3401 testHarness.reload_engine(&h, &h1,
3402 testHarness.engine_path,
3403 testHarness.get_current_testcase()->cfg,
3405 wait_for_warmup_complete(h, h1);
3407 check(verify_vbucket_state(h, h1, 1, vbucket_state_active),
3408 "Bucket state was what it was initially, after restart.");
3409 check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed to set vbucket state.");
3410 check_key_value(h, h1, "key", "somevalue", 9, 1);
3412 check(set_vbucket_state(h, h1, 1, vbucket_state_dead), "Failed set set vbucket 1 state.");
3414 vbucketDelete(h, h1, 1, value);
3415 check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
3416 "Expected failure deleting non-existent bucket.");
3418 check(verify_vbucket_missing(h, h1, 1),
3419 "vbucket 1 was not missing after deleting it.");
3421 testHarness.reload_engine(&h, &h1,
3422 testHarness.engine_path,
3423 testHarness.get_current_testcase()->cfg,
3425 wait_for_warmup_complete(h, h1);
3427 if (verify_vbucket_state(h, h1, 1, vbucket_state_pending, true)) {
3428 std::cerr << "Bucket came up in pending state after delete." << std::endl;
3432 check(verify_vbucket_missing(h, h1, 1),
3433 "vbucket 1 was not missing after restart.");
3438 static enum test_result test_async_vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3439 return vbucket_destroy(h, h1);
3442 static enum test_result test_sync_vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3443 return vbucket_destroy(h, h1, "async=0");
3446 static enum test_result test_async_vbucket_destroy_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3447 return vbucket_destroy_restart(h, h1);
3450 static enum test_result test_sync_vbucket_destroy_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3451 return vbucket_destroy_restart(h, h1, "async=0");
3454 static enum test_result test_vb_set_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3455 return test_pending_vb_mutation(h, h1, OPERATION_SET);
3458 static enum test_result test_vb_add_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3459 return test_pending_vb_mutation(h, h1, OPERATION_ADD);
3462 static enum test_result test_vb_cas_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3463 return test_pending_vb_mutation(h, h1, OPERATION_CAS);
3466 static enum test_result test_vb_append_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3467 return test_pending_vb_mutation(h, h1, OPERATION_APPEND);
3470 static enum test_result test_vb_prepend_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3471 return test_pending_vb_mutation(h, h1, OPERATION_PREPEND);
3474 static enum test_result test_vb_set_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3475 return test_replica_vb_mutation(h, h1, OPERATION_SET);
3478 static enum test_result test_vb_replace_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3479 return test_replica_vb_mutation(h, h1, OPERATION_REPLACE);
3482 static enum test_result test_vb_replace_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3483 return test_pending_vb_mutation(h, h1, OPERATION_REPLACE);
3486 static enum test_result test_vb_add_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3487 return test_replica_vb_mutation(h, h1, OPERATION_ADD);
3490 static enum test_result test_vb_cas_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3491 return test_replica_vb_mutation(h, h1, OPERATION_CAS);
3494 static enum test_result test_vb_append_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3495 return test_replica_vb_mutation(h, h1, OPERATION_APPEND);
3498 static enum test_result test_vb_prepend_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {