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