Merge remote-tracking branch 'couchbase/3.0.x' into sherlock
[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_stat_change(h, h1, "ep_vb_snapshot_total", 0);
234
235     // warmup is complete, notify ep engine that it must now enable
236     // data traffic
237     protocol_binary_request_header *pkt = createPacket(PROTOCOL_BINARY_CMD_ENABLE_TRAFFIC);
238     check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
239           "Failed to enable data traffic");
240     free(pkt);
241
242     return true;
243 }
244
245 static enum test_result test_getl(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
246     const char *key = "k1";
247     uint16_t vbucketId = 0;
248     uint32_t expiration = 25;
249
250     getl(h, h1, key, vbucketId, expiration);
251     check(last_status == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT,
252           "expected the key to be missing...");
253     if (!last_body.empty() && last_body != "NOT_FOUND") {
254         fprintf(stderr, "Should have returned NOT_FOUND. Getl Failed");
255         abort();
256     }
257
258     item *i = NULL;
259     check(store(h, h1, NULL, OPERATION_SET, key, "{\"lock\":\"data\"}",
260                 &i, 0, vbucketId, 3600, PROTOCOL_BINARY_DATATYPE_JSON)
261           == ENGINE_SUCCESS, "Failed to store an item.");
262     h1->release(h, NULL, i);
263
264     /* retry getl, should succeed */
265     getl(h, h1, key, vbucketId, expiration);
266     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
267           "Expected to be able to getl on first try");
268     check(last_body == "{\"lock\":\"data\"}", "Body was malformed.");
269     check(last_datatype == PROTOCOL_BINARY_DATATYPE_JSON,
270             "Expected datatype to be JSON");
271
272     /* wait 16 seconds */
273     testHarness.time_travel(16);
274
275     /* lock's taken so this should fail */
276     getl(h, h1, key, vbucketId, expiration);
277     check(last_status == PROTOCOL_BINARY_RESPONSE_ETMPFAIL,
278           "Expected to fail getl on second try");
279
280     if (!last_body.empty() && last_body != "LOCK_ERROR") {
281         fprintf(stderr, "Should have returned LOCK_ERROR. Getl Failed");
282         abort();
283     }
284
285     check(store(h, h1, NULL, OPERATION_SET, key, "lockdata2", &i, 0, vbucketId)
286           != ENGINE_SUCCESS, "Should have failed to store an item.");
287     h1->release(h, NULL, i);
288
289     /* wait another 10 seconds */
290     testHarness.time_travel(10);
291
292     /* retry set, should succeed */
293     check(store(h, h1, NULL, OPERATION_SET, key, "lockdata", &i, 0, vbucketId)
294           == ENGINE_SUCCESS, "Failed to store an item.");
295     h1->release(h, NULL, i);
296
297     /* point to wrong vbucket, to test NOT_MY_VB response */
298     getl(h, h1, key, 10, expiration);
299     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
300           "Should have received not my vbucket response");
301
302     /* acquire lock, should succeed */
303     getl(h, h1, key, vbucketId, expiration);
304     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
305           "Aquire lock should have succeeded");
306     check(last_datatype == PROTOCOL_BINARY_RAW_BYTES,
307             "Expected datatype to be RAW BYTES");
308
309     /* try an incr operation followed by a delete, both of which should fail */
310     uint64_t cas = 0;
311     uint64_t result = 0;
312     i = NULL;
313     check(h1->arithmetic(h, NULL, key, 2, true, false, 1, 1, 0,
314                          &i, PROTOCOL_BINARY_RAW_BYTES, &result,
315                          0) == ENGINE_TMPFAIL, "Incr failed");
316     h1->release(h, NULL, i);
317
318     check(del(h, h1, key, 0, 0) == ENGINE_TMPFAIL, "Delete failed");
319
320
321     /* bug MB 2699 append after getl should fail with ENGINE_TMPFAIL */
322
323     testHarness.time_travel(26);
324
325     char binaryData1[] = "abcdefg\0gfedcba";
326     char binaryData2[] = "abzdefg\0gfedcba";
327
328     check(storeCasVb11(h, h1, NULL, OPERATION_SET, key,
329                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
330           == ENGINE_SUCCESS,
331           "Failed set.");
332     h1->release(h, NULL, i);
333
334     /* acquire lock, should succeed */
335     getl(h, h1, key, vbucketId, expiration);
336     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
337           "Aquire lock should have succeeded");
338
339     /* append should fail */
340     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, key,
341                        binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
342           == ENGINE_TMPFAIL,
343           "Append should fail.");
344     h1->release(h, NULL, i);
345
346     /* bug MB 3252 & MB 3354.
347      * 1. Set a key with an expiry value.
348      * 2. Take a lock on the item before it expires
349      * 3. Wait for the item to expire
350      * 4. Perform a CAS operation, should fail
351      * 5. Perform a set operation, should succeed
352      */
353     const char *ekey = "test_expiry";
354     const char *edata = "some test data here.";
355
356     item *it = NULL;
357
358     check(h1->allocate(h, NULL, &it, ekey, strlen(ekey), strlen(edata), 0, 2,
359           PROTOCOL_BINARY_RAW_BYTES) == ENGINE_SUCCESS, "Allocation Failed");
360
361     item_info info;
362     info.nvalue = 1;
363     if (!h1->get_item_info(h, NULL, it, &info)) {
364         abort();
365     }
366     memcpy(info.value[0].iov_base, edata, strlen(edata));
367
368     check(h1->store(h, NULL, it, &cas, OPERATION_SET, 0) ==
369         ENGINE_SUCCESS, "Failed to Store item");
370     check_key_value(h, h1, ekey, edata, strlen(edata));
371     h1->release(h, NULL, it);
372
373     testHarness.time_travel(3);
374     cas = last_cas;
375
376     /* cas should fail */
377     check(storeCasVb11(h, h1, NULL, OPERATION_CAS, ekey,
378                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, cas, 0)
379           != ENGINE_SUCCESS,
380           "CAS succeeded.");
381     h1->release(h, NULL, i);
382
383     /* but a simple store should succeed */
384     check(store(h, h1, NULL, OPERATION_SET, ekey, edata, &i, 0, vbucketId)
385           == ENGINE_SUCCESS, "Failed to store an item.");
386     h1->release(h, NULL, i);
387     return SUCCESS;
388 }
389
390 static enum test_result test_unl(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
391
392     const char *key = "k2";
393     uint16_t vbucketId = 0;
394
395     unl(h, h1, key, vbucketId);
396     check(last_status != PROTOCOL_BINARY_RESPONSE_SUCCESS,
397           "expected the key to be missing...");
398
399     item *i = NULL;
400     check(store(h, h1, NULL, OPERATION_SET, key, "lockdata", &i, 0, vbucketId)
401           == ENGINE_SUCCESS, "Failed to store an item.");
402     h1->release(h, NULL, i);
403
404     /* getl, should succeed */
405     getl(h, h1, key, vbucketId, 0);
406     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
407           "Expected to be able to getl on first try");
408
409     /* save the returned cas value for later */
410     uint64_t cas = last_cas;
411
412     /* lock's taken unlocking with a random cas value should fail */
413     unl(h, h1, key, vbucketId);
414     check(last_status == PROTOCOL_BINARY_RESPONSE_ETMPFAIL,
415           "Expected to fail getl on second try");
416
417     if (!last_body.empty() && last_body != "UNLOCK_ERROR") {
418         fprintf(stderr, "Should have returned UNLOCK_ERROR. Unl Failed");
419         abort();
420     }
421
422     unl(h, h1, key, vbucketId, cas);
423     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
424           "Expected to succed unl with correct cas");
425
426     /* acquire lock, should succeed */
427     getl(h, h1, key, vbucketId, 0);
428
429     /* wait 16 seconds */
430     testHarness.time_travel(16);
431
432     /* lock has expired, unl should fail */
433     unl(h, h1, key, vbucketId, last_cas);
434     check(last_status == PROTOCOL_BINARY_RESPONSE_ETMPFAIL,
435           "Expected to fail unl on lock timeout");
436
437     return SUCCESS;
438 }
439
440 static enum test_result test_wrong_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
441                                                ENGINE_STORE_OPERATION op) {
442     item *i = NULL;
443     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
444     uint64_t cas = 11;
445     if (op == OPERATION_ADD) {
446         // Add operation with cas != 0 doesn't make sense
447         cas = 0;
448     }
449     check(store(h, h1, NULL, op,
450                 "key", "somevalue", &i, cas, 1) == ENGINE_NOT_MY_VBUCKET,
451         "Expected not_my_vbucket");
452     h1->release(h, NULL, i);
453     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
454     return SUCCESS;
455 }
456
457 static enum test_result test_pending_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
458                                                  ENGINE_STORE_OPERATION op) {
459     const void *cookie = testHarness.create_cookie();
460     testHarness.set_ewouldblock_handling(cookie, false);
461     item *i = NULL;
462     check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
463     check(verify_vbucket_state(h, h1, 1, vbucket_state_pending), "Bucket state was not set to pending.");
464     uint64_t cas = 11;
465     if (op == OPERATION_ADD) {
466         // Add operation with cas != 0 doesn't make sense..
467         cas = 0;
468     }
469     check(store(h, h1, cookie, op,
470                 "key", "somevalue", &i, cas, 1) == ENGINE_EWOULDBLOCK,
471         "Expected woodblock");
472     h1->release(h, NULL, i);
473     testHarness.destroy_cookie(cookie);
474     return SUCCESS;
475 }
476
477 static enum test_result test_replica_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
478                                                  ENGINE_STORE_OPERATION op) {
479     item *i = NULL;
480     check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
481     check(verify_vbucket_state(h, h1, 1, vbucket_state_replica), "Bucket state was not set to replica.");
482     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
483
484     uint64_t cas = 11;
485     if (op == OPERATION_ADD) {
486         // performing add with a CAS != 0 doesn't make sense...
487         cas = 0;
488     }
489     check(store(h, h1, NULL, op,
490                 "key", "somevalue", &i, cas, 1) == ENGINE_NOT_MY_VBUCKET,
491         "Expected not my vbucket");
492     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
493     h1->release(h, NULL, i);
494     return SUCCESS;
495 }
496
497 //
498 // ----------------------------------------------------------------------
499 // The actual tests are below.
500 // ----------------------------------------------------------------------
501 //
502
503 static enum test_result test_get_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
504     check(verify_key(h, h1, "k") == ENGINE_KEY_ENOENT, "Expected miss.");
505     return SUCCESS;
506 }
507
508 static enum test_result test_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
509     item *i = NULL;
510     item_info info;
511     uint64_t vb_uuid = 0, high_seqno = 0;
512     const int num_sets = 5, num_keys = 4;
513
514     std::string key_arr[num_keys] = { "dummy_key",
515                                       "checkpoint_start",
516                                       "checkpoint_end",
517                                       "key" };
518
519
520     for (int k = 0; k < num_keys; k++) {
521         for (int j = 0; j < num_sets; j++) {
522             memset(&info, 0, sizeof(info));
523             vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
524             high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno",
525                                       "vbucket-seqno");
526
527             std::string err_str_store("Error setting " + key_arr[k]);
528             checkeq(ENGINE_SUCCESS,
529                     store(h, h1, NULL, OPERATION_SET, key_arr[k].c_str(),
530                           "somevalue", &i),
531                     err_str_store.c_str());
532             h1->release(h, NULL, i);
533
534             std::string err_str_get_item_info("Error getting " + key_arr[k]);
535             checkeq(true, get_item_info(h, h1, &info, key_arr[k].c_str()),
536                   err_str_get_item_info.c_str());
537
538             std::string err_str_vb_uuid("Expected valid vbucket uuid for " +
539                                         key_arr[k]);
540             checkeq(vb_uuid, info.vbucket_uuid, err_str_vb_uuid.c_str());
541
542             std::string err_str_seqno("Expected valid sequence number for " +
543                                         key_arr[k]);
544             checkeq(high_seqno + 1, info.seqno, err_str_seqno.c_str());
545         }
546     }
547
548     wait_for_flusher_to_settle(h, h1);
549     std::stringstream error1, error2;
550     error1 << "Expected ep_total_persisted >= num_keys (" << num_keys << ")";
551     error2 << "Expected ep_total_persisted <= num_sets*num_keys ("
552            << num_sets*num_keys << ")";
553
554     // The flusher could of ran > 1 times. We can only assert
555     // that we persisted between num_keys and upto num_keys*num_sets
556     check(get_int_stat(h, h1, "ep_total_persisted") >= num_keys,
557         error1.str().c_str());
558     check(get_int_stat(h, h1, "ep_total_persisted") <= num_sets*num_keys,
559         error2.str().c_str());
560
561     return SUCCESS;
562 }
563
564 struct handle_pair {
565     ENGINE_HANDLE *h;
566     ENGINE_HANDLE_V1 *h1;
567 };
568
569 extern "C" {
570     static void conc_del_set_thread(void *arg) {
571         struct handle_pair *hp = static_cast<handle_pair *>(arg);
572         item *it = NULL;
573
574         for (int i = 0; i < 5000; ++i) {
575             store(hp->h, hp->h1, NULL, OPERATION_ADD,
576                   "key", "somevalue", &it);
577             hp->h1->release(hp->h, NULL, it);
578             usleep(10);
579             checkeq(ENGINE_SUCCESS,
580                     store(hp->h, hp->h1, NULL, OPERATION_SET,
581                           "key", "somevalue", &it),
582                     "Error setting.");
583             hp->h1->release(hp->h, NULL, it);
584             usleep(10);
585             // Ignoring the result here -- we're racing.
586             del(hp->h, hp->h1, "key", 0, 0);
587             usleep(10);
588         }
589     }
590
591     static void conc_incr_thread(void *arg) {
592         struct handle_pair *hp = static_cast<handle_pair *>(arg);
593         uint64_t result = 0;
594
595         for (int i = 0; i < 10; i++) {
596             item *it = NULL;
597             check(hp->h1->arithmetic(hp->h, NULL, "key", 3, true, true, 1, 1, 0,
598                                      &it, PROTOCOL_BINARY_RAW_BYTES, &result,
599                                      0) == ENGINE_SUCCESS,
600                                      "Failed arithmetic operation");
601             hp->h1->release(hp->h, NULL, it);
602         }
603     }
604 }
605
606 static enum test_result test_conc_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
607
608     const int n_threads = 8;
609     cb_thread_t threads[n_threads];
610     struct handle_pair hp = {h, h1};
611
612     wait_for_persisted_value(h, h1, "key", "value1");
613
614     for (int i = 0; i < n_threads; i++) {
615         int r = cb_create_thread(&threads[i], conc_del_set_thread, &hp, 0);
616         cb_assert(r == 0);
617     }
618
619     for (int i = 0; i < n_threads; i++) {
620         int r = cb_join_thread(threads[i]);
621         cb_assert(r == 0);
622     }
623
624     wait_for_flusher_to_settle(h, h1);
625
626     testHarness.reload_engine(&h, &h1,
627                               testHarness.engine_path,
628                               testHarness.get_current_testcase()->cfg,
629                               true, false);
630     wait_for_warmup_complete(h, h1);
631
632     cb_assert(0 == get_int_stat(h, h1, "ep_warmed_dups"));
633
634     return SUCCESS;
635 }
636
637 static enum test_result test_conc_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
638     const int n_threads = 10;
639     cb_thread_t threads[n_threads];
640     struct handle_pair hp = {h, h1};
641     item *i = NULL;
642     check(store(h, h1, NULL, OPERATION_SET, "key", "0", &i) == ENGINE_SUCCESS,
643           "store failure");
644     h1->release(h, NULL, i);
645
646     for (int i = 0; i < n_threads; i++) {
647         int r = cb_create_thread(&threads[i], conc_incr_thread, &hp, 0);
648         cb_assert(r == 0);
649     }
650
651     for (int i = 0; i < n_threads; i++) {
652         int r = cb_join_thread(threads[i]);
653         cb_assert(r == 0);
654     }
655
656     check_key_value(h, h1, "key", "100", 3);
657
658     return SUCCESS;
659 }
660
661 static enum test_result test_conc_incr_new_itm (ENGINE_HANDLE *h,
662                                                 ENGINE_HANDLE_V1 *h1) {
663     const int n_threads = 10;
664     cb_thread_t threads[n_threads];
665     struct handle_pair hp = {h, h1};
666
667     for (int i = 0; i < n_threads; i++) {
668         int r = cb_create_thread(&threads[i], conc_incr_thread, &hp, 0);
669         cb_assert(r == 0);
670     }
671
672     for (int i = 0; i < n_threads; i++) {
673         int r = cb_join_thread(threads[i]);
674         cb_assert(r == 0);
675     }
676
677     check_key_value(h, h1, "key", "100", 3);
678
679     return SUCCESS;
680 }
681
682 struct multi_set_args {
683     ENGINE_HANDLE *h;
684     ENGINE_HANDLE_V1 *h1;
685     std::string prefix;
686     int count;
687 };
688
689 extern "C" {
690     static void multi_set_thread(void *arg) {
691         struct multi_set_args *msa = static_cast<multi_set_args *>(arg);
692
693         for (int i = 0; i < msa->count; i++) {
694             item *it = NULL;
695             std::stringstream s;
696             s << msa->prefix << i;
697             std::string key(s.str());
698             check(ENGINE_SUCCESS == store(msa->h, msa->h1, NULL, OPERATION_SET,
699                           key.c_str(), "somevalue", &it), "Set failure!");
700             msa->h1->release(msa->h, NULL, it);
701         }
702     }
703 }
704
705 static enum test_result test_multi_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
706
707     cb_thread_t thread1, thread2;
708     struct multi_set_args msa1, msa2;
709     msa1.h = h;
710     msa1.h1 = h1;
711     msa1.prefix = "ONE_";
712     msa1.count = 50000;
713     cb_assert(cb_create_thread(&thread1, multi_set_thread, &msa1, 0) == 0);
714
715     msa2.h = h;
716     msa2.h1 = h1;
717     msa2.prefix = "TWO_";
718     msa2.count = 50000;
719     cb_assert(cb_create_thread(&thread2, multi_set_thread, &msa2, 0) == 0);
720
721     cb_assert(cb_join_thread(thread1) == 0);
722     cb_assert(cb_join_thread(thread2) == 0);
723
724     wait_for_flusher_to_settle(h, h1);
725
726     check(get_int_stat(h, h1, "curr_items") == 100000,
727           "Mismatch in number of items inserted");
728     check(get_int_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno") == 100000,
729           "Unexpected high sequence number");
730
731     return SUCCESS;
732 }
733
734 static enum test_result test_set_get_hit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
735     item *i = NULL;
736     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
737           "store failure");
738     check_key_value(h, h1, "key", "somevalue", 9);
739     h1->release(h, NULL, i);
740     return SUCCESS;
741 }
742
743 static enum test_result test_set_get_hit_bin(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
744     char binaryData[] = "abcdefg\0gfedcba";
745     cb_assert(sizeof(binaryData) != strlen(binaryData));
746
747     item *i = NULL;
748     check(ENGINE_SUCCESS ==
749           storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
750                        binaryData, sizeof(binaryData), 82758, &i, 0, 0),
751           "Failed to set.");
752     h1->release(h, NULL, i);
753     check_key_value(h, h1, "key", binaryData, sizeof(binaryData));
754     return SUCCESS;
755 }
756
757 static enum test_result test_set_with_cas_non_existent(ENGINE_HANDLE *h,
758                                                        ENGINE_HANDLE_V1 *h1) {
759     const char *key = "test_expiry_flush";
760     item *i = NULL;
761
762     check(h1->allocate(h, NULL, &i, key, strlen(key), 10, 0, 0,
763           PROTOCOL_BINARY_RAW_BYTES) == ENGINE_SUCCESS, "Allocation failed.");
764
765     Item *it = reinterpret_cast<Item*>(i);
766     it->setCas(1234);
767
768     uint64_t cas = 0;
769     check(h1->store(h, NULL, i, &cas, OPERATION_SET, 0) == ENGINE_KEY_ENOENT,
770           "Expected not found");
771     h1->release(h, NULL, i);
772
773     return SUCCESS;
774 }
775
776 static enum test_result test_set_change_flags(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
777     item *i = NULL;
778     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
779           "Failed to set.");
780     h1->release(h, NULL, i);
781
782     item_info info;
783     uint32_t flags = 828258;
784     check(get_item_info(h, h1, &info, "key"), "Failed to get value.");
785     cb_assert(info.flags != flags);
786
787     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
788                        "newvalue", strlen("newvalue"), flags, &i, 0, 0) == ENGINE_SUCCESS,
789           "Failed to set again.");
790     h1->release(h, NULL, i);
791
792     check(get_item_info(h, h1, &info, "key"), "Failed to get value.");
793
794     return info.flags == flags ? SUCCESS : FAIL;
795 }
796
797 static enum test_result test_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
798     item *i = NULL;
799     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
800           "Failed to do initial set.");
801     h1->release(h, NULL, i);
802     check(store(h, h1, NULL, OPERATION_CAS, "key", "failcas", &i) != ENGINE_SUCCESS,
803           "Failed to fail initial CAS.");
804     h1->release(h, NULL, i);
805     check_key_value(h, h1, "key", "somevalue", 9);
806
807     check(h1->get(h, NULL, &i, "key", 3, 0) == ENGINE_SUCCESS,
808           "Failed to get value.");
809
810     item_info info;
811     info.nvalue = 1;
812     check(h1->get_item_info(h, NULL, i, &info), "Failed to get item info.");
813     h1->release(h, NULL, i);
814
815     check(store(h, h1, NULL, OPERATION_CAS, "key", "winCas", &i,
816                 info.cas) == ENGINE_SUCCESS,
817           "Failed to store CAS");
818     h1->release(h, NULL, i);
819     check_key_value(h, h1, "key", "winCas", 6);
820
821     uint64_t cval = 99999;
822     check(store(h, h1, NULL, OPERATION_CAS, "non-existing", "winCas", &i,
823                 cval) == ENGINE_KEY_ENOENT,
824           "CAS for non-existing key returned the wrong error code");
825     h1->release(h, NULL, i);
826     return SUCCESS;
827 }
828
829 static enum test_result test_add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
830     item *i = NULL;
831     item_info info;
832     uint64_t vb_uuid = 0;
833     uint32_t high_seqno = 0;
834
835     memset(&info, 0, sizeof(info));
836
837     vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
838     high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
839
840     check(store(h, h1, NULL, OPERATION_ADD,"key", "somevalue", &i) == ENGINE_SUCCESS,
841           "Failed to add value.");
842     h1->release(h, NULL, i);
843
844     check(get_item_info(h, h1, &info, "key"), "Error getting item info");
845     check(vb_uuid == info.vbucket_uuid, "Expected valid vbucket uuid");
846     check(high_seqno + 1 == info.seqno, "Expected valid sequence number");
847
848     check(store(h, h1, NULL, OPERATION_ADD,"key", "somevalue", &i) == ENGINE_NOT_STORED,
849           "Failed to fail to re-add value.");
850     h1->release(h, NULL, i);
851
852     // This aborts on failure.
853     check_key_value(h, h1, "key", "somevalue", 9);
854
855     // Expiration above was an hour, so let's go to The Future
856     testHarness.time_travel(3800);
857
858     check(store(h, h1, NULL, OPERATION_ADD,"key", "newvalue", &i) == ENGINE_SUCCESS,
859           "Failed to add value again.");
860
861     h1->release(h, NULL, i);
862     check_key_value(h, h1, "key", "newvalue", 8);
863     return SUCCESS;
864 }
865
866 static enum test_result test_add_add_with_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
867     item *i = NULL;
868     check(store(h, h1, NULL, OPERATION_ADD, "key",
869                 "somevalue", &i) == ENGINE_SUCCESS,
870           "Failed set.");
871     check_key_value(h, h1, "key", "somevalue", 9);
872     item_info info;
873     info.nvalue = 1;
874     info.nvalue = 1;
875     check(h1->get_item_info(h, NULL, i, &info) == true,
876           "Should be able to get info");
877
878     item *i2 = NULL;
879     ENGINE_ERROR_CODE ret;
880     check((ret = store(h, h1, NULL, OPERATION_ADD, "key",
881                        "somevalue", &i2, info.cas)) == ENGINE_KEY_EEXISTS,
882           "Should not be able to add the key two times");
883
884     h1->release(h, NULL, i);
885     h1->release(h, NULL, i2);
886     return SUCCESS;
887 }
888
889 static enum test_result test_replace(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
890     item *i = NULL;
891     item_info info;
892     uint64_t vb_uuid = 0;
893     uint32_t high_seqno = 0;
894
895     memset(&info, 0, sizeof(info));
896
897     check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue", &i) != ENGINE_SUCCESS,
898           "Failed to fail to replace non-existing value.");
899
900     h1->release(h, NULL, i);
901     check(store(h, h1, NULL, OPERATION_SET,"key", "somevalue", &i) == ENGINE_SUCCESS,
902           "Failed to set value.");
903     h1->release(h, NULL, i);
904
905     vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
906     high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
907
908     check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue", &i) == ENGINE_SUCCESS,
909           "Failed to replace existing value.");
910     h1->release(h, NULL, i);
911
912     check(get_item_info(h, h1, &info, "key"), "Error getting item info");
913
914     check(vb_uuid == info.vbucket_uuid, "Expected valid vbucket uuid");
915     check(high_seqno + 1 == info.seqno, "Expected valid sequence number");
916
917     check_key_value(h, h1, "key", "somevalue", 9);
918     return SUCCESS;
919 }
920
921 static enum test_result test_replace_with_eviction(ENGINE_HANDLE *h,
922                                                    ENGINE_HANDLE_V1 *h1) {
923     item *i = NULL;
924     check(store(h, h1, NULL, OPERATION_SET,"key", "somevalue", &i) == ENGINE_SUCCESS,
925           "Failed to set value.");
926     h1->release(h, NULL, i);
927     wait_for_flusher_to_settle(h, h1);
928     evict_key(h, h1, "key");
929     int numBgFetched = get_int_stat(h, h1, "ep_bg_fetched");
930
931     check(store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue1", &i) == ENGINE_SUCCESS,
932           "Failed to replace existing value.");
933
934     check(h1->get_stats(h, NULL, NULL, 0, add_stats) == ENGINE_SUCCESS,
935           "Failed to get stats.");
936     std::string eviction_policy = vals.find("ep_item_eviction_policy")->second;
937     if (eviction_policy == "full_eviction") {
938         numBgFetched++;
939     }
940
941     check(get_int_stat(h, h1, "ep_bg_fetched") == numBgFetched,
942           "Bg fetched value didn't match");
943
944     h1->release(h, NULL, i);
945     check_key_value(h, h1, "key", "somevalue1", 10);
946     return SUCCESS;
947 }
948
949 static enum test_result test_incr_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
950     uint64_t result = 0;
951     item *i = NULL;
952     h1->arithmetic(h, NULL, "key", 3, true, false, 1, 0, 0,
953                    &i, PROTOCOL_BINARY_RAW_BYTES, &result,
954                    0);
955     h1->release(h, NULL, i);
956     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected to not find key");
957     return SUCCESS;
958 }
959
960 static enum test_result test_incr_full_eviction(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
961     uint64_t result = 0;
962     item *i = NULL;
963     check(h1->arithmetic(h, NULL, "key", 3, true, true, 1, 1, 0,
964                    &i, PROTOCOL_BINARY_RAW_BYTES, &result,
965                    0) == ENGINE_SUCCESS,
966           "Failed arithmetic operation");
967     h1->release(h, NULL, i);
968     check(result == 1, "Failed to set initial value in arithmetic operation");
969     return SUCCESS;
970 }
971
972 static enum test_result test_incr_default(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
973     const void *cookie = testHarness.create_cookie();
974     testHarness.set_datatype_support(cookie, false);
975
976     uint64_t result = 0;
977     item *i = NULL;
978     check(h1->arithmetic(h, cookie, "key", 3, true, true, 1, 1, 0,
979                          &i, PROTOCOL_BINARY_RAW_BYTES, &result,
980                          0) == ENGINE_SUCCESS,
981           "Failed first arith");
982     h1->release(h, cookie, i);
983     check(result == 1, "Failed result verification.");
984
985     // Check datatype of counter
986     check(h1->get(h, cookie, &i, "key", 3, 0) == ENGINE_SUCCESS,
987             "Unable to get stored item");
988     item_info info;
989     info.nvalue = 1;
990     h1->get_item_info(h, cookie, i, &info);
991     h1->release(h, cookie, i);
992     check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
993
994     check(h1->arithmetic(h, cookie, "key", 3, true, false, 1, 1, 0,
995                          &i, PROTOCOL_BINARY_RAW_BYTES, &result,
996                          0) == ENGINE_SUCCESS,
997           "Failed second arith.");
998     h1->release(h, cookie, i);
999     check(result == 2, "Failed second result verification.");
1000
1001     check(h1->arithmetic(h, cookie, "key", 3, true, true, 1, 1, 0,
1002                          &i, PROTOCOL_BINARY_RAW_BYTES, &result,
1003                          0) == ENGINE_SUCCESS,
1004           "Failed third arith.");
1005     h1->release(h, cookie, i);
1006     check(result == 3, "Failed third result verification.");
1007
1008     check_key_value(h, h1, "key", "3", 1);
1009
1010     // Check datatype of counter
1011     check(h1->get(h, cookie, &i, "key", 3, 0) == ENGINE_SUCCESS,
1012             "Unable to get stored item");
1013     info.nvalue = 1;
1014     h1->get_item_info(h, cookie, i, &info);
1015     h1->release(h, cookie, i);
1016     check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
1017
1018     testHarness.destroy_cookie(cookie);
1019     return SUCCESS;
1020 }
1021
1022 static enum test_result test_append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1023     item *i = NULL;
1024     item_info info;
1025     uint64_t vb_uuid = 0;
1026     uint32_t high_seqno = 0;
1027
1028     memset(&info, 0, sizeof(info));
1029
1030     // MB-11332: append on non-existing key should return NOT_STORED
1031     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1032                        "foo\r\n", 5, 82758, &i, 0, 0)
1033           == ENGINE_NOT_STORED,
1034           "MB-11332: Failed append.");
1035     h1->release(h, NULL, i);
1036
1037     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1038                        "\r\n", 2, 82758, &i, 0, 0)
1039           == ENGINE_SUCCESS,
1040           "Failed set.");
1041
1042     h1->release(h, NULL, i);
1043
1044     vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
1045     high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
1046
1047     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1048                        "foo\r\n", 5, 82758, &i, 0, 0)
1049           == ENGINE_SUCCESS,
1050           "Failed append.");
1051     h1->release(h, NULL, i);
1052
1053     check(get_item_info(h, h1, &info, "key"), "Error in getting item info");
1054
1055     check(vb_uuid == info.vbucket_uuid, "Expected valid vbucket uuid");
1056     check(high_seqno + 1 == info.seqno, "Expected valid sequence number");
1057
1058     check_key_value(h, h1, "key", "\r\nfoo\r\n", 7);
1059
1060     char binaryData1[] = "abcdefg\0gfedcba\r\n";
1061     char binaryData2[] = "abzdefg\0gfedcba\r\n";
1062     size_t dataSize = 20*1024*1024;
1063     char *bigBinaryData3 = new char[dataSize];
1064     memset(bigBinaryData3, '\0', dataSize);
1065
1066     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1067                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
1068           == ENGINE_SUCCESS,
1069           "Failed set.");
1070     h1->release(h, NULL, i);
1071
1072     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1073                        bigBinaryData3, dataSize, 82758, &i, 0, 0)
1074           == ENGINE_E2BIG,
1075           "Expected append failure.");
1076     h1->release(h, NULL, i);
1077     delete[] bigBinaryData3;
1078
1079     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key",
1080                        binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
1081           == ENGINE_SUCCESS,
1082           "Failed append.");
1083     h1->release(h, NULL, i);
1084
1085     std::string expected;
1086     expected.append(binaryData1, sizeof(binaryData1) - 1);
1087     expected.append(binaryData2, sizeof(binaryData2) - 1);
1088
1089     check_key_value(h, h1, "key", expected.data(), expected.length());
1090     return SUCCESS;
1091 }
1092
1093 static enum test_result test_prepend(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1094     item *i = NULL;
1095     item_info info;
1096     uint64_t vb_uuid = 0;
1097     uint32_t high_seqno = 0;
1098
1099     memset(&info, 0, sizeof(info));
1100
1101     // MB-11332: prepend on non-existing key should return NOT_STORED
1102     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1103                        "foo\r\n", 5, 82758, &i, 0, 0)
1104           == ENGINE_NOT_STORED,
1105           "MB-11332: Failed prepend.");
1106     h1->release(h, NULL, i);
1107
1108     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1109                        "\r\n", 2, 82758, &i, 0, 0)
1110           == ENGINE_SUCCESS,
1111           "Failed set.");
1112     h1->release(h, NULL, i);
1113
1114     vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
1115     high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
1116
1117     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1118                        "foo\r\n", 5, 82758, &i, 0, 0)
1119           == ENGINE_SUCCESS,
1120           "Failed prepend.");
1121     h1->release(h, NULL, i);
1122
1123     check(get_item_info(h, h1, &info, "key"), "Error getting item info");
1124     check(vb_uuid == info.vbucket_uuid, "Expected valid vbucket uuid");
1125     check(high_seqno + 1 == info.seqno, "Expected valid sequence number");
1126
1127     check_key_value(h, h1, "key", "foo\r\n\r\n", 7);
1128
1129     char binaryData1[] = "abcdefg\0gfedcba\r\n";
1130     char binaryData2[] = "abzdefg\0gfedcba\r\n";
1131     size_t dataSize = 20*1024*1024;
1132     char *bigBinaryData3 = new char[dataSize];
1133     memset(bigBinaryData3, '\0', dataSize);
1134
1135     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
1136                        binaryData1, sizeof(binaryData1) - 1, 82758, &i, 0, 0)
1137           == ENGINE_SUCCESS,
1138           "Failed set.");
1139     h1->release(h, NULL, i);
1140
1141     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1142                        bigBinaryData3, dataSize, 82758, &i, 0, 0)
1143           == ENGINE_E2BIG,
1144           "Expected prepend failure.");
1145     h1->release(h, NULL, i);
1146     delete[] bigBinaryData3;
1147
1148     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key",
1149                        binaryData2, sizeof(binaryData2) - 1, 82758, &i, 0, 0)
1150           == ENGINE_SUCCESS,
1151           "Failed append.");
1152     h1->release(h, NULL, i);
1153
1154     std::string expected;
1155     expected.append(binaryData2, sizeof(binaryData2) - 1);
1156     expected.append(binaryData1, sizeof(binaryData1) - 1);
1157
1158     check_key_value(h, h1, "key", expected.data(), expected.length());
1159     return SUCCESS;
1160 }
1161
1162 static enum test_result test_append_compressed(ENGINE_HANDLE *h,
1163                                                ENGINE_HANDLE_V1 *h1) {
1164
1165     item *i = NULL;
1166
1167     size_t len = snappy_max_compressed_length(2);
1168     char *newBuf = (char *) malloc (len);
1169     snappy_compress("\r\n", 2, newBuf, &len);
1170     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key1",
1171                        (const char *)newBuf, len, 82758, &i, 0, 0, 3600,
1172                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1173           == ENGINE_SUCCESS, "Failed set.");
1174     h1->release(h, NULL, i);
1175     free (newBuf);
1176
1177     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key1",
1178                        "foo\r\n", 5, 82758, &i, 0, 0)
1179           == ENGINE_SUCCESS,
1180           "Failed append uncompressed to compressed.");
1181     h1->release(h, NULL, i);
1182
1183     size_t len1 = snappy_max_compressed_length(7);
1184     char *newBuf1 = (char *) malloc (len1);
1185     snappy_compress("\r\nfoo\r\n", 7, newBuf1, &len1);
1186
1187     item_info info;
1188     check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
1189     check(info.nvalue == 1, "info.nvalue != 1");
1190     check(len1 == info.value[0].iov_len, "Value length mismatch");
1191     check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
1192     check(info.datatype == 0x02, "Datatype mismatch");
1193     free (newBuf1);
1194
1195     len = snappy_max_compressed_length(3);
1196     newBuf = (char *) malloc (len);
1197     snappy_compress("bar", 3, newBuf, &len);
1198     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key1",
1199                        (const char*)newBuf, len, 82758, &i, 0, 0, 3600,
1200                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1201             == ENGINE_SUCCESS,
1202             "Failed append compressed to compressed.");
1203     h1->release(h, NULL, i);
1204     free (newBuf);
1205
1206     len1 = snappy_max_compressed_length(10);
1207     newBuf1 = (char *) malloc (len1);
1208     snappy_compress("\r\nfoo\r\nbar", 10, newBuf1, &len1);
1209
1210     check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
1211     check(info.nvalue == 1, "info.nvalue != 1");
1212     check(len1 == info.value[0].iov_len, "Value length mismatch");
1213     check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
1214     check(info.datatype == 0x02, "Datatype mismatch");
1215     free (newBuf1);
1216
1217     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key2",
1218                        "foo", 3, 82758, &i, 0, 0, 3600,
1219                        PROTOCOL_BINARY_RAW_BYTES)
1220           == ENGINE_SUCCESS, "Failed set.");
1221     h1->release(h, NULL, i);
1222
1223     len = snappy_max_compressed_length(3);
1224     newBuf = (char *) malloc (len);
1225     snappy_compress("bar", 3, newBuf, &len);
1226     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, "key2",
1227                        newBuf, len, 82758, &i, 0, 0, 3600,
1228                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1229             == ENGINE_SUCCESS,
1230             "Failed append compressed to uncompressed.");
1231     h1->release(h, NULL, i);
1232     free (newBuf);
1233
1234     check(get_item_info(h, h1, &info, "key2", 0), "checking key and value");
1235     check(info.nvalue == 1, "info.nvalue != 1");
1236     check(info.value[0].iov_len == 6, "Value length mismatch");
1237     check(memcmp(info.value[0].iov_base, "foobar", 6) == 0, "Data mismatch");
1238     check(info.datatype == 0x00, "Datatype mismatch");
1239
1240     return SUCCESS;
1241 }
1242
1243 static enum test_result test_prepend_compressed(ENGINE_HANDLE *h,
1244                                                ENGINE_HANDLE_V1 *h1) {
1245
1246     item *i = NULL;
1247
1248     size_t len = snappy_max_compressed_length(2);
1249     char *newBuf = (char *) malloc (len);
1250     snappy_compress("\r\n", 2, newBuf, &len);
1251     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key1",
1252                        (const char *)newBuf, len, 82758, &i, 0, 0, 3600,
1253                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1254           == ENGINE_SUCCESS, "Failed set.");
1255     h1->release(h, NULL, i);
1256     free (newBuf);
1257
1258     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key1",
1259                        "foo\r\n", 5, 82758, &i, 0, 0)
1260           == ENGINE_SUCCESS,
1261           "Failed prepend uncompressed to compressed.");
1262     h1->release(h, NULL, i);
1263
1264     size_t len1 = snappy_max_compressed_length(7);
1265     char *newBuf1 = (char *) malloc (len1);
1266     snappy_compress("foo\r\n\r\n", 7, newBuf1, &len1);
1267
1268     item_info info;
1269     check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
1270     check(info.nvalue == 1, "info.nvalue != 1");
1271     check(len1 == info.value[0].iov_len, "Value length mismatch");
1272     check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
1273     check(info.datatype == 0x02, "Datatype mismatch");
1274     free (newBuf1);
1275
1276     len = snappy_max_compressed_length(3);
1277     newBuf = (char *) malloc (len);
1278     snappy_compress("bar", 3, newBuf, &len);
1279     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key1",
1280                        (const char*)newBuf, len, 82758, &i, 0, 0, 3600,
1281                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1282             == ENGINE_SUCCESS,
1283             "Failed prepend compressed to compressed.");
1284     h1->release(h, NULL, i);
1285     free (newBuf);
1286
1287     len1 = snappy_max_compressed_length(10);
1288     newBuf1 = (char *) malloc (len1);
1289     snappy_compress("barfoo\r\n\r\n", 10, newBuf1, &len1);
1290
1291     check(get_item_info(h, h1, &info, "key1", 0), "checking key and value");
1292     check(info.nvalue == 1, "info.nvalue != 1");
1293     check(len1 == info.value[0].iov_len, "Value length mismatch");
1294     check(memcmp(info.value[0].iov_base, newBuf1, len1) == 0, "Data mismatch");
1295     check(info.datatype == 0x02, "Datatype mismatch");
1296     free (newBuf1);
1297
1298     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key2",
1299                        "foo", 3, 82758, &i, 0, 0, 3600,
1300                        PROTOCOL_BINARY_RAW_BYTES)
1301           == ENGINE_SUCCESS, "Failed set.");
1302     h1->release(h, NULL, i);
1303
1304     len = snappy_max_compressed_length(3);
1305     newBuf = (char *) malloc (len);
1306     snappy_compress("bar", 3, newBuf, &len);
1307     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, "key2",
1308                        newBuf, len, 82758, &i, 0, 0, 3600,
1309                        PROTOCOL_BINARY_DATATYPE_COMPRESSED)
1310             == ENGINE_SUCCESS,
1311             "Failed prepend compressed to uncompressed.");
1312     h1->release(h, NULL, i);
1313     free (newBuf);
1314
1315     check(get_item_info(h, h1, &info, "key2", 0), "checking key and value");
1316     check(info.nvalue == 1, "info.nvalue != 1");
1317     check(info.value[0].iov_len == 6, "Value length mismatch");
1318     check(memcmp(info.value[0].iov_base, "barfoo", 6) == 0, "Data mismatch");
1319     check(info.datatype == 0x00, "Datatype mismatch");
1320
1321     return SUCCESS;
1322 }
1323
1324 static enum test_result test_append_prepend_to_json(ENGINE_HANDLE *h,
1325                                                     ENGINE_HANDLE_V1 *h1) {
1326     item *i = NULL;
1327     item_info info;
1328
1329     const char* key1 = "foo1";
1330     const char* key2 = "foo2";
1331     const char* value1 = "{\"foo1\":\"bar1\"}";
1332     const char* value2 = "{\"foo2\":\"bar2\"}";
1333
1334     // APPEND
1335     check(storeCasVb11(h, h1, NULL, OPERATION_SET, key1,
1336                        value1, strlen(value1), 82758, &i, 0, 0,
1337                        3600, PROTOCOL_BINARY_DATATYPE_JSON)
1338           == ENGINE_SUCCESS, "Failed set.");
1339     h1->release(h, NULL, i);
1340
1341     check(h1->get(h, NULL, &i, key1, strlen(key1), 0) == ENGINE_SUCCESS,
1342             "Unable to get stored item");
1343     info.nvalue = 1;
1344     h1->get_item_info(h, NULL, i, &info);
1345     check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1346                         (int)info.value[0].iov_len) == 1, "Expected JSON");
1347     check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
1348     h1->release(h, NULL, i);
1349
1350     check(storeCasVb11(h, h1, NULL, OPERATION_APPEND, key1,
1351                        value2, strlen(value2), 82758, &i, 0, 0)
1352           == ENGINE_SUCCESS,
1353           "Failed append.");
1354     h1->release(h, NULL, i);
1355
1356     check(h1->get(h, NULL, &i, key1, strlen(key1), 0) == ENGINE_SUCCESS,
1357             "Unable to get stored item");
1358     info.nvalue = 1;
1359     h1->get_item_info(h, NULL, i, &info);
1360     check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1361                         (int)info.value[0].iov_len) == 0, "Expected Binary");
1362     check(info.datatype == PROTOCOL_BINARY_RAW_BYTES,
1363                 "Invalid datatype after append");
1364     h1->release(h, NULL, i);
1365
1366     // PREPEND
1367     check(storeCasVb11(h, h1, NULL, OPERATION_SET, key2,
1368                        value1, strlen(value1), 82758, &i, 0, 0,
1369                        3600, PROTOCOL_BINARY_DATATYPE_JSON)
1370           == ENGINE_SUCCESS, "Failed set.");
1371     h1->release(h, NULL, i);
1372
1373     check(h1->get(h, NULL, &i, key2, strlen(key2), 0) == ENGINE_SUCCESS,
1374             "Unable to get stored item");
1375     info.nvalue = 1;
1376     h1->get_item_info(h, NULL, i, &info);
1377     check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1378                         (int)info.value[0].iov_len) == 1, "Expected JSON");
1379     check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
1380     h1->release(h, NULL, i);
1381
1382     check(storeCasVb11(h, h1, NULL, OPERATION_PREPEND, key2,
1383                        value2, strlen(value2), 82758, &i, 0, 0)
1384           == ENGINE_SUCCESS,
1385           "Failed prepend.");
1386     h1->release(h, NULL, i);
1387
1388     check(h1->get(h, NULL, &i, key2, strlen(key2), 0) == ENGINE_SUCCESS,
1389             "Unable to get stored item");
1390     info.nvalue = 1;
1391     h1->get_item_info(h, NULL, i, &info);
1392     check(checkUTF8JSON((const unsigned char*)info.value[0].iov_base,
1393                         (int)info.value[0].iov_len) == 0, "Expected Binary");
1394     check(info.datatype == PROTOCOL_BINARY_RAW_BYTES,
1395                 "Invalid datatype after prepend");
1396     h1->release(h, NULL, i);
1397
1398     return SUCCESS;
1399 }
1400
1401 static enum test_result test_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1402     const void *cookie = testHarness.create_cookie();
1403     testHarness.set_datatype_support(cookie, true);
1404
1405     uint64_t result = 0;
1406     item *i = NULL;
1407     const char *key = "key";
1408     const char *val = "1";
1409     check(store(h, h1, NULL, OPERATION_ADD,key, val, &i,
1410                 0, 0, 3600,
1411                 checkUTF8JSON((const unsigned char *)val, 1))
1412             == ENGINE_SUCCESS,
1413           "Failed to add value.");
1414     h1->release(h, NULL, i);
1415
1416     check(h1->arithmetic(h, NULL, key, 3, true, false, 1, 1, 0,
1417                          &i, PROTOCOL_BINARY_RAW_BYTES, &result,
1418                          0) == ENGINE_SUCCESS,
1419           "Failed to incr value.");
1420     h1->release(h, NULL, i);
1421
1422     check_key_value(h, h1, key, "2", 1);
1423
1424     // Check datatype of counter
1425     check(h1->get(h, cookie, &i, key, 3, 0) == ENGINE_SUCCESS,
1426             "Unable to get stored item");
1427     item_info info;
1428     info.nvalue = 1;
1429     h1->get_item_info(h, cookie, i, &info);
1430     h1->release(h, cookie, i);
1431     check(info.datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Invalid datatype");
1432
1433     testHarness.destroy_cookie(cookie);
1434
1435     return SUCCESS;
1436 }
1437
1438 static enum test_result test_bug2799(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1439     uint64_t result = 0;
1440     item *i = NULL;
1441     check(store(h, h1, NULL, OPERATION_ADD, "key", "1", &i) == ENGINE_SUCCESS,
1442           "Failed to add value.");
1443     h1->release(h, NULL, i);
1444
1445     check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
1446                          &i, PROTOCOL_BINARY_RAW_BYTES, &result,
1447                          0) == ENGINE_SUCCESS,
1448           "Failed to incr value.");
1449     h1->release(h, NULL, i);
1450
1451     check_key_value(h, h1, "key", "2", 1);
1452
1453     testHarness.time_travel(3617);
1454
1455     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1456     return SUCCESS;
1457 }
1458
1459 static enum test_result test_flush(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1460     item *i = NULL;
1461
1462     if (get_int_stat(h, h1, "ep_flushall_enabled") == 0) {
1463         check(set_param(h, h1, protocol_binary_engine_param_flush,
1464                     "flushall_enabled", "true"),
1465                 "Set flushall_enabled should have worked");
1466     }
1467     check(get_int_stat(h, h1, "ep_flushall_enabled") == 1,
1468             "flushall wasn't enabled");
1469
1470     // First try to delete something we know to not be there.
1471     check(del(h, h1, "key", 0, 0) == ENGINE_KEY_ENOENT, "Failed to fail initial delete.");
1472     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1473           "Failed set.");
1474     h1->release(h, NULL, i);
1475     check_key_value(h, h1, "key", "somevalue", 9);
1476
1477     set_degraded_mode(h, h1, NULL, true);
1478     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1479           "Failed to flush");
1480     set_degraded_mode(h, h1, NULL, false);
1481
1482     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1483
1484     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1485           "Failed post-flush set.");
1486     h1->release(h, NULL, i);
1487     check_key_value(h, h1, "key", "somevalue", 9);
1488
1489     return SUCCESS;
1490 }
1491
1492 /**
1493  * The following struct: flush_args and function run_flush(),
1494  * will be used by the test that follows: test_multiple_flush
1495  */
1496 struct flush_args {
1497     ENGINE_HANDLE *h;
1498     ENGINE_HANDLE_V1 *h1;
1499     ENGINE_ERROR_CODE expect;
1500     int when;
1501 };
1502
1503 extern "C" {
1504     static void run_flush_all(void *arguments) {
1505         const void *cookie = testHarness.create_cookie();
1506         testHarness.set_ewouldblock_handling(cookie, true);
1507         struct flush_args *args = (struct flush_args *)arguments;
1508
1509         check((args->h1)->flush(args->h, cookie, args->when) == args->expect,
1510                 "Return code is not what is expected");
1511
1512         testHarness.destroy_cookie(cookie);
1513     }
1514 }
1515
1516 static enum test_result test_multiple_flush(ENGINE_HANDLE *h,
1517                                             ENGINE_HANDLE_V1 *h1) {
1518
1519     if (get_int_stat(h, h1, "ep_flushall_enabled") == 0) {
1520         check(set_param(h, h1, protocol_binary_engine_param_flush,
1521                     "flushall_enabled", "true"),
1522                 "Set flushall_enabled should have worked");
1523     }
1524     check(get_int_stat(h, h1, "ep_flushall_enabled") == 1,
1525             "flushall wasn't enabled");
1526
1527     item *i = NULL;
1528     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1529           "Failed set.");
1530     h1->release(h, NULL, i);
1531     wait_for_flusher_to_settle(h, h1);
1532     check(get_int_stat(h, h1, "curr_items") == 1,
1533           "Expected curr_items equals 1");
1534
1535     set_degraded_mode(h, h1, NULL, true);
1536     cb_thread_t t1, t2;
1537     struct flush_args args1,args2;
1538     args1.h = h;
1539     args1.h1 = h1;
1540     args1.expect = ENGINE_SUCCESS;
1541     args1.when = 2;
1542     check(cb_create_thread(&t1, run_flush_all, &args1, 0) == 0,
1543             "cb_create_thread failed!");
1544
1545     sleep(1);
1546
1547     args2.h = h;
1548     args2.h1 = h1;
1549     args2.expect = ENGINE_TMPFAIL;
1550     args2.when = 0;
1551     check(cb_create_thread(&t2, run_flush_all, &args2, 0) == 0,
1552             "cb_create_thread failed!");
1553
1554     cb_assert(cb_join_thread(t1) == 0);
1555     cb_assert(cb_join_thread(t2) == 0);
1556
1557     set_degraded_mode(h, h1, NULL, false);
1558
1559     testHarness.reload_engine(&h, &h1,
1560                               testHarness.engine_path,
1561                               testHarness.get_current_testcase()->cfg,
1562                               true, false);
1563     wait_for_warmup_complete(h, h1);
1564     check(get_int_stat(h, h1, "curr_items") == 0,
1565           "Expected curr_items equals 0");
1566
1567     return SUCCESS;
1568 }
1569
1570 static enum test_result test_flush_disabled(ENGINE_HANDLE *h,
1571                                             ENGINE_HANDLE_V1 *h1) {
1572     item *i = NULL;
1573     // start an engine with disabled flush, the flush() should be noop and
1574     // we expect to see the key after flush()
1575
1576     // store a key and check its existence
1577     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1578           "Failed set.");
1579     h1->release(h, NULL, i);
1580     check_key_value(h, h1, "key", "somevalue", 9);
1581     // expect error msg engine does not support operation
1582     check(h1->flush(h, NULL, 0) == ENGINE_ENOTSUP, "Flush should be disabled");
1583     //check the key
1584     check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1585
1586     // restart engine with flush enabled and redo the test, we expect flush to succeed
1587     std::string param = "flushall_enabled=false";
1588     std::string config = testHarness.get_current_testcase()->cfg;
1589     size_t found = config.find(param);
1590     if(found != config.npos) {
1591         config.replace(found, param.size(), "flushall_enabled=true");
1592     }
1593     testHarness.reload_engine(&h, &h1,
1594                               testHarness.engine_path,
1595                               config.c_str(),
1596                               true, false);
1597     wait_for_warmup_complete(h, h1);
1598
1599
1600     set_degraded_mode(h, h1, NULL, true);
1601     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS, "Flush should be enabled");
1602     set_degraded_mode(h, h1, NULL, false);
1603
1604     //expect missing key
1605     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1606
1607     return SUCCESS;
1608 }
1609
1610 static enum test_result test_flush_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1611     item *i = NULL;
1612     int overhead = get_int_stat(h, h1, "ep_overhead");
1613     int cacheSize = get_int_stat(h, h1, "ep_total_cache_size");
1614     int nonResident = get_int_stat(h, h1, "ep_num_non_resident");
1615
1616     int itemsRemoved = get_int_stat(h, h1, "ep_items_rm_from_checkpoints");
1617     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1618           "Failed set.");
1619     h1->release(h, NULL, i);
1620     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i) == ENGINE_SUCCESS,
1621           "Failed set.");
1622     h1->release(h, NULL, i);
1623     testHarness.time_travel(65);
1624     wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
1625
1626     check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1627     check(ENGINE_SUCCESS == verify_key(h, h1, "key2"), "Expected key2");
1628
1629     check_key_value(h, h1, "key", "somevalue", 9);
1630     check_key_value(h, h1, "key2", "somevalue", 9);
1631
1632     int overhead2 = get_int_stat(h, h1, "ep_overhead");
1633     int cacheSize2 = get_int_stat(h, h1, "ep_total_cache_size");
1634
1635     set_degraded_mode(h, h1, NULL, true);
1636     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS, "Failed to flush");
1637     set_degraded_mode(h, h1, NULL, false);
1638     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1639     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key2"), "Expected missing key");
1640
1641     wait_for_flusher_to_settle(h, h1);
1642
1643     overhead2 = get_int_stat(h, h1, "ep_overhead");
1644     cacheSize2 = get_int_stat(h, h1, "ep_total_cache_size");
1645     int nonResident2 = get_int_stat(h, h1, "ep_num_non_resident");
1646
1647     cb_assert(overhead2 == overhead);
1648     cb_assert(nonResident2 == nonResident);
1649     cb_assert(cacheSize2 == cacheSize);
1650
1651     return SUCCESS;
1652 }
1653
1654 static enum test_result test_flush_multiv(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1655     item *i = NULL;
1656     check(set_vbucket_state(h, h1, 2, vbucket_state_active), "Failed to set vbucket state.");
1657     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1658           "Failed set.");
1659     h1->release(h, NULL, i);
1660     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i,
1661                 0, 2) == ENGINE_SUCCESS,
1662           "Failed set in vb2.");
1663     h1->release(h, NULL, i);
1664
1665     check(ENGINE_SUCCESS == verify_key(h, h1, "key"), "Expected key");
1666     check(ENGINE_SUCCESS == verify_key(h, h1, "key2", 2), "Expected key2");
1667
1668     check_key_value(h, h1, "key", "somevalue", 9);
1669     check_key_value(h, h1, "key2", "somevalue", 9, 2);
1670
1671     set_degraded_mode(h, h1, NULL, true);
1672     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS, "Failed to flush");
1673     set_degraded_mode(h, h1, NULL, false);
1674
1675     vals.clear();
1676     check(h1->get_stats(h, NULL, NULL, 0, add_stats) == ENGINE_SUCCESS,
1677           "Failed to get stats.");
1678     check(vals.find("ep_flush_all") != vals.end(), "Failed to get the status of flush_all");
1679
1680     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1681     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key2", 2), "Expected missing key");
1682
1683     return SUCCESS;
1684 }
1685
1686 static int checkCurrItemsAfterShutdown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
1687                                        int numItems2Load, bool shutdownForce) {
1688     std::vector<std::string> keys;
1689     for (int index = 0; index < numItems2Load; ++index) {
1690         std::stringstream s;
1691         s << "keys_2_load-" << index;
1692         std::string key(s.str());
1693         keys.push_back(key);
1694     }
1695
1696     check(get_int_stat(h, h1, "ep_total_persisted") == 0,
1697           "Expected ep_total_persisted equals 0");
1698     check(get_int_stat(h, h1, "curr_items") == 0,
1699           "Expected curr_items equals 0");
1700
1701     // stop flusher before loading new items
1702     protocol_binary_request_header *pkt = createPacket(PROTOCOL_BINARY_CMD_STOP_PERSISTENCE);
1703     check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
1704           "CMD_STOP_PERSISTENCE failed!");
1705     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
1706           "Failed to stop persistence!");
1707     free(pkt);
1708
1709     std::vector<std::string>::iterator itr;
1710     for (itr = keys.begin(); itr != keys.end(); ++itr) {
1711         item *i;
1712         check(store(h, h1, NULL, OPERATION_SET, itr->c_str(), "oracle", &i, 0, 0)
1713               == ENGINE_SUCCESS, "Failed to store a value");
1714         h1->release(h, NULL, i);
1715     }
1716
1717     check(get_int_stat(h, h1, "ep_total_persisted") == 0,
1718           "Incorrect ep_total_persisted, expected 0");
1719     std::stringstream ss;
1720     ss << "Incorrect curr_items, expected " << numItems2Load;
1721     std::string errmsg(ss.str());
1722     check(get_int_stat(h, h1, "curr_items") == numItems2Load,
1723           errmsg.c_str());
1724
1725     // resume flusher before shutdown + warmup
1726     pkt = createPacket(PROTOCOL_BINARY_CMD_START_PERSISTENCE);
1727     check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
1728           "CMD_START_PERSISTENCE failed!");
1729     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
1730           "Failed to start persistence!");
1731     free(pkt);
1732
1733     // shutdown engine force and restart
1734     testHarness.reload_engine(&h, &h1,
1735                               testHarness.engine_path,
1736                               testHarness.get_current_testcase()->cfg,
1737                               true, shutdownForce);
1738     wait_for_warmup_complete(h, h1);
1739     return get_int_stat(h, h1, "curr_items");
1740 }
1741
1742 static enum test_result test_flush_shutdown_force(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1743     int numItems2load = 3000;
1744     bool shutdownForce = true;
1745     int currItems = checkCurrItemsAfterShutdown(h, h1, numItems2load, shutdownForce);
1746     check (currItems <= numItems2load,
1747            "Number of curr items should be <= 3000, unless previous "
1748            "shutdown force had to wait for the flusher");
1749     return SUCCESS;
1750 }
1751
1752 static enum test_result test_flush_shutdown_noforce(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1753     int numItems2load = 3000;
1754     bool shutdownForce = false;
1755     int currItems = checkCurrItemsAfterShutdown(h, h1, numItems2load, shutdownForce);
1756     check (currItems == numItems2load,
1757            "Number of curr items should be equal to 3000, unless previous "
1758            "shutdown did not wait for the flusher");
1759     return SUCCESS;
1760 }
1761
1762 static enum test_result test_flush_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1763     item *i = NULL;
1764     // First try to delete something we know to not be there.
1765     check(del(h, h1, "key", 0, 0) == ENGINE_KEY_ENOENT, "Failed to fail initial delete.");
1766     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1767           "Failed set.");
1768     h1->release(h, NULL, i);
1769     check_key_value(h, h1, "key", "somevalue", 9);
1770
1771     // Restart once to ensure written to disk.
1772     testHarness.reload_engine(&h, &h1,
1773                               testHarness.engine_path,
1774                               testHarness.get_current_testcase()->cfg,
1775                               true, false);
1776     wait_for_warmup_complete(h, h1);
1777
1778     // Read value from disk.
1779     check_key_value(h, h1, "key", "somevalue", 9);
1780
1781     // Flush
1782     set_degraded_mode(h, h1, NULL, true);
1783     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1784           "Failed to flush");
1785     set_degraded_mode(h, h1, NULL, false);
1786
1787     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i) == ENGINE_SUCCESS,
1788           "Failed post-flush set.");
1789     h1->release(h, NULL, i);
1790     check_key_value(h, h1, "key2", "somevalue", 9);
1791
1792     // Restart again, ensure written to disk.
1793     testHarness.reload_engine(&h, &h1,
1794                               testHarness.engine_path,
1795                               testHarness.get_current_testcase()->cfg,
1796                               true, false);
1797     wait_for_warmup_complete(h, h1);
1798
1799     check(store(h, h1, NULL, OPERATION_SET, "key3", "somevalue", &i) == ENGINE_SUCCESS,
1800           "Failed post-flush, post-restart set.");
1801     h1->release(h, NULL, i);
1802     check_key_value(h, h1, "key3", "somevalue", 9);
1803
1804     // Read value again, should not be there.
1805     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1806     return SUCCESS;
1807 }
1808
1809 static enum test_result test_flush_multiv_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1810     item *i = NULL;
1811     check(set_vbucket_state(h, h1, 2, vbucket_state_active), "Failed to set vbucket state.");
1812     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1813           "Failed set.");
1814     h1->release(h, NULL, i);
1815     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i,
1816                 0, 2) == ENGINE_SUCCESS,
1817           "Failed set in vb2.");
1818     h1->release(h, NULL, i);
1819
1820     // Restart once to ensure written to disk.
1821     testHarness.reload_engine(&h, &h1,
1822                               testHarness.engine_path,
1823                               testHarness.get_current_testcase()->cfg,
1824                               true, false);
1825     wait_for_warmup_complete(h, h1);
1826
1827     // Read value from disk.
1828     check_key_value(h, h1, "key", "somevalue", 9);
1829
1830     // Flush
1831     set_degraded_mode(h, h1, NULL, true);
1832     check(h1->flush(h, NULL, 0) == ENGINE_SUCCESS,
1833           "Failed to flush");
1834     set_degraded_mode(h, h1, NULL, false);
1835
1836     // Restart again, ensure written to disk.
1837     testHarness.reload_engine(&h, &h1,
1838                               testHarness.engine_path,
1839                               testHarness.get_current_testcase()->cfg,
1840                               true, false);
1841     wait_for_warmup_complete(h, h1);
1842
1843     // Read value again, should not be there.
1844     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1845     check(verify_vbucket_missing(h, h1, 2), "Bucket 2 came back.");
1846     return SUCCESS;
1847 }
1848
1849 static enum test_result test_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1850     item *i = NULL;
1851     // First try to delete something we know to not be there.
1852     check(del(h, h1, "key", 0, 0) == ENGINE_KEY_ENOENT, "Failed to fail initial delete.");
1853     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i) == ENGINE_SUCCESS,
1854           "Failed set.");
1855     Item *it = reinterpret_cast<Item*>(i);
1856     uint64_t orig_cas = it->getCas();
1857     h1->release(h, NULL, i);
1858     check_key_value(h, h1, "key", "somevalue", 9);
1859
1860     uint64_t cas = 0;
1861     uint64_t vb_uuid = 0;
1862     mutation_descr_t mut_info;
1863     uint32_t high_seqno = 0;
1864
1865     memset(&mut_info, 0, sizeof(mut_info));
1866
1867     vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
1868     high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
1869     check(h1->remove(h, NULL, "key", 3, &cas, 0, &mut_info) == ENGINE_SUCCESS,
1870           "Failed remove with value.");
1871     check(orig_cas + 1 == cas, "Cas mismatch on delete");
1872     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
1873     check(vb_uuid == mut_info.vbucket_uuid, "Expected valid vbucket uuid");
1874     check(high_seqno + 1 == mut_info.seqno, "Expected valid sequence number");
1875
1876     // Can I time travel to an expired object and delete it?
1877     checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1878             "Failed set.");
1879     h1->release(h, NULL, i);
1880     testHarness.time_travel(3617);
1881     checkeq(ENGINE_KEY_ENOENT, del(h, h1, "key", 0, 0),
1882             "Did not get ENOENT removing an expired object.");
1883     checkeq(ENGINE_KEY_ENOENT, verify_key(h, h1, "key"), "Expected missing key");
1884
1885     return SUCCESS;
1886 }
1887
1888 static enum test_result test_set_delete(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1889     item *i = NULL;
1890     checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
1891             "Failed set.");
1892     h1->release(h, NULL, i);
1893     check_key_value(h, h1, "key", "somevalue", 9);
1894     checkeq(ENGINE_SUCCESS, del(h, h1, "key", 0, 0),
1895             "Failed remove with value.");
1896     checkeq(ENGINE_KEY_ENOENT, verify_key(h, h1, "key"), "Expected missing key");
1897     wait_for_flusher_to_settle(h, h1);
1898     wait_for_stat_to_be(h, h1, "curr_items", 0);
1899     return SUCCESS;
1900 }
1901
1902 static enum test_result test_set_delete_invalid_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1903     item *i = NULL;
1904     check(store(h, h1, NULL, OPERATION_SET, "key",
1905                 "somevalue", &i) == ENGINE_SUCCESS,
1906           "Failed set.");
1907     check_key_value(h, h1, "key", "somevalue", 9);
1908     item_info info;
1909     info.nvalue = 1;
1910     check(h1->get_item_info(h, NULL, i, &info) == true,
1911           "Should be able to get info");
1912     h1->release(h, NULL, i);
1913
1914     check(del(h, h1, "key", info.cas + 1, 0) == ENGINE_KEY_EEXISTS,
1915           "Didn't expect to be able to remove the item with wrong cas");
1916     return SUCCESS;
1917 }
1918
1919 static enum test_result test_bug2509(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1920     for (int j = 0; j < 10000; ++j) {
1921         item *itm = NULL;
1922         checkeq(ENGINE_SUCCESS,
1923                 store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &itm),
1924                 "Failed set.");
1925         h1->release(h, NULL, itm);
1926         usleep(10);
1927         checkeq(ENGINE_SUCCESS, del(h, h1, "key", 0, 0), "Failed remove with value.");
1928         usleep(10);
1929     }
1930
1931     // Restart again, to verify we don't have any duplicates.
1932     testHarness.reload_engine(&h, &h1,
1933                               testHarness.engine_path,
1934                               testHarness.get_current_testcase()->cfg,
1935                               true, false);
1936     wait_for_warmup_complete(h, h1);
1937
1938     return get_int_stat(h, h1, "ep_warmup_dups") == 0 ? SUCCESS : FAIL;
1939 }
1940
1941 static enum test_result test_bug7023(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1942     std::vector<std::string> keys;
1943     // Make a vbucket mess.
1944     for (int j = 0; j < 10000; ++j) {
1945         std::stringstream ss;
1946         ss << "key" << j;
1947         std::string key(ss.str());
1948         keys.push_back(key);
1949     }
1950
1951     std::vector<std::string>::iterator it;
1952     for (int j = 0; j < 5; ++j) {
1953         check(set_vbucket_state(h, h1, 0, vbucket_state_dead), "Failed set set vbucket 0 dead.");
1954         vbucketDelete(h, h1, 0);
1955         check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
1956               "Expected vbucket deletion to work.");
1957         check(set_vbucket_state(h, h1, 0, vbucket_state_active), "Failed set set vbucket 0 active.");
1958         for (it = keys.begin(); it != keys.end(); ++it) {
1959             item *i;
1960             check(store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(), &i)
1961                   == ENGINE_SUCCESS, "Failed to store a value");
1962             h1->release(h, NULL, i);
1963
1964         }
1965     }
1966     wait_for_flusher_to_settle(h, h1);
1967
1968     // Restart again, to verify no data loss.
1969     testHarness.reload_engine(&h, &h1,
1970                               testHarness.engine_path,
1971                               testHarness.get_current_testcase()->cfg,
1972                               true, false);
1973     wait_for_warmup_complete(h, h1);
1974     return get_int_stat(h, h1, "ep_warmup_value_count", "warmup") == 10000 ? SUCCESS : FAIL;
1975 }
1976
1977 static enum test_result test_delete_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1978     wait_for_persisted_value(h, h1, "key", "value1");
1979
1980     check(del(h, h1, "key", 0, 0) == ENGINE_SUCCESS, "Failed remove with value.");
1981
1982     wait_for_persisted_value(h, h1, "key", "value2");
1983
1984     testHarness.reload_engine(&h, &h1,
1985                               testHarness.engine_path,
1986                               testHarness.get_current_testcase()->cfg,
1987                               true, false);
1988     wait_for_warmup_complete(h, h1);
1989
1990     check_key_value(h, h1, "key", "value2", 6);
1991     check(del(h, h1, "key", 0, 0) == ENGINE_SUCCESS, "Failed remove with value.");
1992     wait_for_flusher_to_settle(h, h1);
1993
1994     testHarness.reload_engine(&h, &h1,
1995                               testHarness.engine_path,
1996                               testHarness.get_current_testcase()->cfg,
1997                               true, false);
1998     wait_for_warmup_complete(h, h1);
1999
2000     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
2001
2002     return SUCCESS;
2003 }
2004
2005 static enum test_result test_get_delete_missing_file(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2006     const char *key = "key";
2007     wait_for_persisted_value(h, h1, key, "value2delete");
2008
2009     // whack the db file and directory where the key is stored
2010     rmdb();
2011
2012     item *i = NULL;
2013     int errorCode = h1->get(h, NULL, &i, key, strlen(key), 0);
2014     h1->release(h, NULL, i);
2015
2016     // ep engine must be unaware of well-being of the db file as long as
2017     // the item is still in the memory
2018     check(errorCode == ENGINE_SUCCESS, "Expected success for get");
2019
2020     i = NULL;
2021     evict_key(h, h1, key);
2022     errorCode = h1->get(h, NULL, &i, key, strlen(key), 0);
2023     h1->release(h, NULL, i);
2024
2025     // ep engine must be now aware of the ill-fated db file where
2026     // the item is supposedly stored
2027     check(errorCode == ENGINE_TMPFAIL, "Expected tmp fail for get");
2028
2029     return SUCCESS;
2030 }
2031
2032
2033 static enum test_result test_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2034     item *i = NULL;
2035     static const char val[] = "somevalue";
2036     ENGINE_ERROR_CODE ret;
2037     check((ret = store(h, h1, NULL, OPERATION_SET, "key", val, &i)) == ENGINE_SUCCESS,
2038           "Failed set.");
2039     h1->release(h, NULL, i);
2040
2041     testHarness.reload_engine(&h, &h1,
2042                               testHarness.engine_path,
2043                               testHarness.get_current_testcase()->cfg,
2044                               true, false);
2045     wait_for_warmup_complete(h, h1);
2046     check_key_value(h, h1, "key", val, strlen(val));
2047     return SUCCESS;
2048 }
2049
2050 static enum test_result test_restart_session_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2051     createTapConn(h, h1, "tap_client_thread");
2052
2053     testHarness.reload_engine(&h, &h1,
2054                               testHarness.engine_path,
2055                               testHarness.get_current_testcase()->cfg,
2056                               true, false);
2057     wait_for_warmup_complete(h, h1);
2058     createTapConn(h, h1, "tap_client_thread");
2059
2060     check(h1->get_stats(h, NULL, "tap", 3, add_stats) == ENGINE_SUCCESS,
2061           "Failed to get stats.");
2062     std::string val = vals["eq_tapq:tap_client_thread:backfill_completed"];
2063     check(strcmp(val.c_str(), "true") == 0, "Don't expect the backfill upon restart");
2064     return SUCCESS;
2065 }
2066
2067 static enum test_result test_specialKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2068     item *i = NULL;
2069     ENGINE_ERROR_CODE ret;
2070
2071     // Simplified Chinese "Couchbase"
2072     static const char key0[] = "沙发数据库";
2073     static const char val0[] = "some Chinese value";
2074     check((ret = store(h, h1, NULL, OPERATION_SET, key0, val0, &i)) == ENGINE_SUCCESS,
2075           "Failed set Chinese key");
2076     check_key_value(h, h1, key0, val0, strlen(val0));
2077     h1->release(h, NULL, i);
2078     // Traditional Chinese "Couchbase"
2079     static const char key1[] = "沙發數據庫";
2080     static const char val1[] = "some Traditional Chinese value";
2081     check((ret = store(h, h1, NULL, OPERATION_SET, key1, val1, &i)) == ENGINE_SUCCESS,
2082           "Failed set Traditional Chinese key");
2083     h1->release(h, NULL, i);
2084     // Korean "couch potato"
2085     static const char key2[] = "쇼파감자";
2086     static const char val2[] = "some Korean value";
2087     check((ret = store(h, h1, NULL, OPERATION_SET, key2, val2, &i)) == ENGINE_SUCCESS,
2088           "Failed set Korean key");
2089     h1->release(h, NULL, i);
2090     // Russian "couch potato"
2091     static const char key3[] = "лодырь, лентяй";
2092     static const char val3[] = "some Russian value";
2093     check((ret = store(h, h1, NULL, OPERATION_SET, key3, val3, &i)) == ENGINE_SUCCESS,
2094           "Failed set Russian key");
2095     h1->release(h, NULL, i);
2096     // Japanese "couch potato"
2097     static const char key4[] = "カウチポテト";
2098     static const char val4[] = "some Japanese value";
2099     check((ret = store(h, h1, NULL, OPERATION_SET, key4, val4, &i)) == ENGINE_SUCCESS,
2100           "Failed set Japanese key");
2101     h1->release(h, NULL, i);
2102     // Indian char key, and no idea what it is
2103     static const char key5[] = "हरियानवी";
2104     static const char val5[] = "some Indian value";
2105     check((ret = store(h, h1, NULL, OPERATION_SET, key5, val5, &i)) == ENGINE_SUCCESS,
2106           "Failed set Indian key");
2107     h1->release(h, NULL, i);
2108     // Portuguese translation "couch potato"
2109     static const char key6[] = "sedentário";
2110     static const char val6[] = "some Portuguese value";
2111     check((ret = store(h, h1, NULL, OPERATION_SET, key6, val6, &i)) == ENGINE_SUCCESS,
2112           "Failed set Portuguese key");
2113     h1->release(h, NULL, i);
2114     // Arabic translation "couch potato"
2115     static const char key7[] = "الحافلةالبطاطة";
2116     static const char val7[] = "some Arabic value";
2117     check((ret = store(h, h1, NULL, OPERATION_SET, key7, val7, &i)) == ENGINE_SUCCESS,
2118           "Failed set Arabic key");
2119     h1->release(h, NULL, i);
2120
2121     testHarness.reload_engine(&h, &h1,
2122                               testHarness.engine_path,
2123                               testHarness.get_current_testcase()->cfg,
2124                               true, false);
2125     wait_for_warmup_complete(h, h1);
2126     check_key_value(h, h1, key0, val0, strlen(val0));
2127     check_key_value(h, h1, key1, val1, strlen(val1));
2128     check_key_value(h, h1, key2, val2, strlen(val2));
2129     check_key_value(h, h1, key3, val3, strlen(val3));
2130     check_key_value(h, h1, key4, val4, strlen(val4));
2131     check_key_value(h, h1, key5, val5, strlen(val5));
2132     check_key_value(h, h1, key6, val6, strlen(val6));
2133     check_key_value(h, h1, key7, val7, strlen(val7));
2134     return SUCCESS;
2135 }
2136
2137 static enum test_result test_binKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2138     item *i = NULL;
2139     ENGINE_ERROR_CODE ret;
2140
2141     // binary key with char values beyond 0x7F
2142     static const char key0[] = "\xe0\xed\xf1\x6f\x7f\xf8\xfa";
2143     static const char val0[] = "some value val8";
2144     check((ret = store(h, h1, NULL, OPERATION_SET, key0, val0, &i)) == ENGINE_SUCCESS,
2145           "Failed set binary key0");
2146     check_key_value(h, h1, key0, val0, strlen(val0));
2147     h1->release(h, NULL, i);
2148     // binary keys with char values beyond 0x7F
2149     static const char key1[] = "\xf1\xfd\xfe\xff\xf0\xf8\xef";
2150     static const char val1[] = "some value val9";
2151     check((ret = store(h, h1, NULL, OPERATION_SET, key1, val1, &i)) == ENGINE_SUCCESS,
2152           "Failed set binary key1");
2153     check_key_value(h, h1, key1, val1, strlen(val1));
2154     h1->release(h, NULL, i);
2155     // binary keys with special utf-8 BOM (Byte Order Mark) values 0xBB 0xBF 0xEF
2156     static const char key2[] = "\xff\xfe\xbb\xbf\xef";
2157     static const char val2[] = "some utf-8 bom value";
2158     check((ret = store(h, h1, NULL, OPERATION_SET, key2, val2, &i)) == ENGINE_SUCCESS,
2159           "Failed set binary utf-8 bom key");
2160     check_key_value(h, h1, key2, val2, strlen(val2));
2161     h1->release(h, NULL, i);
2162     // binary keys with special utf-16BE BOM values "U+FEFF"
2163     static const char key3[] = "U+\xfe\xff\xefU+\xff\xfe";
2164     static const char val3[] = "some utf-16 bom value";
2165     check((ret = store(h, h1, NULL, OPERATION_SET, key3, val3, &i)) == ENGINE_SUCCESS,
2166           "Failed set binary utf-16 bom key");
2167     check_key_value(h, h1, key3, val3, strlen(val3));
2168     h1->release(h, NULL, i);
2169
2170     testHarness.reload_engine(&h, &h1,
2171                               testHarness.engine_path,
2172                               testHarness.get_current_testcase()->cfg,
2173                               true, false);
2174     wait_for_warmup_complete(h, h1);
2175     check_key_value(h, h1, key0, val0, strlen(val0));
2176     check_key_value(h, h1, key1, val1, strlen(val1));
2177     check_key_value(h, h1, key2, val2, strlen(val2));
2178     check_key_value(h, h1, key3, val3, strlen(val3));
2179     return SUCCESS;
2180 }
2181
2182 static enum test_result test_restart_bin_val(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2183
2184
2185
2186     char binaryData[] = "abcdefg\0gfedcba";
2187     cb_assert(sizeof(binaryData) != strlen(binaryData));
2188
2189     item *i = NULL;
2190     check(storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
2191                        binaryData, sizeof(binaryData), 82758, &i, 0, 0)
2192           == ENGINE_SUCCESS,
2193           "Failed set.");
2194     h1->release(h, NULL, i);
2195
2196     testHarness.reload_engine(&h, &h1,
2197                               testHarness.engine_path,
2198                               testHarness.get_current_testcase()->cfg,
2199                               true, false);
2200     wait_for_warmup_complete(h, h1);
2201
2202     check_key_value(h, h1, "key", binaryData, sizeof(binaryData));
2203     return SUCCESS;
2204 }
2205
2206 static enum test_result test_wrong_vb_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2207     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2208     check(ENGINE_NOT_MY_VBUCKET == verify_key(h, h1, "key", 1),
2209           "Expected wrong bucket.");
2210     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2211     return SUCCESS;
2212 }
2213
2214 static enum test_result test_vb_get_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2215     check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
2216     const void *cookie = testHarness.create_cookie();
2217     testHarness.set_ewouldblock_handling(cookie, false);
2218
2219     item *i = NULL;
2220     check(ENGINE_EWOULDBLOCK == h1->get(h, cookie, &i, "key", strlen("key"), 1),
2221           "Expected woodblock.");
2222     h1->release(h, NULL, i);
2223
2224     testHarness.destroy_cookie(cookie);
2225     return SUCCESS;
2226 }
2227
2228 static enum test_result test_vb_get_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2229     check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
2230     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2231     check(ENGINE_NOT_MY_VBUCKET == verify_key(h, h1, "key", 1),
2232           "Expected not my bucket.");
2233     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2234     return SUCCESS;
2235 }
2236
2237 static enum test_result test_wrong_vb_incr(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2238     uint64_t result;
2239     item *i = NULL;
2240     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2241     check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
2242                          &i, PROTOCOL_BINARY_RAW_BYTES, &result,
2243                          1) == ENGINE_NOT_MY_VBUCKET,
2244           "Expected not my vbucket.");
2245     h1->release(h, NULL, i);
2246     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2247     return SUCCESS;
2248 }
2249
2250 static enum test_result test_vb_incr_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2251     const void *cookie = testHarness.create_cookie();
2252     testHarness.set_ewouldblock_handling(cookie, false);
2253     uint64_t result;
2254     item *i = NULL;
2255     check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
2256     check(h1->arithmetic(h, cookie, "key", 3, true, false, 1, 1, 0,
2257                          &i, PROTOCOL_BINARY_RAW_BYTES, &result,
2258                          1) == ENGINE_EWOULDBLOCK,
2259           "Expected wouldblock.");
2260     h1->release(h, NULL, i);
2261     testHarness.destroy_cookie(cookie);
2262     return SUCCESS;
2263 }
2264
2265 static enum test_result test_vb_incr_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2266     uint64_t result;
2267     item *i = NULL;
2268     check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
2269     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2270     check(h1->arithmetic(h, NULL, "key", 3, true, false, 1, 1, 0,
2271                          &i, PROTOCOL_BINARY_RAW_BYTES, &result,
2272                          1) == ENGINE_NOT_MY_VBUCKET,
2273           "Expected not my bucket.");
2274     h1->release(h, NULL, i);
2275     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2276     return SUCCESS;
2277 }
2278
2279 static enum test_result test_wrong_vb_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2280     return test_wrong_vb_mutation(h, h1, OPERATION_SET);
2281 }
2282
2283 static enum test_result test_wrong_vb_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2284     return test_wrong_vb_mutation(h, h1, OPERATION_CAS);
2285 }
2286
2287 static enum test_result test_wrong_vb_add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2288     return test_wrong_vb_mutation(h, h1, OPERATION_ADD);
2289 }
2290
2291 static enum test_result test_wrong_vb_replace(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2292     return test_wrong_vb_mutation(h, h1, OPERATION_REPLACE);
2293 }
2294
2295 static enum test_result test_wrong_vb_append(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2296     return test_wrong_vb_mutation(h, h1, OPERATION_APPEND);
2297 }
2298
2299 static enum test_result test_wrong_vb_prepend(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2300     return test_wrong_vb_mutation(h, h1, OPERATION_PREPEND);
2301 }
2302
2303 static enum test_result test_wrong_vb_del(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2304     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2305     check(ENGINE_NOT_MY_VBUCKET == del(h, h1, "key", 0, 1), "Expected wrong bucket.");
2306     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2307     return SUCCESS;
2308 }
2309
2310 static enum test_result test_expiry(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2311     const char *key = "test_expiry";
2312     const char *data = "some test data here.";
2313
2314     item *it = NULL;
2315
2316     ENGINE_ERROR_CODE rv;
2317     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 2,
2318                       PROTOCOL_BINARY_RAW_BYTES);
2319     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2320
2321     item_info info;
2322     info.nvalue = 1;
2323     if (!h1->get_item_info(h, NULL, it, &info)) {
2324         abort();
2325     }
2326     memcpy(info.value[0].iov_base, data, strlen(data));
2327
2328     uint64_t cas = 0;
2329     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2330     check(rv == ENGINE_SUCCESS, "Set failed.");
2331     check_key_value(h, h1, key, data, strlen(data));
2332     h1->release(h, NULL, it);
2333
2334     testHarness.time_travel(5);
2335     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
2336           "Item didn't expire");
2337
2338     int expired_access = get_int_stat(h, h1, "ep_expired_access");
2339     int expired_pager = get_int_stat(h, h1, "ep_expired_pager");
2340     int active_expired = get_int_stat(h, h1, "vb_active_expired");
2341     check(expired_pager == 0, "Expected zero expired item by pager");
2342     check(expired_access == 1, "Expected an expired item on access");
2343     check(active_expired == 1, "Expected an expired active item");
2344     checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, key, data, &it),
2345             "Failed set.");
2346     h1->release(h, NULL, it);
2347
2348     std::stringstream ss;
2349     ss << "curr_items stat should be still 1 after ";
2350     ss << "overwriting the key that was expired, but not purged yet";
2351     checkeq(1, get_int_stat(h, h1, "curr_items"), ss.str().c_str());
2352
2353     return SUCCESS;
2354 }
2355
2356 static enum test_result test_expiry_loader(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2357     const char *key = "test_expiry_loader";
2358     const char *data = "some test data here.";
2359
2360     item *it = NULL;
2361
2362     ENGINE_ERROR_CODE rv;
2363     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 2,
2364                       PROTOCOL_BINARY_RAW_BYTES);
2365     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2366
2367     item_info info;
2368     info.nvalue = 1;
2369     if (!h1->get_item_info(h, NULL, it, &info)) {
2370         abort();
2371     }
2372     memcpy(info.value[0].iov_base, data, strlen(data));
2373
2374     uint64_t cas = 0;
2375     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2376     check(rv == ENGINE_SUCCESS, "Set failed.");
2377     check_key_value(h, h1, key, data, strlen(data));
2378     h1->release(h, NULL, it);
2379
2380     testHarness.time_travel(3);
2381
2382     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
2383           "Item didn't expire");
2384
2385     // Restart the engine to ensure the above expired item is not loaded
2386     testHarness.reload_engine(&h, &h1,
2387                               testHarness.engine_path,
2388                               testHarness.get_current_testcase()->cfg,
2389                               true, false);
2390     wait_for_warmup_complete(h, h1);
2391     cb_assert(0 == get_int_stat(h, h1, "ep_warmup_value_count", "warmup"));
2392
2393     return SUCCESS;
2394 }
2395
2396 static enum test_result test_expiration_on_warmup(ENGINE_HANDLE *h,
2397                                                   ENGINE_HANDLE_V1 *h1) {
2398     const char *key = "KEY";
2399     const char *data = "VALUE";
2400
2401     item *it = NULL;
2402
2403     ENGINE_ERROR_CODE rv;
2404     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 3,
2405                       PROTOCOL_BINARY_RAW_BYTES);
2406     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2407
2408     item_info info;
2409     info.nvalue = 1;
2410     if (!h1->get_item_info(h, NULL, it, &info)) {
2411         abort();
2412     }
2413     memcpy(info.value[0].iov_base, data, strlen(data));
2414
2415     uint64_t cas = 0;
2416     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2417     check(rv == ENGINE_SUCCESS, "Set failed.");
2418     check_key_value(h, h1, key, data, strlen(data));
2419     h1->release(h, NULL, it);
2420     wait_for_flusher_to_settle(h, h1);
2421
2422     check(get_int_stat(h, h1, "curr_items") == 1, "Failed store item");
2423     testHarness.time_travel(5);
2424
2425     // Restart the engine to ensure the above item is expired
2426     testHarness.reload_engine(&h, &h1,
2427                               testHarness.engine_path,
2428                               testHarness.get_current_testcase()->cfg,
2429                               true, false);
2430     wait_for_warmup_complete(h, h1);
2431     int pager_runs = get_int_stat(h, h1, "ep_num_expiry_pager_runs");
2432     wait_for_stat_change(h, h1, "ep_num_expiry_pager_runs", pager_runs);
2433     wait_for_flusher_to_settle(h, h1);
2434     check(get_int_stat(h, h1, "curr_items") == 0,
2435             "The item should have been expired.");
2436
2437     return SUCCESS;
2438
2439 }
2440
2441 static enum test_result test_bug3454(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2442     const char *key = "test_expiry_duplicate_warmup";
2443     const char *data = "some test data here.";
2444
2445     item *it = NULL;
2446
2447     ENGINE_ERROR_CODE rv;
2448     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 5,
2449                       PROTOCOL_BINARY_RAW_BYTES);
2450     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2451
2452     item_info info;
2453     info.nvalue = 1;
2454     if (!h1->get_item_info(h, NULL, it, &info)) {
2455         abort();
2456     }
2457     memcpy(info.value[0].iov_base, data, strlen(data));
2458
2459     uint64_t cas = 0;
2460     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2461     check(rv == ENGINE_SUCCESS, "Set failed.");
2462     check_key_value(h, h1, key, data, strlen(data));
2463     h1->release(h, NULL, it);
2464     wait_for_flusher_to_settle(h, h1);
2465
2466     // Advance the ep_engine time by 10 sec for the above item to be expired.
2467     testHarness.time_travel(10);
2468     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_KEY_ENOENT,
2469           "Item didn't expire");
2470
2471     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 0,
2472                       PROTOCOL_BINARY_RAW_BYTES);
2473     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2474
2475     info.nvalue = 1;
2476     if (!h1->get_item_info(h, NULL, it, &info)) {
2477         abort();
2478     }
2479     memcpy(info.value[0].iov_base, data, strlen(data));
2480
2481     cas = 0;
2482     // Add a new item with the same key.
2483     rv = h1->store(h, NULL, it, &cas, OPERATION_ADD, 0);
2484     check(rv == ENGINE_SUCCESS, "Add failed.");
2485     check_key_value(h, h1, key, data, strlen(data));
2486     h1->release(h, NULL, it);
2487
2488     check(h1->get(h, NULL, &it, key, strlen(key), 0) == ENGINE_SUCCESS,
2489           "Item shouldn't expire");
2490     h1->release(h, NULL, it);
2491
2492     // Restart the engine to ensure the above unexpired new item is loaded
2493     testHarness.reload_engine(&h, &h1,
2494                               testHarness.engine_path,
2495                               testHarness.get_current_testcase()->cfg,
2496                               true, false);
2497     wait_for_warmup_complete(h, h1);
2498     cb_assert(1 == get_int_stat(h, h1, "ep_warmup_value_count", "warmup"));
2499     cb_assert(0 == get_int_stat(h, h1, "ep_warmup_dups", "warmup"));
2500
2501     return SUCCESS;
2502 }
2503
2504 static enum test_result test_bug3522(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2505     const char *key = "test_expiry_no_items_warmup";
2506     const char *data = "some test data here.";
2507
2508     item *it = NULL;
2509
2510     ENGINE_ERROR_CODE rv;
2511     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(data), 0, 0,
2512                       PROTOCOL_BINARY_RAW_BYTES);
2513     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2514
2515     item_info info;
2516     info.nvalue = 1;
2517     if (!h1->get_item_info(h, NULL, it, &info)) {
2518         abort();
2519     }
2520     memcpy(info.value[0].iov_base, data, strlen(data));
2521
2522     uint64_t cas = 0;
2523     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2524     check(rv == ENGINE_SUCCESS, "Set failed.");
2525     check_key_value(h, h1, key, data, strlen(data));
2526     h1->release(h, NULL, it);
2527     wait_for_flusher_to_settle(h, h1);
2528
2529     // Add a new item with the same key and 2 sec of expiration.
2530     const char *new_data = "new data here.";
2531     rv = h1->allocate(h, NULL, &it, key, strlen(key), strlen(new_data), 0, 2,
2532                       PROTOCOL_BINARY_RAW_BYTES);
2533     check(rv == ENGINE_SUCCESS, "Allocation failed.");
2534
2535     info.nvalue = 1;
2536     if (!h1->get_item_info(h, NULL, it, &info)) {
2537         abort();
2538     }
2539     memcpy(info.value[0].iov_base, new_data, strlen(new_data));
2540
2541     int pager_runs = get_int_stat(h, h1, "ep_num_expiry_pager_runs");
2542     cas = 0;
2543     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, 0);
2544     check(rv == ENGINE_SUCCESS, "Set failed.");
2545     check_key_value(h, h1, key, new_data, strlen(new_data));
2546     h1->release(h, NULL, it);
2547     testHarness.time_travel(3);
2548     wait_for_stat_change(h, h1, "ep_num_expiry_pager_runs", pager_runs);
2549     wait_for_flusher_to_settle(h, h1);
2550
2551     // Restart the engine.
2552     testHarness.reload_engine(&h, &h1,
2553                               testHarness.engine_path,
2554                               testHarness.get_current_testcase()->cfg,
2555                               true, false);
2556     wait_for_warmup_complete(h, h1);
2557     // TODO: modify this for a better test case
2558     cb_assert(0 == get_int_stat(h, h1, "ep_warmup_dups", "warmup"));
2559
2560     return SUCCESS;
2561 }
2562
2563 static enum test_result test_get_replica_active_state(ENGINE_HANDLE *h,
2564                                                       ENGINE_HANDLE_V1 *h1) {
2565     protocol_binary_request_header *pkt;
2566     pkt = prepare_get_replica(h, h1, vbucket_state_active);
2567     check(h1->unknown_command(h, NULL, pkt, add_response) ==
2568           ENGINE_SUCCESS, "Get Replica Failed");
2569     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2570           "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
2571
2572     return SUCCESS;
2573 }
2574
2575 static enum test_result test_get_replica_pending_state(ENGINE_HANDLE *h,
2576                                                        ENGINE_HANDLE_V1 *h1) {
2577     protocol_binary_request_header *pkt;
2578
2579     const void *cookie = testHarness.create_cookie();
2580     testHarness.set_ewouldblock_handling(cookie, false);
2581     pkt = prepare_get_replica(h, h1, vbucket_state_pending);
2582     check(h1->unknown_command(h, cookie, pkt, add_response) ==
2583           ENGINE_EWOULDBLOCK, "Should have returned error for pending state");
2584     testHarness.destroy_cookie(cookie);
2585     return SUCCESS;
2586 }
2587
2588 static enum test_result test_get_replica_dead_state(ENGINE_HANDLE *h,
2589                                                     ENGINE_HANDLE_V1 *h1) {
2590     protocol_binary_request_header *pkt;
2591     pkt = prepare_get_replica(h, h1, vbucket_state_dead);
2592     check(h1->unknown_command(h, NULL, pkt, add_response) ==
2593           ENGINE_SUCCESS, "Get Replica Failed");
2594     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2595           "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
2596
2597     return SUCCESS;
2598 }
2599
2600 static enum test_result test_get_replica(ENGINE_HANDLE *h,
2601                                          ENGINE_HANDLE_V1 *h1) {
2602     protocol_binary_request_header *pkt;
2603     pkt = prepare_get_replica(h, h1, vbucket_state_replica);
2604     check(h1->unknown_command(h, NULL, pkt, add_response) == ENGINE_SUCCESS,
2605                               "Get Replica Failed");
2606     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
2607           "Expected PROTOCOL_BINARY_RESPONSE_SUCCESS response.");
2608     check(last_body == "replicadata",
2609           "Should have returned identical value");
2610
2611     return SUCCESS;
2612 }
2613
2614 static enum test_result test_get_replica_non_resident(ENGINE_HANDLE *h,
2615                                                       ENGINE_HANDLE_V1 *h1) {
2616
2617     item *i = NULL;
2618     check(store(h, h1, NULL, OPERATION_SET, "key", "value", &i, 0, 0)
2619           == ENGINE_SUCCESS, "Store Failed");
2620     h1->release(h, NULL, i);
2621     wait_for_flusher_to_settle(h, h1);
2622     wait_for_stat_to_be(h, h1, "ep_total_persisted", 1);
2623
2624     evict_key(h, h1, "key", 0, "Ejected.");
2625     check(set_vbucket_state(h, h1, 0, vbucket_state_replica),
2626           "Failed to set vbucket to replica");
2627
2628     get_replica(h, h1, "key", 0);
2629     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "Expected success");
2630
2631     return SUCCESS;
2632 }
2633
2634 static enum test_result test_get_replica_invalid_key(ENGINE_HANDLE *h,
2635                                                      ENGINE_HANDLE_V1 *h1) {
2636     protocol_binary_request_header *pkt;
2637     bool makeinvalidkey = true;
2638     pkt = prepare_get_replica(h, h1, vbucket_state_replica, makeinvalidkey);
2639     check(h1->unknown_command(h, NULL, pkt, add_response) ==
2640           ENGINE_SUCCESS, "Get Replica Failed");
2641     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2642           "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
2643     return SUCCESS;
2644 }
2645
2646 static enum test_result test_vb_del_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2647     const void *cookie = testHarness.create_cookie();
2648     testHarness.set_ewouldblock_handling(cookie, false);
2649     check(set_vbucket_state(h, h1, 1, vbucket_state_pending), "Failed to set vbucket state.");
2650     check(ENGINE_EWOULDBLOCK == del(h, h1, "key", 0, 1, cookie),
2651           "Expected woodblock.");
2652     testHarness.destroy_cookie(cookie);
2653     return SUCCESS;
2654 }
2655
2656 static enum test_result test_vb_del_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2657     check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set vbucket state.");
2658     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2659     check(ENGINE_NOT_MY_VBUCKET == del(h, h1, "key", 0, 1),
2660           "Expected not my vbucket.");
2661     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2662     return SUCCESS;
2663 }
2664
2665 static enum test_result test_touch(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2666     // key is a mandatory field!
2667     touch(h, h1, NULL, 0, (time(NULL) + 10));
2668     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2669
2670     // extlen is a mandatory field!
2671     protocol_binary_request_header *request;
2672     request = createPacket(PROTOCOL_BINARY_CMD_TOUCH, 0, 0, NULL, 0, "akey", 4);
2673     check(h1->unknown_command(h, NULL, request, add_response) == ENGINE_SUCCESS,
2674           "Failed to call touch");
2675     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2676     free(request);
2677
2678     // Try to touch an unknown item...
2679     touch(h, h1, "mykey", 0, (time(NULL) + 10));
2680     check(last_status == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, "Testing unknown key");
2681
2682     // illegal vbucket
2683     touch(h, h1, "mykey", 5, (time(NULL) + 10));
2684     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, "Testing illegal vbucket");
2685
2686     // Store the item!
2687     item *itm = NULL;
2688     check(store(h, h1, NULL, OPERATION_SET, "mykey", "somevalue", &itm) == ENGINE_SUCCESS,
2689           "Failed set.");
2690     h1->release(h, NULL, itm);
2691
2692     check_key_value(h, h1, "mykey", "somevalue", strlen("somevalue"));
2693
2694     touch(h, h1, "mykey", 0, (time(NULL) + 10));
2695     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch mykey");
2696
2697     // time-travel 9 secs..
2698     testHarness.time_travel(9);
2699
2700     // The item should still exist
2701     check_key_value(h, h1, "mykey", "somevalue", 9);
2702
2703     // time-travel 2 secs..
2704     testHarness.time_travel(2);
2705
2706     // The item should have expired now...
2707     check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2708     return SUCCESS;
2709 }
2710
2711 static enum test_result test_touch_mb7342(ENGINE_HANDLE *h,
2712                                           ENGINE_HANDLE_V1 *h1) {
2713     const char *key = "MB-7342";
2714     // Store the item!
2715     item *itm = NULL;
2716     check(store(h, h1, NULL, OPERATION_SET, key, "v", &itm) == ENGINE_SUCCESS,
2717           "Failed set.");
2718     h1->release(h, NULL, itm);
2719
2720     touch(h, h1, key, 0, 0);
2721     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch key");
2722
2723     check_key_value(h, h1, key, "v", 1);
2724
2725     // Travel a loong time to see if the object is still there (the default
2726     // store sets an exp time of 3600
2727     testHarness.time_travel(3700);
2728
2729     check_key_value(h, h1, key, "v", 1);
2730
2731     return SUCCESS;
2732 }
2733
2734 static enum test_result test_touch_mb10277(ENGINE_HANDLE *h,
2735                                             ENGINE_HANDLE_V1 *h1) {
2736     const char *key = "MB-10277";
2737     // Store the item!
2738     item *itm = NULL;
2739     check(store(h, h1, NULL, OPERATION_SET, key, "v", &itm) == ENGINE_SUCCESS,
2740           "Failed set.");
2741     h1->release(h, NULL, itm);
2742     wait_for_flusher_to_settle(h, h1);
2743     evict_key(h, h1, key, 0, "Ejected.");
2744
2745     touch(h, h1, key, 0, 3600); // A new expiration time remains in the same.
2746     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch key");
2747
2748     return SUCCESS;
2749 }
2750
2751 static enum test_result test_gat(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2752     // key is a mandatory field!
2753     gat(h, h1, NULL, 0, 10);
2754     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2755
2756     // extlen is a mandatory field!
2757     protocol_binary_request_header *request;
2758     request = createPacket(PROTOCOL_BINARY_CMD_GAT, 0, 0, NULL, 0, "akey", 4);
2759     check(h1->unknown_command(h, NULL, request, add_response) == ENGINE_SUCCESS,
2760           "Failed to call gat");
2761     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2762     free(request);
2763
2764     // Try to gat an unknown item...
2765     gat(h, h1, "mykey", 0, 10);
2766     check(last_status == PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, "Testing unknown key");
2767
2768     // illegal vbucket
2769     gat(h, h1, "mykey", 5, 10);
2770     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, "Testing illegal vbucket");
2771
2772     // Store the item!
2773     item *itm = NULL;
2774     check(store(h, h1, NULL, OPERATION_SET, "mykey", "{\"some\":\"value\"}",
2775                 &itm, 0, 0, 3600, PROTOCOL_BINARY_DATATYPE_JSON) == ENGINE_SUCCESS,
2776           "Failed set.");
2777     h1->release(h, NULL, itm);
2778
2779     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2780             strlen("{\"some\":\"value\"}"));
2781
2782     gat(h, h1, "mykey", 0, 10);
2783     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "gat mykey");
2784     check(last_datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Expected datatype to be JSON");
2785     check(last_body.compare(0, sizeof("{\"some\":\"value\"}"),
2786                             "{\"some\":\"value\"}") == 0,
2787           "Invalid data returned");
2788
2789     // time-travel 9 secs..
2790     testHarness.time_travel(9);
2791
2792     // The item should still exist
2793     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2794                     strlen("{\"some\":\"value\"}"));
2795
2796     // time-travel 2 secs..
2797     testHarness.time_travel(2);
2798
2799     // The item should have expired now...
2800     check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2801     return SUCCESS;
2802 }
2803
2804 static enum test_result test_gatq(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2805     // key is a mandatory field!
2806     gat(h, h1, NULL, 0, 10, true);
2807     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2808
2809     // extlen is a mandatory field!
2810     protocol_binary_request_header *request;
2811     request = createPacket(PROTOCOL_BINARY_CMD_GATQ, 0, 0, NULL, 0, "akey", 4);
2812     check(h1->unknown_command(h, NULL, request, add_response) == ENGINE_SUCCESS,
2813           "Failed to call gatq");
2814     check(last_status == PROTOCOL_BINARY_RESPONSE_EINVAL, "Testing invalid arguments");
2815     free(request);
2816
2817     // Try to gatq an unknown item...
2818     last_status = static_cast<protocol_binary_response_status>(0xffff);
2819     gat(h, h1, "mykey", 0, 10, true);
2820
2821     // We should not have sent any response!
2822     check(last_status == (protocol_binary_response_status)0xffff, "Testing unknown key");
2823
2824     // illegal vbucket
2825     gat(h, h1, "mykey", 5, 10, true);
2826     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
2827           "Testing illegal vbucket");
2828
2829     // Store the item!
2830     item *itm = NULL;
2831     check(store(h, h1, NULL, OPERATION_SET, "mykey", "{\"some\":\"value\"}",
2832                 &itm, 0, 0, 3600, PROTOCOL_BINARY_DATATYPE_JSON) == ENGINE_SUCCESS,
2833           "Failed set.");
2834     h1->release(h, NULL, itm);
2835
2836     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2837                     strlen("{\"some\":\"value\"}"));
2838
2839     gat(h, h1, "mykey", 0, 10, true);
2840     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "gat mykey");
2841     check(last_datatype == PROTOCOL_BINARY_DATATYPE_JSON, "Expected datatype to be JSON");
2842     check(last_body.compare(0, sizeof("{\"some\":\"value\"}"),
2843                             "{\"some\":\"value\"}") == 0,
2844           "Invalid data returned");
2845
2846     // time-travel 9 secs..
2847     testHarness.time_travel(9);
2848
2849     // The item should still exist
2850     check_key_value(h, h1, "mykey", "{\"some\":\"value\"}",
2851                     strlen("{\"some\":\"value\"}"));
2852
2853     // time-travel 2 secs..
2854     testHarness.time_travel(2);
2855
2856     // The item should have expired now...
2857     check(h1->get(h, NULL, &itm, "mykey", 5, 0) == ENGINE_KEY_ENOENT, "Item should be gone");
2858     return SUCCESS;
2859 }
2860
2861 static enum test_result test_mb5215(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2862     item *itm = NULL;
2863     check(store(h, h1, NULL, OPERATION_SET, "coolkey", "cooler", &itm)
2864           == ENGINE_SUCCESS, "Failed set.");
2865     h1->release(h, NULL, itm);
2866
2867     check_key_value(h, h1, "coolkey", "cooler", strlen("cooler"));
2868
2869     // set new exptime to 111
2870     int expTime = time(NULL) + 111;
2871
2872     touch(h, h1, "coolkey", 0, expTime);
2873     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch coolkey");
2874
2875     //reload engine
2876     testHarness.reload_engine(&h, &h1,
2877                               testHarness.engine_path,
2878                               testHarness.get_current_testcase()->cfg,
2879                               true, false);
2880
2881     wait_for_warmup_complete(h, h1);
2882
2883     //verify persisted expiration time
2884     const char *statkey = "key coolkey 0";
2885     int newExpTime;
2886     check(h1->get(h, NULL, &itm, "coolkey", 7, 0) == ENGINE_SUCCESS,
2887           "Missing key");
2888     h1->release(h, NULL, itm);
2889     newExpTime = get_int_stat(h, h1, "key_exptime", statkey);
2890     check(newExpTime == expTime, "Failed to persist new exptime");
2891
2892     // evict key, touch expiration time, and verify
2893     evict_key(h, h1, "coolkey", 0, "Ejected.");
2894
2895     expTime = time(NULL) + 222;
2896     touch(h, h1, "coolkey", 0, expTime);
2897     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch coolkey");
2898
2899     testHarness.reload_engine(&h, &h1,
2900                               testHarness.engine_path,
2901                               testHarness.get_current_testcase()->cfg,
2902                               true, false);
2903     wait_for_warmup_complete(h, h1);
2904
2905     check(h1->get(h, NULL, &itm, "coolkey", 7, 0) == ENGINE_SUCCESS,
2906           "Missing key");
2907     h1->release(h, NULL, itm);
2908     newExpTime = get_int_stat(h, h1, "key_exptime", statkey);
2909     check(newExpTime == expTime, "Failed to persist new exptime");
2910
2911     return SUCCESS;
2912 }
2913
2914 static enum test_result test_alloc_limit(ENGINE_HANDLE *h,
2915                                          ENGINE_HANDLE_V1 *h1) {
2916     item *it = NULL;
2917     ENGINE_ERROR_CODE rv;
2918
2919     rv = h1->allocate(h, NULL, &it, "key", 3, 20 * 1024 * 1024, 0, 0,
2920                       PROTOCOL_BINARY_RAW_BYTES);
2921     check(rv == ENGINE_SUCCESS, "Allocated 20MB item");
2922     h1->release(h, NULL, it);
2923
2924     rv = h1->allocate(h, NULL, &it, "key", 3, (20 * 1024 * 1024) + 1, 0, 0,
2925                       PROTOCOL_BINARY_RAW_BYTES);
2926     check(rv == ENGINE_E2BIG, "Object too big");
2927
2928     return SUCCESS;
2929 }
2930
2931 static enum test_result test_whitespace_db(ENGINE_HANDLE *h,
2932                                            ENGINE_HANDLE_V1 *h1) {
2933     vals.clear();
2934     check(h1->get_stats(h, NULL, NULL, 0, add_stats) == ENGINE_SUCCESS,
2935           "Failed to get stats.");
2936     if (vals["ep_dbname"] != std::string(WHITESPACE_DB)) {
2937         std::cerr << "Expected dbname = ``" << WHITESPACE_DB << "''"
2938                   << ", got ``" << vals["ep_dbname"] << "''" << std::endl;
2939         return FAIL;
2940     }
2941
2942     check(access(WHITESPACE_DB, F_OK) != -1, "I expected the whitespace db to exist");
2943     return SUCCESS;
2944 }
2945
2946 static enum test_result test_memory_tracking(ENGINE_HANDLE *h,
2947                                              ENGINE_HANDLE_V1 *h1) {
2948     // Need memory tracker to be able to check our memory usage.
2949     std::string tracker = get_str_stat(h, h1, "ep_mem_tracker_enabled");
2950     if (tracker == "true") {
2951         return SUCCESS;
2952     } else {
2953         std::cerr << "Memory tracker not enabled" << std::endl;
2954         return FAIL;
2955     }
2956 }
2957
2958 static enum test_result test_memory_limit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2959     set_param(h, h1, protocol_binary_engine_param_flush, "mutation_mem_threshold", "95");
2960     wait_for_stat_change(h, h1,"ep_db_data_size", 0);
2961     int used = get_int_stat(h, h1, "mem_used");
2962     double mem_threshold =
2963         static_cast<double>(get_int_stat(h, h1, "ep_mutation_mem_threshold")) / 100;
2964     int max = static_cast<int>(get_int_stat(h, h1, "ep_max_size") * mem_threshold);
2965     check(get_int_stat(h, h1, "ep_oom_errors") == 0 &&
2966           get_int_stat(h, h1, "ep_tmp_oom_errors") == 0, "Expected no OOM errors.");
2967     cb_assert(used < max);
2968
2969     char *data = new char[2 * 1024 * 1024];
2970     cb_assert(data);
2971     memset(data, 'x', 2 * 1024 * 1024);
2972
2973     // Calculate the length of document to set - we want to ensure we can only
2974     // store one document before TEMP_OOM is hit.
2975     size_t vlen = (max - used) * 0.95;
2976     data[vlen] = 0x00;
2977
2978     item *i = NULL;
2979     // So if we add an item,
2980     check(store(h, h1, NULL, OPERATION_SET, "key", data, &i) == ENGINE_SUCCESS,
2981           "store failure");
2982     check_key_value(h, h1, "key", data, vlen);
2983     h1->release(h, NULL, i);
2984     i = NULL;
2985
2986     // There should be no room for another.
2987     ENGINE_ERROR_CODE second = store(h, h1, NULL, OPERATION_SET, "key2", data, &i);
2988     check(second == ENGINE_ENOMEM || second == ENGINE_TMPFAIL,
2989           "should have failed second set");
2990     if (i) {
2991         h1->release(h, NULL, i);
2992         i = NULL;
2993     }
2994     check(get_int_stat(h, h1, "ep_oom_errors") == 1 ||
2995           get_int_stat(h, h1, "ep_tmp_oom_errors") == 1, "Expected an OOM error.");
2996
2997     ENGINE_ERROR_CODE overwrite = store(h, h1, NULL, OPERATION_SET, "key", data, &i);
2998     check(overwrite == ENGINE_ENOMEM || overwrite == ENGINE_TMPFAIL,
2999           "should have failed second override");
3000     if (i) {
3001         h1->release(h, NULL, i);
3002         i = NULL;
3003     }
3004     check(get_int_stat(h, h1, "ep_oom_errors") == 2 ||
3005           get_int_stat(h, h1, "ep_tmp_oom_errors") == 2, "Expected another OOM error.");
3006     check_key_value(h, h1, "key", data, vlen);
3007     check(ENGINE_SUCCESS != verify_key(h, h1, "key2"), "Expected a failure in GET");
3008     int itemsRemoved = get_int_stat(h, h1, "ep_items_rm_from_checkpoints");
3009     // Until we remove that item
3010     check(del(h, h1, "key", 0, 0) == ENGINE_SUCCESS, "Failed remove with value.");
3011     check(ENGINE_KEY_ENOENT == verify_key(h, h1, "key"), "Expected missing key");
3012     testHarness.time_travel(65);
3013     wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
3014
3015     check(store(h, h1, NULL, OPERATION_SET, "key2", "somevalue2", &i) == ENGINE_SUCCESS,
3016           "should have succeded on the last set");
3017     check_key_value(h, h1, "key2", "somevalue2", 10);
3018     h1->release(h, NULL, i);
3019     delete []data;
3020     return SUCCESS;
3021 }
3022
3023 static enum test_result test_vbucket_get_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3024     return verify_vbucket_missing(h, h1, 1) ? SUCCESS : FAIL;
3025 }
3026
3027 static enum test_result test_vbucket_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3028     return verify_vbucket_state(h, h1, 0, vbucket_state_active) ? SUCCESS : FAIL;
3029 }
3030
3031 static enum test_result test_vbucket_create(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3032     if (!verify_vbucket_missing(h, h1, 1)) {
3033         fprintf(stderr, "vbucket wasn't missing.\n");
3034         return FAIL;
3035     }
3036
3037     if (!set_vbucket_state(h, h1, 1, vbucket_state_active)) {
3038         fprintf(stderr, "set state failed.\n");
3039         return FAIL;
3040     }
3041
3042     return verify_vbucket_state(h, h1, 1, vbucket_state_active) ? SUCCESS : FAIL;
3043 }
3044
3045 static enum test_result test_vbucket_compact(ENGINE_HANDLE *h,
3046                                              ENGINE_HANDLE_V1 *h1) {
3047     const char *key = "Carss";
3048     const char *value = "pollute";
3049     if (!verify_vbucket_missing(h, h1, 0)) {
3050         fprintf(stderr, "vbucket wasn't missing.\n");
3051         return FAIL;
3052     }
3053
3054     if (!set_vbucket_state(h, h1, 0, vbucket_state_active)) {
3055         fprintf(stderr, "set state failed.\n");
3056         return FAIL;
3057     }
3058
3059     check(verify_vbucket_state(h, h1, 0, vbucket_state_active),
3060             "VBucket state not active");
3061
3062     // Set two keys - one to be expired and other to remain...
3063     item *itm = NULL;
3064     check(store(h, h1, NULL, OPERATION_SET, key, value, &itm)
3065           == ENGINE_SUCCESS, "Failed set.");
3066     h1->release(h, NULL, itm);
3067
3068     check_key_value(h, h1, key, value, strlen(value));
3069
3070     // Set a non-expiring key...
3071     check(store(h, h1, NULL, OPERATION_SET, "trees", "cleanse", &itm)
3072           == ENGINE_SUCCESS, "Failed set.");
3073     h1->release(h, NULL, itm);
3074
3075     check_key_value(h, h1, "trees", "cleanse", strlen("cleanse"));
3076
3077     touch(h, h1, key, 0, 11);
3078     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS, "touch Carss");
3079
3080     testHarness.time_travel(12);
3081     wait_for_flusher_to_settle(h, h1);
3082
3083     // Store a dummy item since we do not purge the item with highest seqno
3084     check(ENGINE_SUCCESS ==
3085             store(h, h1, NULL, OPERATION_SET, "dummykey", "dummyvalue", &itm,
3086                 0, 0, 0), "Error setting.");
3087
3088     wait_for_flusher_to_settle(h, h1);
3089
3090     check(get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno") == 0,
3091             "purge_seqno not found to be zero before compaction");
3092
3093     // Compaction on VBucket
3094     compact_db(h, h1, 0, 2, 3, 1);
3095
3096     check(get_int_stat(h, h1, "ep_pending_compactions") == 0,
3097     "ep_pending_compactions stat did not tick down after compaction command");
3098
3099     // the key tree and its value should be intact...
3100     check(verify_key(h, h1, "trees") == ENGINE_SUCCESS,
3101           "key trees should be found.");
3102     // the key Carrs should have disappeared...
3103     int val = verify_key(h, h1, "Carss");
3104     check(val == ENGINE_KEY_ENOENT, "Key Carss has not expired.");
3105
3106     check(get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno") == 4,
3107         "purge_seqno didn't match expected value");
3108
3109     return SUCCESS;
3110 }
3111
3112 static enum test_result test_compaction_config(ENGINE_HANDLE *h,
3113                                                ENGINE_HANDLE_V1 *h1) {
3114
3115     check(get_int_stat(h, h1, "ep_compaction_write_queue_cap") == 10000,
3116             "Expected compaction queue cap to be 10000");
3117     set_param(h, h1, protocol_binary_engine_param_flush,
3118               "compaction_write_queue_cap", "100000");
3119     check(get_int_stat(h, h1, "ep_compaction_write_queue_cap") == 100000,
3120             "Expected compaction queue cap to be 100000");
3121     return SUCCESS;
3122 }
3123
3124 struct comp_thread_ctx {
3125     ENGINE_HANDLE *h;
3126     ENGINE_HANDLE_V1 *h1;
3127     uint16_t vbid;
3128 };
3129
3130 extern "C" {
3131     static void compaction_thread(void *arg) {
3132         struct comp_thread_ctx *ctx = static_cast<comp_thread_ctx *>(arg);
3133         compact_db(ctx->h, ctx->h1, ctx->vbid, 0, 0, 0);
3134     }
3135 }
3136
3137 static enum test_result test_multiple_vb_compactions(ENGINE_HANDLE *h,
3138                                                      ENGINE_HANDLE_V1 *h1) {
3139     for (uint16_t i = 0; i < 4; ++i) {
3140         if (!set_vbucket_state(h, h1, i, vbucket_state_active)) {
3141             fprintf(stderr, "set state failed for vbucket %d.\n", i);
3142             return FAIL;
3143         }
3144         check(verify_vbucket_state(h, h1, i, vbucket_state_active),
3145               "VBucket state not active");
3146     }
3147
3148     std::vector<std::string> keys;
3149     for (int j = 0; j < 20000; ++j) {
3150         std::stringstream ss;
3151         ss << "key" << j;
3152         std::string key(ss.str());
3153         keys.push_back(key);
3154     }
3155
3156     int count = 0;
3157     std::vector<std::string>::iterator it;
3158     for (it = keys.begin(); it != keys.end(); ++it) {
3159         uint16_t vbid = count % 4;
3160         item *i;
3161         check(store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(), &i, 0, vbid)
3162               == ENGINE_SUCCESS, "Failed to store a value");
3163         h1->release(h, NULL, i);
3164         ++count;
3165     }
3166
3167     // Compact multiple vbuckets.
3168     const int n_threads = 4;
3169     cb_thread_t threads[n_threads];
3170     struct comp_thread_ctx ctx[n_threads];
3171
3172     for (int i = 0; i < n_threads; i++) {
3173         ctx[i].h = h;
3174         ctx[i].h1 = h1;
3175         ctx[i].vbid = static_cast<uint16_t>(i);
3176         int r = cb_create_thread(&threads[i], compaction_thread, &ctx[i], 0);
3177         cb_assert(r == 0);
3178     }
3179
3180     for (int i = 0; i < n_threads; i++) {
3181         int r = cb_join_thread(threads[i]);
3182         cb_assert(r == 0);
3183     }
3184
3185     check(get_int_stat(h, h1, "ep_pending_compactions") == 0,
3186     "ep_pending_compactions stat did not tick down after compaction command");
3187
3188     return SUCCESS;
3189 }
3190
3191 static enum test_result
3192 test_multi_vb_compactions_with_workload(ENGINE_HANDLE *h,
3193                                         ENGINE_HANDLE_V1 *h1) {
3194     for (uint16_t i = 0; i < 4; ++i) {
3195         if (!set_vbucket_state(h, h1, i, vbucket_state_active)) {
3196             fprintf(stderr, "set state failed for vbucket %d.\n", i);
3197             return FAIL;
3198         }
3199         check(verify_vbucket_state(h, h1, i, vbucket_state_active),
3200               "VBucket state not active");
3201     }
3202
3203     std::vector<std::string> keys;
3204     for (int j = 0; j < 10000; ++j) {
3205         std::stringstream ss;
3206         ss << "key" << j;
3207         std::string key(ss.str());
3208         keys.push_back(key);
3209     }
3210
3211     int count = 0;
3212     std::vector<std::string>::iterator it;
3213     for (it = keys.begin(); it != keys.end(); ++it) {
3214         uint16_t vbid = count % 4;
3215         item *i;
3216         check(store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(), &i, 0, vbid)
3217               == ENGINE_SUCCESS, "Failed to store a value");
3218         h1->release(h, NULL, i);
3219         ++count;
3220     }
3221     wait_for_flusher_to_settle(h, h1);
3222
3223     for (int i = 0; i < 2; ++i) {
3224         count = 0;
3225         for (it = keys.begin(); it != keys.end(); ++it) {
3226             uint16_t vbid = count % 4;
3227             item *i = NULL;
3228             check(h1->get(h, NULL, &i, it->c_str(), strlen(it->c_str()), vbid) ==
3229                   ENGINE_SUCCESS, "Unable to get stored item");
3230             h1->release(h, NULL, i);
3231             ++count;
3232         }
3233     }
3234     wait_for_str_stat_to_be(h, h1, "ep_workload_pattern", "read_heavy", NULL);
3235
3236     // Compact multiple vbuckets.
3237     const int n_threads = 4;
3238     cb_thread_t threads[n_threads];
3239     struct comp_thread_ctx ctx[n_threads];
3240
3241     for (int i = 0; i < n_threads; i++) {
3242         ctx[i].h = h;
3243         ctx[i].h1 = h1;
3244         ctx[i].vbid = static_cast<uint16_t>(i);
3245         int r = cb_create_thread(&threads[i], compaction_thread, &ctx[i], 0);
3246         cb_assert(r == 0);
3247     }
3248
3249     for (int i = 0; i < n_threads; i++) {
3250         int r = cb_join_thread(threads[i]);
3251         cb_assert(r == 0);
3252     }
3253
3254     check(get_int_stat(h, h1, "ep_pending_compactions") == 0,
3255     "ep_pending_compactions stat did not tick down after compaction command");
3256
3257     return SUCCESS;
3258 }
3259
3260 static enum test_result vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
3261                                              const char* value = NULL) {
3262     check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed to set vbucket state.");
3263
3264     vbucketDelete(h, h1, 2, value);
3265     check(last_status == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
3266           "Expected failure deleting non-existent bucket.");
3267
3268     check(set_vbucket_state(h, h1, 1, vbucket_state_dead), "Failed set set vbucket 1 state.");
3269
3270     vbucketDelete(h, h1, 1, value);
3271     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
3272           "Expected failure deleting non-existent bucket.");
3273
3274     check(verify_vbucket_missing(h, h1, 1),
3275           "vbucket 0 was not missing after deleting it.");
3276
3277     return SUCCESS;
3278 }
3279
3280 static enum test_result test_vbucket_destroy_stats(ENGINE_HANDLE *h,
3281                                                    ENGINE_HANDLE_V1 *h1) {
3282
3283     int cacheSize = get_int_stat(h, h1, "ep_total_cache_size");
3284     int overhead = get_int_stat(h, h1, "ep_overhead");
3285     int nonResident = get_int_stat(h, h1, "ep_num_non_resident");
3286
3287     check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed to set vbucket state.");
3288
3289     std::vector<std::string> keys;
3290     for (int j = 0; j < 2000; ++j) {
3291         std::stringstream ss;
3292         ss << "key" << j;
3293         std::string key(ss.str());
3294         keys.push_back(key);
3295     }
3296
3297     int itemsRemoved = get_int_stat(h, h1, "ep_items_rm_from_checkpoints");
3298     std::vector<std::string>::iterator it;
3299     for (it = keys.begin(); it != keys.end(); ++it) {
3300         item *i;
3301         check(store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(), &i, 0, 1)
3302               == ENGINE_SUCCESS, "Failed to store a value");
3303         h1->release(h, NULL, i);
3304     }
3305     wait_for_flusher_to_settle(h, h1);
3306     testHarness.time_travel(65);
3307     wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
3308
3309     check(set_vbucket_state(h, h1, 1, vbucket_state_dead), "Failed set set vbucket 1 state.");
3310
3311     int vbucketDel = get_int_stat(h, h1, "ep_vbucket_del");
3312     vbucketDelete(h, h1, 1);
3313     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
3314           "Expected failure deleting non-existent bucket.");
3315
3316     check(verify_vbucket_missing(h, h1, 1),
3317           "vbucket 1 was not missing after deleting it.");
3318
3319     wait_for_stat_change(h, h1, "ep_vbucket_del", vbucketDel);
3320
3321     wait_for_stat_to_be(h, h1, "ep_total_cache_size", cacheSize);
3322     wait_for_stat_to_be(h, h1, "ep_overhead", overhead);
3323     wait_for_stat_to_be(h, h1, "ep_num_non_resident", nonResident);
3324
3325     return SUCCESS;
3326 }
3327
3328 static enum test_result vbucket_destroy_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
3329                                                 const char* value = NULL) {
3330     check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed to set vbucket state.");
3331
3332     // Store a value so the restart will try to resurrect it.
3333     item *i = NULL;
3334     check(store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i, 0, 1)
3335           == ENGINE_SUCCESS, "Failed to set a value");
3336     check_key_value(h, h1, "key", "somevalue", 9, 1);
3337     h1->release(h, NULL, i);
3338
3339     // Reload to get a flush forced.
3340     testHarness.reload_engine(&h, &h1,
3341                               testHarness.engine_path,
3342                               testHarness.get_current_testcase()->cfg,
3343                               true, false);
3344     wait_for_warmup_complete(h, h1);
3345
3346     check(verify_vbucket_state(h, h1, 1, vbucket_state_active),
3347           "Bucket state was what it was initially, after restart.");
3348     check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed to set vbucket state.");
3349     check_key_value(h, h1, "key", "somevalue", 9, 1);
3350
3351     check(set_vbucket_state(h, h1, 1, vbucket_state_dead), "Failed set set vbucket 1 state.");
3352
3353     vbucketDelete(h, h1, 1, value);
3354     check(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS,
3355           "Expected failure deleting non-existent bucket.");
3356
3357     check(verify_vbucket_missing(h, h1, 1),
3358           "vbucket 1 was not missing after deleting it.");
3359
3360     testHarness.reload_engine(&h, &h1,
3361                               testHarness.engine_path,
3362                               testHarness.get_current_testcase()->cfg,
3363                               true, false);
3364     wait_for_warmup_complete(h, h1);
3365
3366     if (verify_vbucket_state(h, h1, 1, vbucket_state_pending, true)) {
3367         std::cerr << "Bucket came up in pending state after delete." << std::endl;
3368         abort();
3369     }
3370
3371     check(verify_vbucket_missing(h, h1, 1),
3372           "vbucket 1 was not missing after restart.");
3373
3374     return SUCCESS;
3375 }
3376
3377 static enum test_result test_async_vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3378     return vbucket_destroy(h, h1);
3379 }
3380
3381 static enum test_result test_sync_vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3382     return vbucket_destroy(h, h1, "async=0");
3383 }
3384
3385 static enum test_result test_async_vbucket_destroy_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3386     return vbucket_destroy_restart(h, h1);
3387 }
3388
3389 static enum test_result test_sync_vbucket_destroy_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3390     return vbucket_destroy_restart(h, h1, "async=0");
3391 }
3392
3393 static enum test_result test_vb_set_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3394     return test_pending_vb_mutation(h, h1, OPERATION_SET);
3395 }
3396
3397 static enum test_result test_vb_add_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3398     return test_pending_vb_mutation(h, h1, OPERATION_ADD);
3399 }
3400
3401 static enum test_result test_vb_cas_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3402     return test_pending_vb_mutation(h, h1, OPERATION_CAS);
3403 }
3404
3405 static enum test_result test_vb_append_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3406     return test_pending_vb_mutation(h, h1, OPERATION_APPEND);
3407 }
3408
3409 static enum test_result test_vb_prepend_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3410     return test_pending_vb_mutation(h, h1, OPERATION_PREPEND);
3411 }
3412
3413 static enum test_result test_vb_set_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3414     return test_replica_vb_mutation(h, h1, OPERATION_SET);
3415 }
3416
3417 static enum test_result test_vb_replace_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3418     return test_replica_vb_mutation(h, h1, OPERATION_REPLACE);
3419 }
3420
3421 static enum test_result test_vb_replace_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3422     return test_pending_vb_mutation(h, h1, OPERATION_REPLACE);
3423 }
3424
3425 static enum test_result test_vb_add_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3426     return test_replica_vb_mutation(h, h1, OPERATION_ADD);
3427 }
3428
3429 static enum test_result test_vb_cas_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3430     return test_replica_vb_mutation(h, h1, OPERATION_CAS);
3431 }
3432
3433 static enum test_result test_vb_append_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3434     return test_replica_vb_mutation(h, h1, OPERATION_APPEND);
3435 }
3436
3437 static enum test_result test_vb_prepend_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3438     return test_replica_vb_mutation(h, h1, OPERATION_PREPEND);
3439 }
3440
3441 static enum test_result test_stats_seqno(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3442     check(set_vbucket_state(h, h1, 1, vbucket_state_active),
3443           "Failed to set vbucket state.");
3444
3445     int num_keys = 100;
3446     for (int ii = 0; ii < num_keys; ++ii) {
3447         std::stringstream ss;
3448         ss << "key" << ii;
3449         check(store(h, h1, NULL, OPERATION_SET, ss.str().c_str(),
3450                     "value", NULL, 0, 0) == ENGINE_SUCCESS,
3451               "Failed to store an item.");
3452     }
3453
3454     check(get_int_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno") == 100,
3455           "Invalid seqno");
3456     check(get_int_stat(h, h1, "vb_1:high_seqno", "vbucket-seqno") == 0,
3457           "Invalid seqno");
3458     check(get_int_stat(h, h1, "vb_1:high_seqno", "vbucket-seqno 1") == 0,
3459           "Invalid seqno");
3460
3461     uint64_t vb_uuid = get_ull_stat(h, h1, "vb_1:0:id", "failovers");
3462     check(get_ull_stat(h, h1, "vb_1:uuid", "vbucket-seqno 1") == vb_uuid,
3463           "Invalid uuid");
3464     check(vals.size() == 4, "Expected four stats");
3465
3466     // Check invalid vbucket
3467     check(h1->get_stats(h, NULL, "vbucket-seqno 2", 15, add_stats)
3468           == ENGINE_NOT_MY_VBUCKET, "Expected not my vbucket");
3469
3470     // Check bad vbucket parameter (not numeric)
3471     check(h1->get_stats(h, NULL, "vbucket-seqno tt2", 17, add_stats)
3472           == ENGINE_EINVAL, "Expected invalid");
3473
3474     // Check extra spaces at the end
3475     check(h1->get_stats(h, NULL, "vbucket-seqno    ", 17, add_stats)
3476           == ENGINE_EINVAL, "Expected invalid");
3477
3478     return SUCCESS;
3479 }
3480
3481 static enum test_result test_stats_diskinfo(ENGINE_HANDLE *h,
3482                                             ENGINE_HANDLE_V1 *h1) {
3483     check(set_vbucket_state(h, h1, 1, vbucket_state_active),
3484           "Failed to set vbucket state.");
3485
3486     int num_keys = 100;
3487     for (int ii = 0; ii < num_keys; ++ii) {
3488         std::stringstream ss;
3489         ss << "key" << ii;
3490         check(store(h, h1, NULL, OPERATION_SET, ss.str().c_str(),
3491                     "value", NULL, 0, 1) == ENGINE_SUCCESS,
3492               "Failed to store an item.");
3493     }
3494     wait_for_flusher_to_settle(h, h1);
3495
3496     size_t file_size = get_int_stat(h, h1, "ep_db_file_size", "diskinfo");
3497     size_t data_size = get_int_stat(h, h1, "ep_db_data_size", "diskinfo");
3498     check(file_size > 0, "DB file size should be greater than 0");
3499     check(data_size > 0, "DB data size should be greater than 0");
3500     check(file_size >= data_size, "DB file size should be >= DB data size");
3501  &nbs