MB-20182: Update checkpoint snapshot correctly during TAP backfill
[ep-engine.git] / tests / ep_testsuite.cc
1 /* -*- MODE: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2010 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17
18 // Usage: (to repeatedly run just a single test case)
19 // make engine_tests IS_LOOP=-L EP_TEST_NUM=3
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <sys/stat.h>
28 #ifdef _MSC_VER
29 #include <direct.h>
30 #define mkdir(a, b) _mkdir(a)
31 #else
32 #include <sys/wait.h>
33 #endif
34
35 #include <cstdlib>
36 #include <iostream>
37 #include <iomanip>
38 #include <map>
39 #include <set>
40 #include <sstream>
41 #include <string>
42 #include <vector>
43
44 #include <platform/dirutils.h>
45
46 #include "atomic.h"
47 #include "ep-engine/command_ids.h"
48 #include "ep_test_apis.h"
49 #include "ep_testsuite.h"
50 #include "locks.h"
51 #include <libcouchstore/couch_db.h>
52 #include "mock/mock_dcp.h"
53 #include "mutex.h"
54
55 #include <snappy-c.h>
56 #include <JSON_checker.h>
57
58 #ifdef linux
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 ..
63  */
64 #undef ntohs
65 #undef ntohl
66 #undef htons
67 #undef htonl
68 #endif
69
70 #undef THREAD_SANITIZER
71 #if __clang__
72 #   if defined(__has_feature) && __has_feature(thread_sanitizer)
73 #define THREAD_SANITIZER
74 #   endif
75 #endif
76
77 // ptr_fun don't like the extern "C" thing for unlock cookie.. cast it
78 // away ;)
79 typedef void (*UNLOCK_COOKIE_T)(const void *cookie);
80
81 template <typename T>
82 static void checknefn(T exp, T got, const char *msg, const char *file, const int linenum) {
83     if (exp == got) {
84         std::stringstream ss;
85         ss << "Expected `" << exp << "' to not equal `" << got << "' - " << msg;
86         abort_msg(ss.str().c_str(), file, linenum);
87     }
88 }
89
90 #define checkne(a, b, c) checknefn(a, b, c, __FILE__, __LINE__)
91
92 extern "C" {
93 #define check(expr, msg) \
94     static_cast<void>((expr) ? 0 : abort_msg(#expr, msg, __LINE__))
95
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"
99
100 struct test_harness testHarness;
101
102 class ThreadData {
103 public:
104     ThreadData(ENGINE_HANDLE *eh, ENGINE_HANDLE_V1 *ehv1,
105                int e=0) : h(eh), h1(ehv1), extra(e) {}
106     ENGINE_HANDLE    *h;
107     ENGINE_HANDLE_V1 *h1;
108     int               extra;
109 };
110
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);
114     abort();
115     // UNREACHABLE
116     return false;
117 }
118
119 static const char *dbname_env;
120 static enum test_result rmdb(void)
121 {
122     const char *files[] = { WHITESPACE_DB,
123                             "/tmp/test",
124                             "/tmp/mutation.log",
125                             dbname_env,
126                             NULL };
127     int ii = 0;
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;
132             return FAIL;
133         }
134         ++ii;
135     }
136
137     return SUCCESS;
138 }
139
140 static enum test_result skipped_test_function(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
141     (void) h;
142     (void) h1;
143     return SKIPPED;
144 }
145
146 static bool teardown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
147     (void)h; (void)h1;
148     vals.clear();
149     return true;
150 }
151
152 static const void* createTapConn(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
153                                  const char *name) {
154     const void *cookie = testHarness.create_cookie();
155     testHarness.lock_cookie(cookie);
156     TAP_ITERATOR iter = h1->get_tap_iterator(h, cookie, name,
157                                              strlen(name),
158                                              TAP_CONNECT_FLAG_DUMP, NULL,
159                                              0);
160     check(iter != NULL, "Failed to create a tap iterator");
161     return cookie;
162 }
163
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) {
167     item_info info;
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");
172 }
173
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) {
177     item *i = NULL;
178     checkeq(ENGINE_SUCCESS,
179             h1->get(h, NULL, &i, key.c_str(), key.size(), /*vBucket*/0),
180             "Failed to get key");
181
182     item_info info;
183     info.nvalue = 1;
184     check(h1->get_item_info(h, NULL, i, &info),
185           "Failed to get item info for key");
186     h1->release(h, NULL, i);
187
188     return info.cas;
189 }
190
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;
196     uint16_t recv_vb_id;
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;
202
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");
214
215     if (failover) {
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");
220     }
221 }
222
223 static bool test_setup(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
224     wait_for_warmup_complete(h, h1);
225
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.");
231     }
232
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);
236
237     // warmup is complete, notify ep engine that it must now enable
238     // data traffic
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");
242     free(pkt);
243
244     return true;
245 }
246
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;
251
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");
257         abort();
258     }
259
260     item *i = NULL;
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);
265
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");
273
274     /* wait 16 seconds */
275     testHarness.time_travel(16);
276
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");
281
282     if (!last_body.empty() && last_body != "LOCK_ERROR") {
283         fprintf(stderr, "Should have returned LOCK_ERROR. Getl Failed");
284         abort();
285     }
286
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);
290
291     /* wait another 10 seconds */
292     testHarness.time_travel(10);
293
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);
298
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");
303
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");
310
311     /* try an incr operation followed by a delete, both of which should fail */
312     uint64_t cas = 0;
313     uint64_t result = 0;
314     i = NULL;
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);
319
320     check(del(h, h1, key, 0, 0) == ENGINE_TMPFAIL, "Delete failed");
321
322
323     /* bug MB 2699 append after getl should fail with ENGINE_TMPFAIL */
324
325     testHarness.time_travel(26);
326
327     char binaryData1[] = "abcdefg\0gfedcba";
328     char binaryData2[] = "abzdefg\0gfedcba";
329
330     check(storeCasVb11(h, h1, NULL, OPERATION_SET, key,
331                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
332           == ENGINE_SUCCESS,
333           "Failed set.");
334     h1->release(h, NULL, i);
335
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");
340
341     /* append should fail */
342     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, key,
343                        binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
344           == ENGINE_TMPFAIL,
345           "Append should fail.");
346     h1->release(h, NULL, i);
347
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
354      */
355     const char *ekey = "test_expiry";
356     const char *edata = "some test data here.";
357
358     item *it = NULL;
359
360     check(h1->allocate(h, NULL, &it, ekey, strlen(ekey), strlen(edata), 0, 2,
361           PROTOCOL_BINARY_RAW_BYTES) == ENGINE_SUCCESS, "Allocation Failed");
362
363     item_info info;
364     info.nvalue = 1;
365     if (!h1->get_item_info(h, NULL, it, &info)) {
366         abort();
367     }
368     memcpy(info.value[0].iov_base, edata, strlen(edata));
369
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);
374
375     testHarness.time_travel(3);
376     cas = last_cas;
377
378     /* cas should fail */
379     check(storeCasVb11(h, h1, NULL, OPERATION_CAS, ekey,
380                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, cas, 0)
381           != ENGINE_SUCCESS,
382           "CAS succeeded.");
383     h1->release(h, NULL, i);
384
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);
389     return SUCCESS;
390 }
391
392 static enum test_result test_unl(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
393
394     const char *key = "k2";
395     uint16_t vbucketId = 0;
396
397     unl(h, h1, key, vbucketId);
398     check(last_status != PROTOCOL_BINARY_RESPONSE_SUCCESS,
399           "expected the key to be missing...");
400
401     item *i = NULL;
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);
405
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");
410
411     /* save the returned cas value for later */
412     uint64_t cas = last_cas;
413
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");
418
419     if (!last_body.empty() && last_body != "UNLOCK_ERROR") {
420         fprintf(stderr, "Should have returned UNLOCK_ERROR. Unl Failed");
421         abort();
422     }
423
424     unl(h, h1, key, vbucketId, cas);
425     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
426           "Expected to succed unl with correct cas");
427
428     /* acquire lock, should succeed */
429     getl(h, h1, key, vbucketId, 0);
430
431     /* wait 16 seconds */
432     testHarness.time_travel(16);
433
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");
438
439     return SUCCESS;
440 }
441
442 static enum test_result test_wrong_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
443                                                ENGINE_STORE_OPERATION op) {
444     item *i = NULL;
445     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
446     uint64_t cas = 11;
447     if (op == OPERATION_ADD) {
448         // Add operation with cas != 0 doesn't make sense
449         cas = 0;
450     }
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);
456     return SUCCESS;
457 }
458
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);
463     item *i = NULL;
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.");
466     uint64_t cas = 11;
467     if (op == OPERATION_ADD) {
468         // Add operation with cas != 0 doesn't make sense..
469         cas = 0;
470     }
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);
476     return SUCCESS;
477 }
478
479 static enum test_result test_replica_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
480                                                  ENGINE_STORE_OPERATION op) {
481     item *i = NULL;
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");
485
486     uint64_t cas = 11;
487     if (op == OPERATION_ADD) {
488         // performing add with a CAS != 0 doesn't make sense...
489         cas = 0;
490     }
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);
496     return SUCCESS;
497 }
498
499 //
500 // ----------------------------------------------------------------------
501 // The actual tests are below.
502 // ----------------------------------------------------------------------
503 //
504
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.");
507     return SUCCESS;
508 }
509
510 static enum test_result test_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
511     item *i = NULL;
512     item_info info;
513     uint64_t vb_uuid = 0, high_seqno = 0;
514     const int num_sets = 5, num_keys = 4;
515
516     std::string key_arr[num_keys] = { "dummy_key",
517                                       "checkpoint_start",
518                                       "checkpoint_end",
519                                       "key" };
520
521
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",
527                                       "vbucket-seqno");
528
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(),
532                           "somevalue", &i),
533                     err_str_store.c_str());
534             h1->release(h, NULL, i);
535
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());
539
540             std::string err_str_vb_uuid("Expected valid vbucket uuid for " +
541                                         key_arr[k]);
542             checkeq(vb_uuid, info.vbucket_uuid, err_str_vb_uuid.c_str());
543
544             std::string err_str_seqno("Expected valid sequence number for " +
545                                         key_arr[k]);
546             checkeq(high_seqno + 1, info.seqno, err_str_seqno.c_str());
547         }
548     }
549
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 << ")";
555
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());
562
563     return SUCCESS;
564 }
565
566 struct handle_pair {
567     ENGINE_HANDLE *h;
568     ENGINE_HANDLE_V1 *h1;
569 };
570
571 extern "C" {
572     static void conc_del_set_thread(void *arg) {
573         struct handle_pair *hp = static_cast<handle_pair *>(arg);
574         item *it = NULL;
575
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);
580             usleep(10);
581             checkeq(ENGINE_SUCCESS,
582                     store(hp->h, hp->h1, NULL, OPERATION_SET,
583                           "key", "somevalue", &it),
584                     "Error setting.");
585             hp->h1->release(hp->h, NULL, it);
586             usleep(10);
587             // Ignoring the result here -- we're racing.
588             del(hp->h, hp->h1, "key", 0, 0);
589             usleep(10);
590         }
591     }
592
593     static void conc_incr_thread(void *arg) {
594         struct handle_pair *hp = static_cast<handle_pair *>(arg);
595         uint64_t result = 0;
596
597         for (int i = 0; i < 10; i++) {
598             item *it = NULL;
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);
604         }
605     }
606 }
607
608 static enum test_result test_conc_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
609
610     const int n_threads = 8;
611     cb_thread_t threads[n_threads];
612     struct handle_pair hp = {h, h1};
613
614     wait_for_persisted_value(h, h1, "key", "value1");
615
616     for (int i = 0; i < n_threads; i++) {
617         int r = cb_create_thread(&threads[i], conc_del_set_thread, &hp, 0);
618         cb_assert(r == 0);
619     }
620
621     for (int i = 0; i < n_threads; i++) {
622         int r = cb_join_thread(threads[i]);
623         cb_assert(r == 0);
624     }
625
626     wait_for_flusher_to_settle(h, h1);
627
628     testHarness.reload_engine(&h, &h1,
629                               testHarness.engine_path,
630                               testHarness.get_current_testcase()->cfg,
631                               true, false);
632     wait_for_warmup_complete(h, h1);
633
634     cb_assert(0 == get_int_stat(h, h1, "ep_warmed_dups"));
635
636     return SUCCESS;
637 }
638
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};
643     item *i = NULL;
644     check(store(h, h1, NULL, OPERATION_SET, "key", "0", &i) == ENGINE_SUCCESS,
645           "store failure");
646     h1->release(h, NULL, i);
647
648     for (int i = 0; i < n_threads; i++) {
649         int r = cb_create_thread(&threads[i], conc_incr_thread, &hp, 0);
650         cb_assert(r == 0);
651     }
652
653     for (int i = 0; i < n_threads; i++) {
654         int r = cb_join_thread(threads[i]);
655         cb_assert(r == 0);
656     }
657
658     check_key_value(h, h1, "key", "100", 3);
659
660     return SUCCESS;
661 }
662
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};
668
669     for (int i = 0; i < n_threads; i++) {
670         int r = cb_create_thread(&threads[i], conc_incr_thread, &hp, 0);
671         cb_assert(r == 0);
672     }
673
674     for (int i = 0; i < n_threads; i++) {
675         int r = cb_join_thread(threads[i]);
676         cb_assert(r == 0);
677     }
678
679     check_key_value(h, h1, "key", "100", 3);
680
681     return SUCCESS;
682 }
683
684 struct multi_set_args {
685     ENGINE_HANDLE *h;
686     ENGINE_HANDLE_V1 *h1;
687     std::string prefix;
688     int count;
689 };
690
691 extern "C" {
692     static void multi_set_thread(void *arg) {
693         struct multi_set_args *msa = static_cast<multi_set_args *>(arg);
694
695         for (int i = 0; i < msa->count; i++) {
696             item *it = NULL;
697             std::stringstream s;
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);
703         }
704     }
705 }
706
707 static enum test_result test_multi_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
708
709     cb_thread_t thread1, thread2;
710     struct multi_set_args msa1, msa2;
711     msa1.h = h;
712     msa1.h1 = h1;
713     msa1.prefix = "ONE_";
714     msa1.count = 50000;
715     cb_assert(cb_create_thread(&thread1, multi_set_thread, &msa1, 0) == 0);
716
717     msa2.h = h;
718     msa2.h1 = h1;
719     msa2.prefix = "TWO_";
720     msa2.count = 50000;
721     cb_assert(cb_create_thread(&thread2, multi_set_thread, &msa2, 0) == 0);
722
723     cb_assert(cb_join_thread(thread1) == 0);
724     cb_assert(cb_join_thread(thread2) == 0);
725
726     wait_for_flusher_to_settle(h, h1);
727
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");
732
733     return SUCCESS;
734 }
735
736 static enum test_result test_set_get_hit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
737     item *i = NULL;
738     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
739           "store failure");
740     check_key_value(h, h1, "key", "somevalue", 9);
741     h1->release(h, NULL, i);
742     return SUCCESS;
743 }
744
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));
748
749     item *i = NULL;
750     check(ENGINE_SUCCESS ==
751           storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
752                        binaryData, sizeof(binaryData), 82758, &i, 0, 0),
753           "Failed to set.");
754     h1->release(h, NULL, i);
755     check_key_value(h, h1, "key", binaryData, sizeof(binaryData));
756     return SUCCESS;
757 }
758
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";
762     item *i = NULL;
763
764     check(h1->allocate(h, NULL, &i, key, strlen(key), 10, 0, 0,
765           PROTOCOL_BINARY_RAW_BYTES) == ENGINE_SUCCESS, "Allocation failed.");
766
767     Item *it = reinterpret_cast<Item*>(i);
768     it->setCas(1234);
769
770     uint64_t cas = 0;
771     check(h1->store(h, NULL, i, &cas, OPERATION_SET, 0) == ENGINE_KEY_ENOENT,
772           "Expected not found");
773     h1->release(h, NULL, i);
774
775     return SUCCESS;
776 }
777
778 static enum test_result test_set_change_flags(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
779     item *i = NULL;
780     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
781           "Failed to set.");
782     h1->release(h, NULL, i);
783
784     item_info info;
785     uint32_t flags = 828258;
786     check(get_item_info(h, h1, &info, "key"), "Failed to get value.");
787     cb_assert(info.flags != flags);
788
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);
793
794     check(get_item_info(h, h1, &info, "key"), "Failed to get value.");
795
796     return info.flags == flags ? SUCCESS : FAIL;
797 }
798
799 static enum test_result test_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
800     item *i = NULL;
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);
808
809     check(h1->get(h, NULL, &i, "key", 3, 0) == ENGINE_SUCCESS,
810           "Failed to get value.");
811
812     item_info info;
813     info.nvalue = 1;
814     check(h1->get_item_info(h, NULL, i, &info), "Failed to get item info.");
815     h1->release(h, NULL, i);
816
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);
822
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);
828     return SUCCESS;
829 }
830
831 static enum test_result test_add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
832     item *i = NULL;
833     item_info info;
834     uint64_t vb_uuid = 0;
835     uint32_t high_seqno = 0;
836
837     memset(&info, 0, sizeof(info));
838
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");
841
842     check(store(h, h1, NULL, OPERATION_ADD,"key", "somevalue", &i) == ENGINE_SUCCESS,
843           "Failed to add value.");
844     h1->release(h, NULL, i);
845
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");
849
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);
853
854     // This aborts on failure.
855     check_key_value(h, h1, "key", "somevalue", 9);
856
857     // Expiration above was an hour, so let's go to The Future
858     testHarness.time_travel(3800);
859
860     check(store(h, h1, NULL, OPERATION_ADD,"key", "newvalue", &i) == ENGINE_SUCCESS,
861           "Failed to add value again.");
862
863     h1->release(h, NULL, i);
864     check_key_value(h, h1, "key", "newvalue", 8);
865     return SUCCESS;
866 }
867
868 static enum test_result test_add_add_with_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
869     item *i = NULL;
870     check(store(h, h1, NULL, OPERATION_ADD, "key",
871                 "somevalue", &i) == ENGINE_SUCCESS,
872           "Failed set.");
873     check_key_value(h, h1, "key", "somevalue", 9);
874     item_info info;
875     info.nvalue = 1;
876     info.nvalue = 1;
877     check(h1->get_item_info(h, NULL, i, &info) == true,
878           "Should be able to get info");
879
880     item *i2 = NULL;
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");
885
886     h1->release(h, NULL, i);
887     h1->release(h, NULL, i2);
888     return SUCCESS;
889 }
890
891 static enum test_result test_replace(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
892     item *i = NULL;
893     item_info info;
894     uint64_t vb_uuid = 0;
895     uint32_t high_seqno = 0;
896
897     memset(&info, 0, sizeof(info));
898
899     check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue", &i) != ENGINE_SUCCESS,
900           "Failed to fail to replace non-existing value.");
901
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);
906
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");
909
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);
913
914     check(get_item_info(h, h1, &info, "key"), "Error getting item info");
915
916     check(vb_uuid == info.vbucket_uuid, "Expected valid vbucket uuid");
917     check(high_seqno + 1 == info.seqno, "Expected valid sequence number");
918
919     check_key_value(h, h1, "key", "somevalue", 9);
920     return SUCCESS;
921 }
922
923 static enum test_result test_replace_with_eviction(ENGINE_HANDLE *h,
924                                                    ENGINE_HANDLE_V1 *h1) {
925     item *i = NULL;
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");
932
933     check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue1", &i) == ENGINE_SUCCESS,
934           "Failed to replace existing value.");
935
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") {
940         numBgFetched++;
941     }
942
943     check(get_int_stat(h, h1, "ep_bg_fetched") == numBgFetched,
944           "Bg fetched value didn't match");
945
946     h1->release(h, NULL, i);
947     check_key_value(h, h1, "key", "somevalue1", 10);
948     return SUCCESS;
949 }
950
951 static enum test_result test_incr_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
952     uint64_t result = 0;
953     item *i = NULL;
954     h1->arithmetic(h, NULL, "key", 3, true, false, 1, 0, 0,
955                    &i, PROTOCOL_BINARY_RAW_BYTES, &result,
956                    0);
957     h1->release(h, NULL, i);
958     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected to not find key");
959     return SUCCESS;
960 }
961
962 static enum test_result test_incr_full_eviction(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
963     uint64_t result = 0;
964     item *i = NULL;
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");
971     return SUCCESS;
972 }
973
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);
977
978     uint64_t result = 0;
979     item *i = NULL;
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.");
986
987     // Check datatype of counter
988     check(h1->get(h, cookie, &i, "key", 3, 0) == ENGINE_SUCCESS,
989             "Unable to get stored item");
990     item_info info;
991     info.nvalue = 1;
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");
995
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.");
1002
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.");
1009
1010     check_key_value(h, h1, "key", "3", 1);
1011
1012     // Check datatype of counter
1013     check(h1->get(h, cookie, &i, "key", 3, 0) == ENGINE_SUCCESS,
1014             "Unable to get stored item");
1015     info.nvalue = 1;
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");
1019
1020     testHarness.destroy_cookie(cookie);
1021     return SUCCESS;
1022 }
1023
1024 static enum test_result test_append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1025     item *i = NULL;
1026     item_info info;
1027     uint64_t vb_uuid = 0;
1028     uint32_t high_seqno = 0;
1029
1030     memset(&info, 0, sizeof(info));
1031
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);
1038
1039     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1040                        "\r\n", 2, 82758, &i, 0, 0)
1041           == ENGINE_SUCCESS,
1042           "Failed set.");
1043
1044     h1->release(h, NULL, i);
1045
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");
1048
1049     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1050                        "foo\r\n", 5, 82758, &i, 0, 0)
1051           == ENGINE_SUCCESS,
1052           "Failed append.");
1053     h1->release(h, NULL, i);
1054
1055     check(get_item_info(h, h1, &info, "key"), "Error in getting item info");
1056
1057     check(vb_uuid == info.vbucket_uuid, "Expected valid vbucket uuid");
1058     check(high_seqno + 1 == info.seqno, "Expected valid sequence number");
1059
1060     check_key_value(h, h1, "key", "\r\nfoo\r\n", 7);
1061
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);
1067
1068     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1069                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
1070           == ENGINE_SUCCESS,
1071           "Failed set.");
1072     h1->release(h, NULL, i);
1073
1074     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1075                        bigBinaryData3, dataSize, 82758, &i, 0, 0)
1076           == ENGINE_E2BIG,
1077           "Expected append failure.");
1078     h1->release(h, NULL, i);
1079     delete[] bigBinaryData3;
1080
1081     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1082                        binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
1083           == ENGINE_SUCCESS,
1084           "Failed append.");
1085     h1->release(h, NULL, i);
1086
1087     std::string expected;
1088     expected.append(binaryData1, sizeof(binaryData1) - 1);
1089     expected.append(binaryData2, sizeof(binaryData2) - 1);
1090
1091     check_key_value(h, h1, "key", expected.data(), expected.length());
1092     return SUCCESS;
1093 }
1094
1095 static enum test_result test_prepend(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1096     item *i = NULL;
1097     item_info info;
1098     uint64_t vb_uuid = 0;
1099     uint32_t high_seqno = 0;
1100
1101     memset(&info, 0, sizeof(info));
1102
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);
1109
1110     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1111                        "\r\n", 2, 82758, &i, 0, 0)
1112           == ENGINE_SUCCESS,
1113           "Failed set.");
1114     h1->release(h, NULL, i);
1115
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");
1118
1119     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1120                        "foo\r\n", 5, 82758, &i, 0, 0)
1121           == ENGINE_SUCCESS,
1122           "Failed prepend.");
1123     h1->release(h, NULL, i);
1124
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");
1128
1129     check_key_value(h, h1, "key", "foo\r\n\r\n", 7);
1130
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);
1136
1137     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1138                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
1139           == ENGINE_SUCCESS,
1140           "Failed set.");
1141     h1->release(h, NULL, i);
1142
1143     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1144                        bigBinaryData3, dataSize, 82758, &i, 0, 0)
1145           == ENGINE_E2BIG,
1146           "Expected prepend failure.");
1147     h1->release(h, NULL, i);
1148     delete[] bigBinaryData3;
1149
1150     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1151                        binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
1152           == ENGINE_SUCCESS,
1153           "Failed append.");
1154     h1->release(h, NULL, i);
1155
1156     std::string expected;
1157     expected.append(binaryData2, sizeof(binaryData2) - 1);
1158     expected.append(binaryData1, sizeof(binaryData1) - 1);
1159
1160     check_key_value(h, h1, "key", expected.data(), expected.length());
1161     return SUCCESS;
1162 }
1163
1164 static enum test_result test_append_compressed(ENGINE_HANDLE *h,
1165                                                ENGINE_HANDLE_V1 *h1) {
1166
1167     item *i = NULL;
1168
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);
1177     free (newBuf);
1178
1179     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key1",
1180                        "foo\r\n", 5, 82758, &i, 0, 0)
1181           == ENGINE_SUCCESS,
1182           "Failed append uncompressed to compressed.");
1183     h1->release(h, NULL, i);
1184
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);
1188
1189     item_info info;
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");
1195     free (newBuf1);
1196
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)
1203             == ENGINE_SUCCESS,
1204             "Failed append compressed to compressed.");
1205     h1->release(h, NULL, i);
1206     free (newBuf);
1207
1208     len1 = snappy_max_compressed_length(10);
1209     newBuf1 = (char *) malloc (len1);
1210     snappy_compress("\r\nfoo\r\nbar", 10, newBuf1, &len1);
1211
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");
1217     free (newBuf1);
1218
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);
1224
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)
1231             == ENGINE_SUCCESS,
1232             "Failed append compressed to uncompressed.");
1233     h1->release(h, NULL, i);
1234     free (newBuf);
1235
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");
1241
1242     return SUCCESS;
1243 }
1244
1245 static enum test_result test_prepend_compressed(ENGINE_HANDLE *h,
1246                                                ENGINE_HANDLE_V1 *h1) {
1247
1248     item *i = NULL;
1249
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);
1258     free (newBuf);
1259
1260     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key1",
1261                        "foo\r\n", 5, 82758, &i, 0, 0)
1262           == ENGINE_SUCCESS,
1263           "Failed prepend uncompressed to compressed.");
1264     h1->release(h, NULL, i);
1265
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);
1269
1270     item_info info;
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");
1276     free (newBuf1);
1277
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)
1284             == ENGINE_SUCCESS,
1285             "Failed prepend compressed to compressed.");
1286     h1->release(h, NULL, i);
1287     free (newBuf);
1288
1289     len1 = snappy_max_compressed_length(10);
1290     newBuf1 = (char *) malloc (len1);
1291     snappy_compress("barfoo\r\n\r\n", 10, newBuf1, &len1);
1292
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");
1298     free (newBuf1);
1299
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);
1305
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)
1312             == ENGINE_SUCCESS,
1313             "Failed prepend compressed to uncompressed.");
1314     h1->release(h, NULL, i);
1315     free (newBuf);
1316
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");
1322
1323     return SUCCESS;
1324 }
1325
1326 static enum test_result test_append_prepend_to_json(ENGINE_HANDLE *h,
1327                                                     ENGINE_HANDLE_V1 *h1) {
1328     item *i = NULL;
1329     item_info info;
1330
1331     const char* key1 = "foo1";
1332     const char* key2 = "foo2";
1333     const char* value1 = "{\"foo1\":\"bar1\"}";
1334     const char* value2 = "{\"foo2\":\"bar2\"}";
1335
1336     // APPEND
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);
1342
1343     check(h1->get(h, NULL, &i, key1, strlen(key1), 0) == ENGINE_SUCCESS,
1344             "Unable to get stored item");
1345     info.nvalue = 1;
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);
1351
1352     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, key1,
1353                        value2, strlen(value2), 82758, &i, 0, 0)
1354           == ENGINE_SUCCESS,
1355           "Failed append.");
1356     h1->release(h, NULL, i);
1357
1358     check(h1->get(h, NULL, &i, key1, strlen(key1), 0) == ENGINE_SUCCESS,
1359             "Unable to get stored item");
1360     info.nvalue = 1;
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);
1367
1368     // PREPEND
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);
1374
1375     check(h1->get(h, NULL, &i, key2, strlen(key2), 0) == ENGINE_SUCCESS,
1376             "Unable to get stored item");
1377     info.nvalue = 1;
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);
1383
1384     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, key2,
1385                        value2, strlen(value2), 82758, &i, 0, 0)
1386           == ENGINE_SUCCESS,
1387           "Failed prepend.");
1388     h1->release(h, NULL, i);
1389
1390     check(h1->get(h, NULL, &i, key2, strlen(key2), 0) == ENGINE_SUCCESS,
1391             "Unable to get stored item");
1392     info.nvalue = 1;
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);
1399
1400     return SUCCESS;
1401 }
1402
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);
1406
1407     uint64_t result = 0;
1408     item *i = NULL;
1409     const char *key = "key";
1410     const char *val = "1";
1411     check(store(h, h1, NULL, OPERATION_ADD,key, val, &i,
1412                 0, 0, 3600,
1413                 checkUTF8JSON((const unsigned char *)val, 1))
1414             == ENGINE_SUCCESS,
1415           "Failed to add value.");
1416     h1->release(h, NULL, i);
1417
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);
1423
1424     check_key_value(h, h1, key, "2", 1);
1425
1426     // Check datatype of counter
1427     check(h1->get(h, cookie, &i, key, 3, 0) == ENGINE_SUCCESS,
1428             "Unable to get stored item");
1429     item_info info;
1430     info.nvalue = 1;
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");
1434
1435     testHarness.destroy_cookie(cookie);
1436
1437     return SUCCESS;
1438 }
1439
1440 static enum test_result test_bug2799(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1441     uint64_t result = 0;
1442     item *i = NULL;
1443     check(store(h, h1, NULL, OPERATION_ADD, "key", "1", &i) == ENGINE_SUCCESS,
1444           "Failed to add value.");
1445     h1->release(h, NULL, i);
1446
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);
1452
1453     check_key_value(h, h1, "key", "2", 1);
1454
1455     testHarness.time_travel(3617);
1456
1457     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1458     return SUCCESS;
1459 }
1460
1461 static enum test_result test_flush(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1462     item *i = NULL;
1463
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");
1468     }
1469     check(get_int_stat(h, h1, "ep_flushall_enabled") == 1,
1470             "flushall wasn't enabled");
1471
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,
1475           "Failed set.");
1476     h1->release(h, NULL, i);
1477     check_key_value(h, h1, "key", "somevalue", 9);
1478
1479     set_degraded_mode(h, h1, NULL, true);
1480     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1481           "Failed to flush");
1482     set_degraded_mode(h, h1, NULL, false);
1483
1484     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1485
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);
1490
1491     return SUCCESS;
1492 }
1493
1494 /**
1495  * The following struct: flush_args and function run_flush(),
1496  * will be used by the test that follows: test_multiple_flush
1497  */
1498 struct flush_args {
1499     ENGINE_HANDLE *h;
1500     ENGINE_HANDLE_V1 *h1;
1501     ENGINE_ERROR_CODE expect;
1502     int when;
1503 };
1504
1505 extern "C" {
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;
1510
1511         check((args->h1)->flush(args->h, cookie, args->when) == args->expect,
1512                 "Return code is not what is expected");
1513
1514         testHarness.destroy_cookie(cookie);
1515     }
1516 }
1517
1518 static enum test_result test_multiple_flush(ENGINE_HANDLE *h,
1519                                             ENGINE_HANDLE_V1 *h1) {
1520
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");
1525     }
1526     check(get_int_stat(h, h1, "ep_flushall_enabled") == 1,
1527             "flushall wasn't enabled");
1528
1529     item *i = NULL;
1530     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1531           "Failed set.");
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");
1536
1537     set_degraded_mode(h, h1, NULL, true);
1538     cb_thread_t t1, t2;
1539     struct flush_args args1,args2;
1540     args1.h = h;
1541     args1.h1 = h1;
1542     args1.expect = ENGINE_SUCCESS;
1543     args1.when = 2;
1544     check(cb_create_thread(&t1, run_flush_all, &args1, 0) == 0,
1545             "cb_create_thread failed!");
1546
1547     sleep(1);
1548
1549     args2.h = h;
1550     args2.h1 = h1;
1551     args2.expect = ENGINE_TMPFAIL;
1552     args2.when = 0;
1553     check(cb_create_thread(&t2, run_flush_all, &args2, 0) == 0,
1554             "cb_create_thread failed!");
1555
1556     cb_assert(cb_join_thread(t1) == 0);
1557     cb_assert(cb_join_thread(t2) == 0);
1558
1559     set_degraded_mode(h, h1, NULL, false);
1560
1561     testHarness.reload_engine(&h, &h1,
1562                               testHarness.engine_path,
1563                               testHarness.get_current_testcase()->cfg,
1564                               true, false);
1565     wait_for_warmup_complete(h, h1);
1566     check(get_int_stat(h, h1, "curr_items") == 0,
1567           "Expected curr_items equals 0");
1568
1569     return SUCCESS;
1570 }
1571
1572 static enum test_result test_flush_disabled(ENGINE_HANDLE *h,
1573                                             ENGINE_HANDLE_V1 *h1) {
1574     item *i = NULL;
1575     // start an engine with disabled flush, the flush() should be noop and
1576     // we expect to see the key after flush()
1577
1578     // store a key and check its existence
1579     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1580           "Failed set.");
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");
1585     //check the key
1586     check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1587
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");
1594     }
1595     testHarness.reload_engine(&h, &h1,
1596                               testHarness.engine_path,
1597                               config.c_str(),
1598                               true, false);
1599     wait_for_warmup_complete(h, h1);
1600
1601
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);
1605
1606     //expect missing key
1607     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1608
1609     return SUCCESS;
1610 }
1611
1612 static enum test_result test_flush_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1613     item *i = NULL;
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");
1617
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,
1620           "Failed set.");
1621     h1->release(h, NULL, i);
1622     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i) == ENGINE_SUCCESS,
1623           "Failed set.");
1624     h1->release(h, NULL, i);
1625     testHarness.time_travel(65);
1626     wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
1627
1628     check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1629     check(ENGINE_SUCCESS == verify_key(h, h1, "key2"), "Expected key2");
1630
1631     check_key_value(h, h1, "key", "somevalue", 9);
1632     check_key_value(h, h1, "key2", "somevalue", 9);
1633
1634     int overhead2 = get_int_stat(h, h1, "ep_overhead");
1635     int cacheSize2 = get_int_stat(h, h1, "ep_total_cache_size");
1636
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");
1642
1643     wait_for_flusher_to_settle(h, h1);
1644
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");
1648
1649     cb_assert(overhead2 == overhead);
1650     cb_assert(nonResident2 == nonResident);
1651     cb_assert(cacheSize2 == cacheSize);
1652
1653     return SUCCESS;
1654 }
1655
1656 static enum test_result test_flush_multiv(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1657     item *i = NULL;
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,
1660           "Failed set.");
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);
1666
1667     check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1668     check(ENGINE_SUCCESS == verify_key(h, h1, "key2", 2), "Expected key2");
1669
1670     check_key_value(h, h1, "key", "somevalue", 9);
1671     check_key_value(h, h1, "key2", "somevalue", 9, 2);
1672
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);
1676
1677     vals.clear();
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");
1681
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");
1684
1685     return SUCCESS;
1686 }
1687
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);
1696     }
1697
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");
1702
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!");
1709     free(pkt);
1710
1711     std::vector<std::string>::iterator itr;
1712     for (itr = keys.begin(); itr != keys.end(); ++itr) {
1713         item *i;
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);
1717     }
1718
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,
1725           errmsg.c_str());
1726
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!");
1733     free(pkt);
1734
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");
1742 }
1743
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");
1751     return SUCCESS;
1752 }
1753
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");
1761     return SUCCESS;
1762 }
1763
1764 static enum test_result test_flush_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1765     item *i = NULL;
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,
1769           "Failed set.");
1770     h1->release(h, NULL, i);
1771     check_key_value(h, h1, "key", "somevalue", 9);
1772
1773     // Restart once to ensure written to disk.
1774     testHarness.reload_engine(&h, &h1,
1775                               testHarness.engine_path,
1776                               testHarness.get_current_testcase()->cfg,
1777                               true, false);
1778     wait_for_warmup_complete(h, h1);
1779
1780     // Read value from disk.
1781     check_key_value(h, h1, "key", "somevalue", 9);
1782
1783     // Flush
1784     set_degraded_mode(h, h1, NULL, true);
1785     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1786           "Failed to flush");
1787     set_degraded_mode(h, h1, NULL, false);
1788
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);
1793
1794     // Restart again, ensure written to disk.
1795     testHarness.reload_engine(&h, &h1,
1796                               testHarness.engine_path,
1797                               testHarness.get_current_testcase()->cfg,
1798                               true, false);
1799     wait_for_warmup_complete(h, h1);
1800
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);
1805
1806     // Read value again, should not be there.
1807     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1808     return SUCCESS;
1809 }
1810
1811 static enum test_result test_flush_multiv_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1812     item *i = NULL;
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,
1815           "Failed set.");
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);
1821
1822     // Restart once to ensure written to disk.
1823     testHarness.reload_engine(&h, &h1,
1824                               testHarness.engine_path,
1825                               testHarness.get_current_testcase()->cfg,
1826                               true, false);
1827     wait_for_warmup_complete(h, h1);
1828
1829     // Read value from disk.
1830     check_key_value(h, h1, "key", "somevalue", 9);
1831
1832     // Flush
1833     set_degraded_mode(h, h1, NULL, true);
1834     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1835           "Failed to flush");
1836     set_degraded_mode(h, h1, NULL, false);
1837
1838     // Restart again, ensure written to disk.
1839     testHarness.reload_engine(&h, &h1,
1840                               testHarness.engine_path,
1841                               testHarness.get_current_testcase()->cfg,
1842                               true, false);
1843     wait_for_warmup_complete(h, h1);
1844
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.");
1848     return SUCCESS;
1849 }
1850
1851 static enum test_result test_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1852     item *i = NULL;
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,
1856           "Failed set.");
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);
1861
1862     uint64_t cas = 0;
1863     uint64_t vb_uuid = 0;
1864     mutation_descr_t mut_info;
1865     uint32_t high_seqno = 0;
1866
1867     memset(&mut_info, 0, sizeof(mut_info));
1868
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");
1877
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),
1880             "Failed set.");
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");
1886
1887     return SUCCESS;
1888 }
1889
1890 static enum test_result test_set_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1891     item *i = NULL;
1892     checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1893             "Failed set.");
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);
1901     return SUCCESS;
1902 }
1903
1904 static enum test_result test_set_delete_invalid_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1905     item *i = NULL;
1906     check(store(h, h1, NULL, OPERATION_SET, "key",
1907                 "somevalue", &i) == ENGINE_SUCCESS,
1908           "Failed set.");
1909     check_key_value(h, h1, "key", "somevalue", 9);
1910     item_info info;
1911     info.nvalue = 1;
1912     check(h1->get_item_info(h, NULL, i, &info) == true,
1913           "Should be able to get info");
1914     h1->release(h, NULL, i);
1915
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");
1918     return SUCCESS;
1919 }
1920
1921 static enum test_result test_bug2509(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1922     for (int j = 0; j < 10000; ++j) {
1923         item *itm = NULL;
1924         checkeq(ENGINE_SUCCESS,
1925                 store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &itm),
1926                 "Failed set.");
1927         h1->release(h, NULL, itm);
1928         usleep(10);
1929         checkeq(ENGINE_SUCCESS, del(h, h1, "key", 0, 0), "Failed remove with value.");
1930         usleep(10);
1931     }
1932
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,
1937                               true, false);
1938     wait_for_warmup_complete(h, h1);
1939
1940     return get_int_stat(h, h1, "ep_warmup_dups") == 0 ? SUCCESS : FAIL;
1941 }
1942
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;
1948         ss << "key" << j;
1949         std::string key(ss.str());
1950         keys.push_back(key);
1951     }
1952
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) {
1961             item *i;
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);
1965
1966         }
1967     }
1968     wait_for_flusher_to_settle(h, h1);
1969
1970     // Restart again, to verify no data loss.
1971     testHarness.reload_engine(&h, &h1,
1972                               testHarness.engine_path,
1973                               testHarness.get_current_testcase()->cfg,
1974                               true, false);
1975     wait_for_warmup_complete(h, h1);
1976     return get_int_stat(h, h1, "ep_warmup_value_count", "warmup") == 10000 ? SUCCESS : FAIL;
1977 }
1978
1979 static enum test_result test_delete_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1980     wait_for_persisted_value(h, h1, "key", "value1");
1981
1982     check(del(h, h1, "key", 0, 0) == ENGINE_SUCCESS, "Failed remove with value.");
1983
1984     wait_for_persisted_value(h, h1, "key", "value2");
1985
1986     testHarness.reload_engine(&h, &h1,
1987                               testHarness.engine_path,
1988                               testHarness.get_current_testcase()->cfg,
1989                               true, false);
1990     wait_for_warmup_complete(h, h1);
1991
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);
1995
1996     testHarness.reload_engine(&h, &h1,
1997                               testHarness.engine_path,
1998                               testHarness.get_current_testcase()->cfg,
1999                               true, false);
2000     wait_for_warmup_complete(h, h1);
2001
2002     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
2003
2004     return SUCCESS;
2005 }
2006
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");
2010
2011     // whack the db file and directory where the key is stored
2012     rmdb();
2013
2014     item *i = NULL;
2015     int errorCode = h1->get(h, NULL, &i, key, strlen(key), 0);
2016     h1->release(h, NULL, i);
2017
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");
2021
2022     i = NULL;
2023     evict_key(h, h1, key);
2024     errorCode = h1->get(h, NULL, &i, key, strlen(key), 0);
2025     h1->release(h, NULL, i);
2026
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");
2030
2031     return SUCCESS;
2032 }
2033
2034
2035 static enum test_result test_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2036     item *i = NULL;
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,
2040           "Failed set.");
2041     h1->release(h, NULL, i);
2042
2043     testHarness.reload_engine(&h, &h1,
2044                               testHarness.engine_path,
2045                               testHarness.get_current_testcase()->cfg,
2046                               true, false);
2047     wait_for_warmup_complete(h, h1);
2048     check_key_value(h, h1, "key", val, strlen(val));
2049     return SUCCESS;
2050 }
2051
2052 static enum test_result test_restart_session_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2053     createTapConn(h, h1, "tap_client_thread");
2054
2055     testHarness.reload_engine(&h, &h1,
2056                               testHarness.engine_path,
2057                               testHarness.get_current_testcase()->cfg,
2058                               true, false);
2059     wait_for_warmup_complete(h, h1);
2060     createTapConn(h, h1, "tap_client_thread");
2061
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");
2066     return SUCCESS;
2067 }
2068
2069 static enum test_result test_specialKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2070     item *i = NULL;
2071     ENGINE_ERROR_CODE ret;
2072
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);
2122
2123     testHarness.reload_engine(&h, &h1,
2124                               testHarness.engine_path,
2125                               testHarness.get_current_testcase()->cfg,
2126                               true, false);
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));
2136     return SUCCESS;
2137 }
2138
2139 static enum test_result test_binKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2140     item *i = NULL;
2141     ENGINE_ERROR_CODE ret;
2142
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);
2171
2172     testHarness.reload_engine(&h, &h1,
2173                               testHarness.engine_path,
2174                               testHarness.get_current_testcase()->cfg,
2175                               true, false);
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));
2181     return SUCCESS;
2182 }
2183
2184 static enum test_result test_restart_bin_val(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2185
2186
2187
2188     char binaryData[] = "abcdefg\0gfedcba";
2189     cb_assert(sizeof(binaryData) != strlen(binaryData));
2190
2191     item *i = NULL;
2192     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
2193                        binaryData, sizeof(binaryData), 82758, &i, 0, 0)
2194           == ENGINE_SUCCESS,
2195           "Failed set.");
2196     h1->release(h, NULL, i);
2197
2198     testHarness.reload_engine(&h, &h1,
2199                               testHarness.engine_path,
2200                               testHarness.get_current_testcase()->cfg,
2201                               true, false);
2202     wait_for_warmup_complete(h, h1);
2203
2204     check_key_value(h, h1, "key", binaryData, sizeof(binaryData));
2205     return SUCCESS;
2206 }
2207
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);
2213     return SUCCESS;
2214 }
2215
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);
2220
2221     item *i = NULL;
2222     check(ENGINE_EWOULDBLOCK == h1->get(h, cookie, &i, "key", strlen("key"), 1),
2223           "Expected woodblock.");
2224     h1->release(h, NULL, i);
2225
2226     testHarness.destroy_cookie(cookie);
2227     return SUCCESS;
2228 }
2229
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);
2236     return SUCCESS;
2237 }
2238
2239 static enum test_result test_wrong_vb_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2240     uint64_t result;
2241     item *i = NULL;
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);
2249     return SUCCESS;
2250 }
2251
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);
2255     uint64_t result;
2256     item *i = NULL;
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);
2264     return SUCCESS;
2265 }
2266
2267 static enum test_result test_vb_incr_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2268     uint64_t result;
2269     item *i = NULL;
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);
2278     return SUCCESS;
2279 }
2280
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);
2283 }
2284
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);
2287 }
2288
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);
2291 }
2292
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);
2295 }
2296
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);
2299 }
2300
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);
2303 }
2304
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);
2309     return SUCCESS;
2310 }
2311
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.";
2315
2316     item *it = NULL;
2317
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.");
2322
2323     item_info info;
2324     info.nvalue = 1;
2325     if (!h1->get_item_info(h, NULL, it, &info)) {
2326         abort();
2327     }
2328     memcpy(info.value[0].iov_base, data, strlen(data));
2329
2330     uint64_t cas = 0;
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);
2335
2336     testHarness.time_travel(5);
2337     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
2338           "Item didn't expire");
2339
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),
2347             "Failed set.");
2348     h1->release(h, NULL, it);
2349
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());
2354
2355     return SUCCESS;
2356 }
2357
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.";
2361
2362     item *it = NULL;
2363
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.");
2368
2369     item_info info;
2370     info.nvalue = 1;
2371     if (!h1->get_item_info(h, NULL, it, &info)) {
2372         abort();
2373     }
2374     memcpy(info.value[0].iov_base, data, strlen(data));
2375
2376     uint64_t cas = 0;
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);
2381
2382     testHarness.time_travel(3);
2383
2384     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
2385           "Item didn't expire");
2386
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,
2391                               true, false);
2392     wait_for_warmup_complete(h, h1);
2393     cb_assert(0 == get_int_stat(h, h1, "ep_warmup_value_count", "warmup"));
2394
2395     return SUCCESS;
2396 }
2397
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";
2402
2403     item *it = NULL;
2404
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.");
2409
2410     item_info info;
2411     info.nvalue = 1;
2412     if (!h1->get_item_info(h, NULL, it, &info)) {
2413         abort();
2414     }
2415     memcpy(info.value[0].iov_base, data, strlen(data));
2416
2417     uint64_t cas = 0;
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);
2423
2424     check(get_int_stat(h, h1, "curr_items") == 1, "Failed store item");
2425     testHarness.time_travel(5);
2426
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,
2431                               true, false);
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.");
2438
2439     return SUCCESS;
2440
2441 }
2442
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.";
2446
2447     item *it = NULL;
2448
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.");
2453
2454     item_info info;
2455     info.nvalue = 1;
2456     if (!h1->get_item_info(h, NULL, it, &info)) {
2457         abort();
2458     }
2459     memcpy(info.value[0].iov_base, data, strlen(data));
2460
2461     uint64_t cas = 0;
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);
2467
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");
2472
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.");
2476
2477     info.nvalue = 1;
2478     if (!h1->get_item_info(h, NULL, it, &info)) {
2479         abort();
2480     }
2481     memcpy(info.value[0].iov_base, data, strlen(data));
2482
2483     cas = 0;
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);
2489
2490     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_SUCCESS,
2491           "Item shouldn't expire");
2492     h1->release(h, NULL, it);
2493
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,
2498                               true, false);
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"));
2502
2503     return SUCCESS;
2504 }
2505
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.";
2509
2510     item *it = NULL;
2511
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.");
2516
2517     item_info info;
2518     info.nvalue = 1;
2519     if (!h1->get_item_info(h, NULL, it, &info)) {
2520         abort();
2521     }
2522     memcpy(info.value[0].iov_base, data, strlen(data));
2523
2524     uint64_t cas = 0;
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);
2530
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.");
2536
2537     info.nvalue = 1;
2538     if (!h1->get_item_info(h, NULL, it, &info)) {
2539         abort();
2540     }
2541     memcpy(info.value[0].iov_base, new_data, strlen(new_data));
2542
2543     int pager_runs = get_int_stat(h, h1, "ep_num_expiry_pager_runs");
2544     cas = 0;
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);
2552
2553     // Restart the engine.
2554     testHarness.reload_engine(&h, &h1,
2555                               testHarness.engine_path,
2556                               testHarness.get_current_testcase()->cfg,
2557                               true, false);
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"));
2561
2562     return SUCCESS;
2563 }
2564
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.");
2573
2574     return SUCCESS;
2575 }
2576
2577 static enum test_result test_get_replica_pending_state(ENGINE_HANDLE *h,
2578                                                        ENGINE_HANDLE_V1 *h1) {
2579     protocol_binary_request_header *pkt;
2580
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);
2587     return SUCCESS;
2588 }
2589
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.");
2598
2599     return SUCCESS;
2600 }
2601
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");
2612
2613     return SUCCESS;
2614 }
2615
2616 static enum test_result test_get_replica_non_resident(ENGINE_HANDLE *h,
2617                                                       ENGINE_HANDLE_V1 *h1) {
2618
2619     item *i = NULL;
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);
2625
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");
2629
2630     get_replica(h, h1, "key", 0);
2631     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "Expected success");
2632
2633     return SUCCESS;
2634 }
2635
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.");
2645     return SUCCESS;
2646 }
2647
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);
2655     return SUCCESS;
2656 }
2657
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);
2664     return SUCCESS;
2665 }
2666
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");
2671
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");
2678     free(request);
2679
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");
2683
2684     // illegal vbucket
2685     touch(h, h1, "mykey", 5, (time(NULL) + 10));
2686     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, "Testing illegal vbucket");
2687
2688     // Store the item!
2689     item *itm = NULL;
2690     check(store(h, h1, NULL, OPERATION_SET, "mykey", "somevalue", &itm) == ENGINE_SUCCESS,
2691           "Failed set.");
2692     h1->release(h, NULL, itm);
2693
2694     check_key_value(h, h1, "mykey", "somevalue", strlen("somevalue"));
2695
2696     touch(h, h1, "mykey", 0, (time(NULL) + 10));
2697     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch mykey");
2698
2699     // time-travel 9 secs..
2700     testHarness.time_travel(9);
2701
2702     // The item should still exist
2703     check_key_value(h, h1, "mykey", "somevalue", 9);
2704
2705     // time-travel 2 secs..
2706     testHarness.time_travel(2);
2707
2708     // The item should have expired now...
2709     check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2710     return SUCCESS;
2711 }
2712
2713 static enum test_result test_touch_mb7342(ENGINE_HANDLE *h,
2714                                           ENGINE_HANDLE_V1 *h1) {
2715     const char *key = "MB-7342";
2716     // Store the item!
2717     item *itm = NULL;
2718     check(store(h, h1, NULL, OPERATION_SET, key, "v", &itm) == ENGINE_SUCCESS,
2719           "Failed set.");
2720     h1->release(h, NULL, itm);
2721
2722     touch(h, h1, key, 0, 0);
2723     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch key");
2724
2725     check_key_value(h, h1, key, "v", 1);
2726
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);
2730
2731     check_key_value(h, h1, key, "v", 1);
2732
2733     return SUCCESS;
2734 }
2735
2736 static enum test_result test_touch_mb10277(ENGINE_HANDLE *h,
2737                                             ENGINE_HANDLE_V1 *h1) {
2738     const char *key = "MB-10277";
2739     // Store the item!
2740     item *itm = NULL;
2741     check(store(h, h1, NULL, OPERATION_SET, key, "v", &itm) == ENGINE_SUCCESS,
2742           "Failed set.");
2743     h1->release(h, NULL, itm);
2744     wait_for_flusher_to_settle(h, h1);
2745     evict_key(h, h1, key, 0, "Ejected.");
2746
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");
2749
2750     return SUCCESS;
2751 }
2752
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");
2757
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");
2764     free(request);
2765
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");
2769
2770     // illegal vbucket
2771     gat(h, h1, "mykey", 5, 10);
2772     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, "Testing illegal vbucket");
2773
2774     // Store the item!
2775     item *itm = NULL;
2776     check(store(h, h1, NULL, OPERATION_SET, "mykey", "{\"some\":\"value\"}",
2777                 &itm, 0, 0, 3600, PROTOCOL_BINARY_DATATYPE_JSON) == ENGINE_SUCCESS,
2778           "Failed set.");
2779     h1->release(h, NULL, itm);
2780
2781     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2782             strlen("{\"some\":\"value\"}"));
2783
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");
2790
2791     // time-travel 9 secs..
2792     testHarness.time_travel(9);
2793
2794     // The item should still exist
2795     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2796                     strlen("{\"some\":\"value\"}"));
2797
2798     // time-travel 2 secs..
2799     testHarness.time_travel(2);
2800
2801     // The item should have expired now...
2802     check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2803     return SUCCESS;
2804 }
2805
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");
2810
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");
2817     free(request);
2818
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);
2822
2823     // We should not have sent any response!
2824     check(last_status == (protocol_binary_response_status)0xffff, "Testing unknown key");
2825
2826     // illegal vbucket
2827     gat(h, h1, "mykey", 5, 10, true);
2828     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2829           "Testing illegal vbucket");
2830
2831     // Store the item!
2832     item *itm = NULL;
2833     check(store(h, h1, NULL, OPERATION_SET, "mykey", "{\"some\":\"value\"}",
2834                 &itm, 0, 0, 3600, PROTOCOL_BINARY_DATATYPE_JSON) == ENGINE_SUCCESS,
2835           "Failed set.");
2836     h1->release(h, NULL, itm);
2837
2838     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2839                     strlen("{\"some\":\"value\"}"));
2840
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");
2847
2848     // time-travel 9 secs..
2849     testHarness.time_travel(9);
2850
2851     // The item should still exist
2852     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2853                     strlen("{\"some\":\"value\"}"));
2854
2855     // time-travel 2 secs..
2856     testHarness.time_travel(2);
2857
2858     // The item should have expired now...
2859     check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2860     return SUCCESS;
2861 }
2862
2863 static enum test_result test_mb5215(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2864     item *itm = NULL;
2865     check(store(h, h1, NULL, OPERATION_SET, "coolkey", "cooler", &itm)
2866           == ENGINE_SUCCESS, "Failed set.");
2867     h1->release(h, NULL, itm);
2868
2869     check_key_value(h, h1, "coolkey", "cooler", strlen("cooler"));
2870
2871     // set new exptime to 111
2872     int expTime = time(NULL) + 111;
2873
2874     touch(h, h1, "coolkey", 0, expTime);
2875     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch coolkey");
2876
2877     //reload engine
2878     testHarness.reload_engine(&h, &h1,
2879                               testHarness.engine_path,
2880                               testHarness.get_current_testcase()->cfg,
2881                               true, false);
2882
2883     wait_for_warmup_complete(h, h1);
2884
2885     //verify persisted expiration time
2886     const char *statkey = "key coolkey 0";
2887     int newExpTime;
2888     check(h1->get(h, NULL, &itm, "coolkey", 7, 0) == ENGINE_SUCCESS,
2889           "Missing key");
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");
2893
2894     // evict key, touch expiration time, and verify
2895     evict_key(h, h1, "coolkey", 0, "Ejected.");
2896
2897     expTime = time(NULL) + 222;
2898     touch(h, h1, "coolkey", 0, expTime);
2899     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch coolkey");
2900
2901     testHarness.reload_engine(&h, &h1,
2902                               testHarness.engine_path,
2903                               testHarness.get_current_testcase()->cfg,
2904                               true, false);
2905     wait_for_warmup_complete(h, h1);
2906
2907     check(h1->get(h, NULL, &itm, "coolkey", 7, 0) == ENGINE_SUCCESS,
2908           "Missing key");
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");
2912
2913     return SUCCESS;
2914 }
2915
2916 static enum test_result test_alloc_limit(ENGINE_HANDLE *h,
2917                                          ENGINE_HANDLE_V1 *h1) {
2918     item *it = NULL;
2919     ENGINE_ERROR_CODE rv;
2920
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);
2925
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");
2929
2930     return SUCCESS;
2931 }
2932
2933 static enum test_result test_whitespace_db(ENGINE_HANDLE *h,
2934                                            ENGINE_HANDLE_V1 *h1) {
2935     vals.clear();
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;
2941         return FAIL;
2942     }
2943
2944     check(access(WHITESPACE_DB, F_OK) != -1, "I expected the whitespace db to exist");
2945     return SUCCESS;
2946 }
2947
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") {
2953         return SUCCESS;
2954     } else {
2955         std::cerr << "Memory tracker not enabled" << std::endl;
2956         return FAIL;
2957     }
2958 }
2959
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);
2970
2971     char *data = new char[2 * 1024 * 1024];
2972     cb_assert(data);
2973     memset(data, 'x', 2 * 1024 * 1024);
2974
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;
2978     data[vlen] = 0x00;
2979
2980     item *i = NULL;
2981     // So if we add an item,
2982     check(store(h, h1, NULL, OPERATION_SET, "key", data, &i) == ENGINE_SUCCESS,
2983           "store failure");
2984     check_key_value(h, h1, "key", data, vlen);
2985     h1->release(h, NULL, i);
2986     i = NULL;
2987
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");
2992     if (i) {
2993         h1->release(h, NULL, i);
2994         i = NULL;
2995     }
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.");
2998
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");
3002     if (i) {
3003         h1->release(h, NULL, i);
3004         i = NULL;
3005     }
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);
3016
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);
3021     delete []data;
3022     return SUCCESS;
3023 }
3024
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;
3027 }
3028
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;
3031 }
3032
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");
3036         return FAIL;
3037     }
3038
3039     if (!set_vbucket_state(h, h1, 1, vbucket_state_active)) {
3040         fprintf(stderr, "set state failed.\n");
3041         return FAIL;
3042     }
3043
3044     return verify_vbucket_state(h, h1, 1, vbucket_state_active) ? SUCCESS : FAIL;
3045 }
3046
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");
3053         return FAIL;
3054     }
3055
3056     if (!set_vbucket_state(h, h1, 0, vbucket_state_active)) {
3057         fprintf(stderr, "set state failed.\n");
3058         return FAIL;
3059     }
3060
3061     check(verify_vbucket_state(h, h1, 0, vbucket_state_active),
3062             "VBucket state not active");
3063
3064     // Set two keys - one to be expired and other to remain...
3065     item *itm = NULL;
3066     check(store(h, h1, NULL, OPERATION_SET, key, value, &itm)
3067           == ENGINE_SUCCESS, "Failed set.");
3068     h1->release(h, NULL, itm);
3069
3070     check_key_value(h, h1, key, value, strlen(value));
3071
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);
3076
3077     check_key_value(h, h1, "trees", "cleanse", strlen("cleanse"));
3078
3079     touch(h, h1, key, 0, 11);
3080     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch Carss");
3081
3082     testHarness.time_travel(12);
3083     wait_for_flusher_to_settle(h, h1);
3084
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.");
3089
3090     wait_for_flusher_to_settle(h, h1);
3091
3092     check(get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno") == 0,
3093             "purge_seqno not found to be zero before compaction");
3094
3095     // Compaction on VBucket
3096     compact_db(h, h1, 0, 2, 3, 1);
3097
3098     check(get_int_stat(h, h1, "ep_pending_compactions") == 0,
3099     "ep_pending_compactions stat did not tick down after compaction command");
3100
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.");
3107
3108     check(get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno") == 4,
3109         "purge_seqno didn't match expected value");
3110
3111     return SUCCESS;
3112 }
3113
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";
3121
3122     /* Write 2 keys */
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),
3126                 "Error setting.");
3127     }
3128
3129     /* Delete one key */
3130     checkeq(ENGINE_SUCCESS, del(h, h1, key[0], 0, 0),
3131             "Failed remove with value.");
3132
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,
3136                   0, 0, 0),
3137             "Error setting.");
3138     wait_for_flusher_to_settle(h, h1);
3139
3140     /* Compact once */
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");
3149
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");
3157
3158     /* Reload the engine */
3159     testHarness.reload_engine(&h, &h1,
3160                               testHarness.engine_path,
3161                               testHarness.get_current_testcase()->cfg,
3162                               true, false);
3163     wait_for_warmup_complete(h, h1);
3164
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");
3169
3170     return SUCCESS;
3171 }
3172
3173 static enum test_result test_compaction_config(ENGINE_HANDLE *h,
3174                                                ENGINE_HANDLE_V1 *h1) {
3175
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");
3182     return SUCCESS;
3183 }
3184
3185 struct comp_thread_ctx {
3186     ENGINE_HANDLE *h;
3187     ENGINE_HANDLE_V1 *h1;
3188     uint16_t vbid;
3189 };
3190
3191 extern "C" {
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);
3195     }
3196 }
3197
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);
3203             return FAIL;
3204         }
3205         check(verify_vbucket_state(h, h1, i, vbucket_state_active),
3206               "VBucket state not active");
3207     }
3208
3209     std::vector<std::string> keys;
3210     for (int j = 0; j < 20000; ++j) {
3211         std::stringstream ss;
3212         ss << "key" << j;
3213         std::string key(ss.str());
3214         keys.push_back(key);
3215     }
3216
3217     int count = 0;
3218     std::vector<std::string>::iterator it;
3219     for (it = keys.begin(); it != keys.end(); ++it) {
3220         uint16_t vbid = count % 4;
3221         item *i;
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);
3225         ++count;
3226     }
3227
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];
3232
3233     for (int i = 0; i < n_threads; i++) {
3234         ctx[i].h = h;
3235         ctx[i].h1 = h1;
3236         ctx[i].vbid = static_cast<uint16_t>(i);
3237         int r = cb_create_thread(&threads[i], compaction_thread, &ctx[i], 0);
3238         cb_assert(r == 0);
3239     }
3240
3241     for (int i = 0; i < n_threads; i++) {
3242         int r = cb_join_thread(threads[i]);
3243         cb_assert(r == 0);
3244     }
3245
3246     check(get_int_stat(h, h1, "ep_pending_compactions") == 0,
3247     "ep_pending_compactions stat did not tick down after compaction command");
3248
3249     return SUCCESS;
3250 }
3251
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);
3258             return FAIL;
3259         }
3260         check(verify_vbucket_state(h, h1, i, vbucket_state_active),
3261               "VBucket state not active");
3262     }
3263
3264     std::vector<std::string> keys;
3265     for (int j = 0; j < 10000; ++j) {
3266         std::stringstream ss;
3267         ss << "key" << j;
3268         std::string key(ss.str());
3269         keys.push_back(key);
3270     }
3271
3272     int count = 0;
3273     std::vector<std::string>::iterator it;
3274     for (it = keys.begin(); it != keys.end(); ++it) {
3275         uint16_t vbid = count % 4;
3276         item *i;
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);
3280         ++count;
3281     }
3282     wait_for_flusher_to_settle(h, h1);
3283
3284     for (int i = 0; i < 2; ++i) {
3285         count = 0;
3286         for (it = keys.begin(); it != keys.end(); ++it) {
3287             uint16_t vbid = count % 4;
3288             item *i = NULL;
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);
3292             ++count;
3293         }
3294     }
3295     wait_for_str_stat_to_be(h, h1, "ep_workload_pattern", "read_heavy", NULL);
3296
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];
3301
3302     for (int i = 0; i < n_threads; i++) {
3303         ctx[i].h = h;
3304         ctx[i].h1 = h1;
3305         ctx[i].vbid = static_cast<uint16_t>(i);
3306         int r = cb_create_thread(&threads[i], compaction_thread, &ctx[i], 0);
3307         cb_assert(r == 0);
3308     }
3309
3310     for (int i = 0; i < n_threads; i++) {
3311         int r = cb_join_thread(threads[i]);
3312         cb_assert(r == 0);
3313     }
3314
3315     check(get_int_stat(h, h1, "ep_pending_compactions") == 0,
3316     "ep_pending_compactions stat did not tick down after compaction command");
3317
3318     return SUCCESS;
3319 }
3320
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.");
3324
3325     vbucketDelete(h, h1, 2, value);
3326     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
3327           "Expected failure deleting non-existent bucket.");
3328
3329     check(set_vbucket_state(h, h1, 1, vbucket_state_dead), "Failed set set vbucket 1 state.");
3330
3331     vbucketDelete(h, h1, 1, value);
3332     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
3333           "Expected failure deleting non-existent bucket.");
3334
3335     check(verify_vbucket_missing(h, h1, 1),
3336           "vbucket 0 was not missing after deleting it.");
3337
3338     return SUCCESS;
3339 }
3340
3341 static enum test_result test_vbucket_destroy_stats(ENGINE_HANDLE *h,
3342                                                    ENGINE_HANDLE_V1 *h1) {
3343
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");
3347
3348     check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed to set vbucket state.");
3349
3350     std::vector<std::string> keys;
3351     for (int j = 0; j < 2000; ++j) {
3352         std::stringstream ss;
3353         ss << "key" << j;
3354         std::string key(ss.str());
3355         keys.push_back(key);
3356     }
3357
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) {
3361         item *i;
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);
3365     }
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);
3369
3370     check(set_vbucket_state(h, h1, 1, vbucket_state_dead), "Failed set set vbucket 1 state.");
3371
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.");
3376
3377     check(verify_vbucket_missing(h, h1, 1),
3378           "vbucket 1 was not missing after deleting it.");
3379
3380     wait_for_stat_change(h, h1, "ep_vbucket_del", vbucketDel);
3381
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);
3385
3386     return SUCCESS;
3387 }
3388
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.");
3392
3393     // Store a value so the restart will try to resurrect it.
3394     item *i = NULL;
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);
3399
3400     // Reload to get a flush forced.
3401     testHarness.reload_engine(&h, &h1,
3402                               testHarness.engine_path,
3403                               testHarness.get_current_testcase()->cfg,
3404                               true, false);
3405     wait_for_warmup_complete(h, h1);
3406
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);
3411
3412     check(set_vbucket_state(h, h1, 1, vbucket_state_dead), "Failed set set vbucket 1 state.");
3413
3414     vbucketDelete(h, h1, 1, value);
3415     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
3416           "Expected failure deleting non-existent bucket.");
3417
3418     check(verify_vbucket_missing(h, h1, 1),
3419           "vbucket 1 was not missing after deleting it.");
3420
3421     testHarness.reload_engine(&h, &h1,
3422                               testHarness.engine_path,
3423                               testHarness.get_current_testcase()->cfg,
3424                               true, false);
3425     wait_for_warmup_complete(h, h1);
3426
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;
3429         abort();
3430     }
3431
3432     check(verify_vbucket_missing(h, h1, 1),
3433           "vbucket 1 was not missing after restart.");
3434
3435     return SUCCESS;
3436 }
3437
3438 static enum test_result test_async_vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3439     return vbucket_destroy(h, h1);
3440 }
3441
3442 static enum test_result test_sync_vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3443     return vbucket_destroy(h, h1, "async=0");
3444 }
3445
3446 static enum test_result test_async_vbucket_destroy_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3447     return vbucket_destroy_restart(h, h1);
3448 }
3449
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");
3452 }
3453
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);
3456 }
3457
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);
3460 }
3461
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);
3464 }
3465
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);
3468 }
3469
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);
3472 }
3473
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);
3476 }
3477
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);
3480 }
3481
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);
3484 }
3485
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);
3488 }
3489
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);
3492 }
3493
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);
3496 }
3497
3498 static enum test_result test_vb_prepend_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {