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