179a9d87dSDavid Liao/* -*- MODE: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2ba5b814bSMatt Ingenthron/*
366eb94d0SMike Wiederhold *     Copyright 2010 Couchbase, Inc
4ba5b814bSMatt Ingenthron *
5ba5b814bSMatt Ingenthron *   Licensed under the Apache License, Version 2.0 (the "License");
6ba5b814bSMatt Ingenthron *   you may not use this file except in compliance with the License.
7ba5b814bSMatt Ingenthron *   You may obtain a copy of the License at
8ba5b814bSMatt Ingenthron *
9ba5b814bSMatt Ingenthron *       http://www.apache.org/licenses/LICENSE-2.0
10ba5b814bSMatt Ingenthron *
11ba5b814bSMatt Ingenthron *   Unless required by applicable law or agreed to in writing, software
1290a18674STrond Norbye *   distributed under the License is distributed on an "AS IS" BASIS,
1390a18674STrond Norbye *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14ba5b814bSMatt Ingenthron *   See the License for the specific language governing permissions and
15ba5b814bSMatt Ingenthron *   limitations under the License.
16ba5b814bSMatt Ingenthron */
17244c0146SMike Wiederhold
18b554d6e1Sabhinavdangeti// Usage: (to run just a single test case)
19b554d6e1Sabhinavdangeti// make engine_tests EP_TEST_NUM=3
20225850baSSundar Sridharan
215f546033STrond Norbye#include "config.h"
228e20ce5eSDustin Sallings
236a56cf03SSean Lynch#include <stdio.h>
2453e068aeSDustin Sallings#include <stdlib.h>
2553e068aeSDustin Sallings#include <string.h>
2683d115deSabhinavdangeti
27b298b60fSDave Rigby#include <chrono>
28e9a655b4SDaniel Owen#include <condition_variable>
29244c0146SMike Wiederhold#include <cstdlib>
300437adf6SDave Rigby#include <iomanip>
31b298b60fSDave Rigby#include <iostream>
32244c0146SMike Wiederhold#include <map>
33e9a655b4SDaniel Owen#include <mutex>
34b298b60fSDave Rigby#include <regex>
35ed729846SMike Wiederhold#include <set>
36244c0146SMike Wiederhold#include <sstream>
37244c0146SMike Wiederhold#include <string>
38e9a655b4SDaniel Owen#include <thread>
39cdfef387SDave Rigby#include <unordered_map>
40f3c370caSJim Walker#include <unordered_set>
41244c0146SMike Wiederhold#include <vector>
426a56cf03SSean Lynch
43fc9615cdSMike Wiederhold#include "atomic.h"
4445fa1633SDave Rigby#include "couch-kvstore/couch-kvstore-metadata.h"
45ccdfed7dSMike Wiederhold#include "ep_test_apis.h"
46bd6514a7SDave Rigby
47bd6514a7SDave Rigby#include "ep_testsuite_common.h"
48244c0146SMike Wiederhold#include "locks.h"
49238f579dSJim Walker#include <libcouchstore/couch_db.h>
50bd6514a7SDave Rigby#include <memcached/engine.h>
51bd6514a7SDave Rigby#include <memcached/engine_testapp.h>
520d150516SDave Rigby#include <platform/cb_malloc.h>
535fe4831eSDave Rigby#include <platform/dirutils.h>
54c8f54d3eSabhinavdangeti#include <JSON_checker.h>
55b2c84d53STrond Norbye#include <memcached/types.h>
56f9ae921eSSriram Ganesan#include <string_utilities.h>
57110df6adSTrond Norbye#include <xattr/blob.h>
58f9ae921eSSriram Ganesan#include <xattr/utils.h>
5982a6f303Sabhinavdangeti
60aa83d3a0SDustin Sallings#ifdef linux
61aa83d3a0SDustin Sallings/* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
62aa83d3a0SDustin Sallings * optimize the conversion functions, but the prototypes generate warnings
63aa83d3a0SDustin Sallings * from gcc. The conversion methods isn't the bottleneck for my app, so
64aa83d3a0SDustin Sallings * just remove the warnings by undef'ing the optimization ..
65aa83d3a0SDustin Sallings */
66aa83d3a0SDustin Sallings#undef ntohs
67aa83d3a0SDustin Sallings#undef ntohl
68aa83d3a0SDustin Sallings#undef htons
69aa83d3a0SDustin Sallings#undef htonl
70aa83d3a0SDustin Sallings#endif
71aa83d3a0SDustin Sallings
72da3303e4STrond Norbye// ptr_fun don't like the extern "C" thing for unlock cookie.. cast it
73da3303e4STrond Norbye// away ;)
74da3303e4STrond Norbyetypedef void (*UNLOCK_COOKIE_T)(const void *cookie);
75418b8d81SChiyoung Seo
76f5613908SDustin Sallingsclass ThreadData {
77f5613908SDustin Sallingspublic:
787d42f348SDustin Sallings    ThreadData(ENGINE_HANDLE *eh, ENGINE_HANDLE_V1 *ehv1,
797d42f348SDustin Sallings               int e=0) : h(eh), h1(ehv1), extra(e) {}
80f5613908SDustin Sallings    ENGINE_HANDLE    *h;
81f5613908SDustin Sallings    ENGINE_HANDLE_V1 *h1;
827d42f348SDustin Sallings    int               extra;
83f5613908SDustin Sallings};
84f5613908SDustin Sallings
85c90c9af9SDave Rigbyenum class BucketType { EP, Ephemeral };
86c90c9af9SDave Rigby
87c90c9af9SDave Rigbystatic void check_observe_seqno(bool failover,
88c90c9af9SDave Rigby                                BucketType bucket_type,
89c90c9af9SDave Rigby                                uint8_t format_type,
90c90c9af9SDave Rigby                                uint16_t vb_id,
91c90c9af9SDave Rigby                                uint64_t vb_uuid,
92c90c9af9SDave Rigby                                uint64_t last_persisted_seqno,
93c90c9af9SDave Rigby                                uint64_t current_seqno,
94c90c9af9SDave Rigby                                uint64_t failover_vbuuid = 0,
95f062a5b7SSriram Ganesan                                uint64_t failover_seqno = 0) {
96c90c9af9SDave Rigby    uint8_t recv_format_type;
97f062a5b7SSriram Ganesan    uint16_t recv_vb_id;
98f062a5b7SSriram Ganesan    uint64_t recv_vb_uuid;
99f062a5b7SSriram Ganesan    uint64_t recv_last_persisted_seqno;
100f062a5b7SSriram Ganesan    uint64_t recv_current_seqno;
101f062a5b7SSriram Ganesan    uint64_t recv_failover_vbuuid;
102f062a5b7SSriram Ganesan    uint64_t recv_failover_seqno;
103f062a5b7SSriram Ganesan
104c94aa0d8SDave Rigby    memcpy(&recv_format_type, last_body.data(), sizeof(uint8_t));
105df27e4e3Sabhinavdangeti    checkeq(format_type, recv_format_type, "Wrong format type in result");
106c94aa0d8SDave Rigby    memcpy(&recv_vb_id, last_body.data() + 1, sizeof(uint16_t));
107df27e4e3Sabhinavdangeti    checkeq(vb_id, ntohs(recv_vb_id), "Wrong vbucket id in result");
108c94aa0d8SDave Rigby    memcpy(&recv_vb_uuid, last_body.data() + 3, sizeof(uint64_t));
109df27e4e3Sabhinavdangeti    checkeq(vb_uuid, ntohll(recv_vb_uuid), "Wrong vbucket uuid in result");
110c94aa0d8SDave Rigby    memcpy(&recv_last_persisted_seqno, last_body.data() + 11, sizeof(uint64_t));
111c90c9af9SDave Rigby
112c90c9af9SDave Rigby    switch (bucket_type) {
113c90c9af9SDave Rigby    case BucketType::EP:
114c90c9af9SDave Rigby        // Should get the "real" persisted seqno:
115c90c9af9SDave Rigby        checkeq(last_persisted_seqno,
116c90c9af9SDave Rigby                ntohll(recv_last_persisted_seqno),
117c90c9af9SDave Rigby                "Wrong persisted seqno in result (EP)");
118c90c9af9SDave Rigby        break;
119c90c9af9SDave Rigby    case BucketType::Ephemeral:
120c90c9af9SDave Rigby        // For ephemeral, this should always be zero, as there is no
121c90c9af9SDave Rigby        // persistence.
122c90c9af9SDave Rigby        checkeq(uint64_t(0),
123c90c9af9SDave Rigby                ntohll(recv_last_persisted_seqno),
124c90c9af9SDave Rigby                "Wrong persisted seqno in result (Ephemeral)");
125c90c9af9SDave Rigby        break;
126c90c9af9SDave Rigby    }
127c90c9af9SDave Rigby
128c94aa0d8SDave Rigby    memcpy(&recv_current_seqno, last_body.data() + 19, sizeof(uint64_t));
129df27e4e3Sabhinavdangeti    checkeq(current_seqno, ntohll(recv_current_seqno), "Wrong current seqno in result");
130f062a5b7SSriram Ganesan
131f062a5b7SSriram Ganesan    if (failover) {
132c94aa0d8SDave Rigby        memcpy(&recv_failover_vbuuid, last_body.data() + 27, sizeof(uint64_t));
133df27e4e3Sabhinavdangeti        checkeq(failover_vbuuid, ntohll(recv_failover_vbuuid),
134df27e4e3Sabhinavdangeti                "Wrong failover uuid in result");
135c94aa0d8SDave Rigby        memcpy(&recv_failover_seqno, last_body.data() + 35, sizeof(uint64_t));
136df27e4e3Sabhinavdangeti        checkeq(failover_seqno, ntohll(recv_failover_seqno),
137df27e4e3Sabhinavdangeti                "Wrong failover seqno in result");
138f062a5b7SSriram Ganesan    }
139f062a5b7SSriram Ganesan}
140f062a5b7SSriram Ganesan
1411d92be04SDave Rigbystatic enum test_result test_replace_with_eviction(ENGINE_HANDLE *h,
1421d92be04SDave Rigby                                                   ENGINE_HANDLE_V1 *h1) {
143df27e4e3Sabhinavdangeti    checkeq(ENGINE_SUCCESS,
144d8de1991SDave Rigby            store(h, h1, NULL, OPERATION_SET, "key", "somevalue"),
1451d92be04SDave Rigby            "Failed to set value.");
14683d115deSabhinavdangeti    wait_for_flusher_to_settle(h, h1);
1471d92be04SDave Rigby    evict_key(h, h1, "key");
1481d92be04SDave Rigby    int numBgFetched = get_int_stat(h, h1, "ep_bg_fetched");
149d9d123f4SJunyi Xie
150df27e4e3Sabhinavdangeti    checkeq(ENGINE_SUCCESS,
151d8de1991SDave Rigby            store(h, h1, NULL, OPERATION_REPLACE, "key", "somevalue1"),
1521d92be04SDave Rigby            "Failed to replace existing value.");
15346774481STrond Norbye
154df27e4e3Sabhinavdangeti    checkeq(ENGINE_SUCCESS,
155f9c178f3STrond Norbye            get_stats(h, {}, add_stats),
1561d92be04SDave Rigby            "Failed to get stats.");
1571d92be04SDave Rigby    std::string eviction_policy = vals.find("ep_item_eviction_policy")->second;
1581d92be04SDave Rigby    if (eviction_policy == "full_eviction") {
1591d92be04SDave Rigby        numBgFetched++;
1601d92be04SDave Rigby    }
1611553f495SJin Lim
1621d92be04SDave Rigby    checkeq(numBgFetched,
1631d92be04SDave Rigby            get_int_stat(h, h1, "ep_bg_fetched"),
1641d92be04SDave Rigby            "Bg fetched value didn't match");
165d9d123f4SJunyi Xie
1661d92be04SDave Rigby    check_key_value(h, h1, "key", "somevalue1", 10);
167d9d123f4SJunyi Xie    return SUCCESS;
168d9d123f4SJunyi Xie}
169d9d123f4SJunyi Xie
1701d92be04SDave Rigbystatic enum test_result test_wrong_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
1711d92be04SDave Rigby                                               ENGINE_STORE_OPERATION op) {
1721d92be04SDave Rigby    int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
1731d92be04SDave Rigby    uint64_t cas = 11;
1741d92be04SDave Rigby    if (op == OPERATION_ADD) {
1751d92be04SDave Rigby        // Add operation with cas != 0 doesn't make sense
1761d92be04SDave Rigby        cas = 0;
1771d92be04SDave Rigby    }
1781d92be04SDave Rigby    checkeq(ENGINE_NOT_MY_VBUCKET,
179d8de1991SDave Rigby            store(h, h1, NULL, op, "key", "somevalue", nullptr, cas, 1),
1801d92be04SDave Rigby            "Expected not_my_vbucket");
1811d92be04SDave Rigby    wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
182d63de529SChiyoung Seo    return SUCCESS;
183d63de529SChiyoung Seo}
184d63de529SChiyoung Seo
1851d92be04SDave Rigbystatic enum test_result test_pending_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
1861d92be04SDave Rigby                                                 ENGINE_STORE_OPERATION op) {
1871d92be04SDave Rigby    const void *cookie = testHarness.create_cookie();
1881d92be04SDave Rigby    testHarness.set_ewouldblock_handling(cookie, false);
1891d92be04SDave Rigby    check(set_vbucket_state(h, h1, 1, vbucket_state_pending),
190df27e4e3Sabhinavdangeti          "Failed to set vbucket state.");
1911d92be04SDave Rigby    check(verify_vbucket_state(h, h1, 1, vbucket_state_pending),
1921d92be04SDave Rigby          "Bucket state was not set to pending.");
1931d92be04SDave Rigby    uint64_t cas = 11;
1941d92be04SDave Rigby    if (op == OPERATION_ADD) {
1951d92be04SDave Rigby        // Add operation with cas != 0 doesn't make sense..
1961d92be04SDave Rigby        cas = 0;
1971d92be04SDave Rigby    }
1981d92be04SDave Rigby    checkeq(ENGINE_EWOULDBLOCK,
199d8de1991SDave Rigby            store(h, h1, cookie, op, "key", "somevalue", nullptr, cas, 1),
2001d92be04SDave Rigby            "Expected ewouldblock");
2011d92be04SDave Rigby    testHarness.destroy_cookie(cookie);
2021d92be04SDave Rigby    return SUCCESS;
2031d92be04SDave Rigby}
2047d515e64SDustin Sallings
2051d92be04SDave Rigbystatic enum test_result test_replica_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
2061d92be04SDave Rigby                                                 ENGINE_STORE_OPERATION op) {
2071d92be04SDave Rigby    check(set_vbucket_state(h, h1, 1, vbucket_state_replica),
2081d92be04SDave Rigby          "Failed to set vbucket state.");
2091d92be04SDave Rigby    check(verify_vbucket_state(h, h1, 1, vbucket_state_replica),
2101d92be04SDave Rigby          "Bucket state was not set to replica.");
2111d92be04SDave Rigby    int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
2127d515e64SDustin Sallings
2131d92be04SDave Rigby    uint64_t cas = 11;
2141d92be04SDave Rigby    if (op == OPERATION_ADD) {
2151d92be04SDave Rigby        // performing add with a CAS != 0 doesn't make sense...
2161d92be04SDave Rigby        cas = 0;
2171d92be04SDave Rigby    }
2181d92be04SDave Rigby    checkeq(ENGINE_NOT_MY_VBUCKET,
219d8de1991SDave Rigby            store(h, h1, NULL, op, "key", "somevalue", nullptr, cas, 1),
2201d92be04SDave Rigby            "Expected not my vbucket");
2211d92be04SDave Rigby    wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
2227d515e64SDustin Sallings    return SUCCESS;
2237d515e64SDustin Sallings}
2247d515e64SDustin Sallings
2251d92be04SDave Rigby//
2261d92be04SDave Rigby// ----------------------------------------------------------------------
2271d92be04SDave Rigby// The actual tests are below.
2281d92be04SDave Rigby// ----------------------------------------------------------------------
2291d92be04SDave Rigby//
2301d92be04SDave Rigby
231edafd1b2SJin Limstatic int checkCurrItemsAfterShutdown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
232edafd1b2SJin Lim                                       int numItems2Load, bool shutdownForce) {
2335163fad1SDave Rigby    if (!isWarmupEnabled(h, h1)) {
2345163fad1SDave Rigby        return SKIPPED;
2355163fad1SDave Rigby    }
2365163fad1SDave Rigby
237edafd1b2SJin Lim    std::vector<std::string> keys;
238edafd1b2SJin Lim    for (int index = 0; index < numItems2Load; ++index) {
239edafd1b2SJin Lim        std::stringstream s;
240edafd1b2SJin Lim        s << "keys_2_load-" << index;
241edafd1b2SJin Lim        std::string key(s.str());
242edafd1b2SJin Lim        keys.push_back(key);
243edafd1b2SJin Lim    }
244edafd1b2SJin Lim
245526b3f4eSDave Rigby    // Check preconditions.
246df27e4e3Sabhinavdangeti    checkeq(0, get_int_stat(h, h1, "ep_total_persisted"),
247df27e4e3Sabhinavdangeti            "Expected ep_total_persisted equals 0");
248df27e4e3Sabhinavdangeti    checkeq(0, get_int_stat(h, h1, "curr_items"),
249df27e4e3Sabhinavdangeti            "Expected curr_items equals 0");
250edafd1b2SJin Lim
251edafd1b2SJin Lim    // stop flusher before loading new items
2520389c521STrond Norbye    protocol_binary_request_header *pkt = createPacket(PROTOCOL_BINARY_CMD_STOP_PERSISTENCE);
253df27e4e3Sabhinavdangeti    checkeq(ENGINE_SUCCESS,
2547515175cSJim Walker            h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
255df27e4e3Sabhinavdangeti            "CMD_STOP_PERSISTENCE failed!");
256df27e4e3Sabhinavdangeti    checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS,
257df27e4e3Sabhinavdangeti            last_status.load(),
258df27e4e3Sabhinavdangeti            "Failed to stop persistence!");
2590d150516SDave Rigby    cb_free(pkt);
260edafd1b2SJin Lim
261edafd1b2SJin Lim    std::vector<std::string>::iterator itr;
262edafd1b2SJin Lim    for (itr = keys.begin(); itr != keys.end(); ++itr) {
263df27e4e3Sabhinavdangeti        checkeq(ENGINE_SUCCESS,
264d8de1991SDave Rigby                store(h, h1, NULL, OPERATION_SET, itr->c_str(), "oracle"),
265df27e4e3Sabhinavdangeti                "Failed to store a value");
266edafd1b2SJin Lim    }
267edafd1b2SJin Lim
268df27e4e3Sabhinavdangeti    checkeq(0, get_int_stat(h, h1, "ep_total_persisted"),
269df27e4e3Sabhinavdangeti            "Incorrect ep_total_persisted, expected 0");
270526b3f4eSDave Rigby
271526b3f4eSDave Rigby    // Can only check curr_items in value_only eviction; full-eviction
272526b3f4eSDave Rigby    // relies on persistence to complete (via flusher) to update count.
273526b3f4eSDave Rigby    const auto evictionPolicy = get_str_stat(h, h1, "ep_item_eviction_policy");
274526b3f4eSDave Rigby    if (evictionPolicy == "value_only") {
275526b3f4eSDave Rigby        checkeq(numItems2Load,
276526b3f4eSDave Rigby                get_int_stat(h, h1, "curr_items"),
277526b3f4eSDave Rigby                "Expected curr_items to reflect item count");
278526b3f4eSDave Rigby    }
279edafd1b2SJin Lim
280edafd1b2SJin Lim    // resume flusher before shutdown + warmup
2810389c521STrond Norbye    pkt = createPacket(PROTOCOL_BINARY_CMD_START_PERSISTENCE);
2827515175cSJim Walker    checkeq(ENGINE_SUCCESS, h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
283df27e4e3Sabhinavdangeti            "CMD_START_PERSISTENCE failed!");
284df27e4e3Sabhinavdangeti    checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
2853b9a12eaSSundar Sridharan          "Failed to start persistence!");
2860d150516SDave Rigby    cb_free(pkt);
287edafd1b2SJin Lim
288edafd1b2SJin Lim    // shutdown engine force and restart
289edafd1b2SJin Lim    testHarness.reload_engine(&h, &h1,
290edafd1b2SJin Lim                              testHarness.engine_path,
291edafd1b2SJin Lim                              testHarness.get_current_testcase()->cfg,
292edafd1b2SJin Lim                              true, shutdownForce);
293edafd1b2SJin Lim    wait_for_warmup_complete(h, h1);
294edafd1b2SJin Lim    return get_int_stat(h, h1, "curr_items");
295edafd1b2SJin Lim}
296edafd1b2SJin Lim
297edafd1b2SJin Limstatic enum test_result test_flush_shutdown_force(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2985163fad1SDave Rigby    if (!isWarmupEnabled(h, h1)) {
2995163fad1SDave Rigby        return SKIPPED;
3005163fad1SDave Rigby    }
3015163fad1SDave Rigby
302edafd1b2SJin Lim    int numItems2load = 3000;
303edafd1b2SJin Lim    bool shutdownForce = true;
304edafd1b2SJin Lim    int currItems = checkCurrItemsAfterShutdown(h, h1, numItems2load, shutdownForce);
305edafd1b2SJin Lim    check (currItems <= numItems2load,
306edafd1b2SJin Lim           "Number of curr items should be <= 3000, unless previous "
307edafd1b2SJin Lim           "shutdown force had to wait for the flusher");
308edafd1b2SJin Lim    return SUCCESS;
309edafd1b2SJin Lim}
310edafd1b2SJin Lim
311edafd1b2SJin Limstatic enum test_result test_flush_shutdown_noforce(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3125163fad1SDave Rigby    if (!isWarmupEnabled(h, h1)) {
3135163fad1SDave Rigby        return SKIPPED;
3145163fad1SDave Rigby    }
3155163fad1SDave Rigby
316edafd1b2SJin Lim    int numItems2load = 3000;
317edafd1b2SJin Lim    bool shutdownForce = false;
318edafd1b2SJin Lim    int currItems = checkCurrItemsAfterShutdown(h, h1, numItems2load, shutdownForce);
319edafd1b2SJin Lim    check (currItems == numItems2load,
320edafd1b2SJin Lim           "Number of curr items should be equal to 3000, unless previous "
321edafd1b2SJin Lim           "shutdown did not wait for the flusher");
322edafd1b2SJin Lim    return SUCCESS;
323edafd1b2SJin Lim}
324edafd1b2SJin Lim
325bd4376e1SManu Dhundistatic enum test_result test_shutdown_snapshot_range(ENGINE_HANDLE *h,
326bd4376e1SManu Dhundi                                                     ENGINE_HANDLE_V1 *h1) {
3275163fad1SDave Rigby    if (!isWarmupEnabled(h, h1)) {
3285163fad1SDave Rigby        return SKIPPED;
3295163fad1SDave Rigby    }
3305163fad1SDave Rigby
331bd4376e1SManu Dhundi    const int num_items = 100;
332bd4376e1SManu Dhundi    for (int j = 0; j < num_items; ++j) {
333bd4376e1SManu Dhundi        std::stringstream ss;
334bd4376e1SManu Dhundi        ss << "key" << j;
335bd4376e1SManu Dhundi        checkeq(ENGINE_SUCCESS,
336d8de1991SDave Rigby                store(h, h1, NULL, OPERATION_SET, ss.str().c_str(), "data"),
337bd4376e1SManu Dhundi                "Failed to store a value");
338bd4376e1SManu Dhundi    }
339bd4376e1SManu Dhundi
340bd4376e1SManu Dhundi    wait_for_flusher_to_settle(h, h1);
341bd4376e1SManu Dhundi    int end = get_int_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
342bd4376e1SManu Dhundi
343bd4376e1SManu Dhundi    /* change vb state to replica before restarting (as it happens in graceful
344bd4376e1SManu Dhundi       failover)*/
345bd4376e1SManu Dhundi    check(set_vbucket_state(h, h1, 0, vbucket_state_replica),
346bd4376e1SManu Dhundi          "Failed set vbucket 0 to replica state.");
347bd4376e1SManu Dhundi
348bd4376e1SManu Dhundi    /* trigger persist vb state task */
349bd4376e1SManu Dhundi    check(set_param(h, h1, protocol_binary_engine_param_flush,
350bd4376e1SManu Dhundi                    "vb_state_persist_run", "0"),
3511d92be04SDave Rigby          "Failed to trigger vb state persist");
352b7720fd8SChiyoung Seo
3531d92be04SDave Rigby    /* restart the engine */
354b7720fd8SChiyoung Seo    testHarness.reload_engine(&h, &h1,
355b7720fd8SChiyoung Seo                              testHarness.engine_path,
356b7720fd8SChiyoung Seo                              testHarness.get_current_testcase()->cfg,
357b7720fd8SChiyoung Seo                              true, false);
358b7720fd8SChiyoung Seo    wait_for_warmup_complete(h, h1);
359b7720fd8SChiyoung Seo
3601d92be04SDave Rigby    /* Check if snapshot range is persisted correctly */
3611d92be04SDave Rigby    checkeq(end, get_int_stat(h, h1, "vb_0:last_persisted_snap_start",
3621d92be04SDave Rigby                              "vbucket-seqno"),
3631d92be04SDave Rigby            "Wrong snapshot start persisted");
3641d92be04SDave Rigby    checkeq(end, get_int_stat(h, h1, "vb_0:last_persisted_snap_end",
3651d92be04SDave Rigby                                    "vbucket-seqno"),
3661d92be04SDave Rigby            "Wrong snapshot end persisted");
36733d09fd3SDustin Sallings
3681d92be04SDave Rigby    return SUCCESS;
3691d92be04SDave Rigby}
37033d09fd3SDustin Sallings
371873f71cdSDustin Sallingsstatic enum test_result test_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3725163fad1SDave Rigby    if (!isWarmupEnabled(h, h1)) {
3735163fad1SDave Rigby        return SKIPPED;
3745163fad1SDave Rigby    }
3755163fad1SDave Rigby
3766a56cf03SSean Lynch    static const char val[] = "somevalue";
377d8de1991SDave Rigby    ENGINE_ERROR_CODE ret = store(h, h1, NULL, OPERATION_SET, "key", val);
378df27e4e3Sabhinavdangeti    checkeq(ENGINE_SUCCESS, ret, "Failed set.");
379873f71cdSDustin Sallings
380873f71cdSDustin Sallings    testHarness.reload_engine(&h, &h1,
381873f71cdSDustin Sallings                              testHarness.engine_path,
38229097179STrond Norbye                              testHarness.get_current_testcase()->cfg,
38314cff449SChiyoung Seo                              true, false);
38480e31635SChiyoung Seo    wait_for_warmup_complete(h, h1);
38500e90515SMike Wiederhold    check_key_value(h, h1, "key", val, strlen(val));
38600e90515SMike Wiederhold    return SUCCESS;
387873f71cdSDustin Sallings}
388873f71cdSDustin Sallings
389bb7c7400SLiang Guostatic enum test_result test_specialKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
390bb7c7400SLiang Guo    ENGINE_ERROR_CODE ret;
391bb7c7400SLiang Guo
392bb7c7400SLiang Guo    // Simplified Chinese "Couchbase"
393bb7c7400SLiang Guo    static const char key0[] = "沙发数据库";
394bb7c7400SLiang Guo    static const char val0[] = "some Chinese value";
395d8de1991SDave Rigby    check((ret = store(h, h1, NULL, OPERATION_SET, key0, val0)) ==
396d8de1991SDave Rigby                  ENGINE_SUCCESS,
397bb7c7400SLiang Guo          "Failed set Chinese key");
398bb7c7400SLiang Guo    check_key_value(h, h1, key0, val0, strlen(val0));
399d8de1991SDave Rigby
400bb7c7400SLiang Guo    // Traditional Chinese "Couchbase"
401bb7c7400SLiang Guo    static const char key1[] = "沙發數據庫";
402bb7c7400SLiang Guo    static const char val1[] = "some Traditional Chinese value";
403d8de1991SDave Rigby    check((ret = store(h, h1, NULL, OPERATION_SET, key1, val1)) ==
404d8de1991SDave Rigby                  ENGINE_SUCCESS,
405bb7c7400SLiang Guo          "Failed set Traditional Chinese key");
406d8de1991SDave Rigby
407bb7c7400SLiang Guo    // Korean "couch potato"
408bb7c7400SLiang Guo    static const char key2[] = "쇼파감자";
409bb7c7400SLiang Guo    static const char val2[] = "some Korean value";
410d8de1991SDave Rigby    check((ret = store(h, h1, NULL, OPERATION_SET, key2, val2)) ==
411d8de1991SDave Rigby                  ENGINE_SUCCESS,
412bb7c7400SLiang Guo          "Failed set Korean key");
413d8de1991SDave Rigby
414bb7c7400SLiang Guo    // Russian "couch potato"
415bb7c7400SLiang Guo    static const char key3[] = "лодырь, лентяй";
416bb7c7400SLiang Guo    static const char val3[] = "some Russian value";
417d8de1991SDave Rigby    check((ret = store(h, h1, NULL, OPERATION_SET, key3, val3)) ==
418d8de1991SDave Rigby                  ENGINE_SUCCESS,
419bb7c7400SLiang Guo          "Failed set Russian key");
420d8de1991SDave Rigby
421bb7c7400SLiang Guo    // Japanese "couch potato"
422bb7c7400SLiang Guo    static const char key4[] = "カウチポテト";
423bb7c7400SLiang Guo    static const char val4[] = "some Japanese value";
424d8de1991SDave Rigby    check((ret = store(h, h1, NULL, OPERATION_SET, key4, val4)) ==
425d8de1991SDave Rigby                  ENGINE_SUCCESS,
426bb7c7400SLiang Guo          "Failed set Japanese key");
427d8de1991SDave Rigby
428bb7c7400SLiang Guo    // Indian char key, and no idea what it is
429bb7c7400SLiang Guo    static const char key5[] = "हरियानवी";
430bb7c7400SLiang Guo    static const char val5[] = "some Indian value";
431d8de1991SDave Rigby    check((ret = store(h, h1, NULL, OPERATION_SET, key5, val5)) ==
432d8de1991SDave Rigby                  ENGINE_SUCCESS,
433bb7c7400SLiang Guo          "Failed set Indian key");
434d8de1991SDave Rigby
435bb7c7400SLiang Guo    // Portuguese translation "couch potato"
436bb7c7400SLiang Guo    static const char key6[] = "sedentário";
437bb7c7400SLiang Guo    static const char val6[] = "some Portuguese value";
438d8de1991SDave Rigby    check((ret = store(h, h1, NULL, OPERATION_SET, key6, val6)) ==
439d8de1991SDave Rigby                  ENGINE_SUCCESS,
440bb7c7400SLiang Guo          "Failed set Portuguese key");
441d8de1991SDave Rigby
442bb7c7400SLiang Guo    // Arabic translation "couch potato"
443bb7c7400SLiang Guo    static const char key7[] = "الحافلةالبطاطة";
444bb7c7400SLiang Guo    static const char val7[] = "some Arabic value";
445d8de1991SDave Rigby    check((ret = store(h, h1, NULL, OPERATION_SET, key7, val7)) ==
446d8de1991SDave Rigby                  ENGINE_SUCCESS,
447bb7c7400SLiang Guo          "Failed set Arabic key");
448bb7c7400SLiang Guo
4495163fad1SDave Rigby    if (isWarmupEnabled(h, h1)) {
4505163fad1SDave Rigby        // Check that after warmup the keys are still present.
4515163fad1SDave Rigby        testHarness.reload_engine(&h, &h1,
4525163fad1SDave Rigby                                  testHarness.engine_path,
4535163fad1SDave Rigby                                  testHarness.get_current_testcase()->cfg,
4545163fad1SDave Rigby                                  true, false);
4555163fad1SDave Rigby        wait_for_warmup_complete(h, h1);
4565163fad1SDave Rigby        check_key_value(h, h1, key0, val0, strlen(val0));
4575163fad1SDave Rigby        check_key_value(h, h1, key1, val1, strlen(val1));
4585163fad1SDave Rigby        check_key_value(h, h1, key2, val2, strlen(val2));
4595163fad1SDave Rigby        check_key_value(h, h1, key3, val3, strlen(val3));
4605163fad1SDave Rigby        check_key_value(h, h1, key4, val4, strlen(val4));
4615163fad1SDave Rigby        check_key_value(h, h1, key5, val5, strlen(val5));
4625163fad1SDave Rigby        check_key_value(h, h1, key6, val6, strlen(val6));
4635163fad1SDave Rigby        check_key_value(h, h1, key7, val7, strlen(val7));
4645163fad1SDave Rigby    }
465bb7c7400SLiang Guo    return SUCCESS;
466bb7c7400SLiang Guo}
467bb7c7400SLiang Guo
468b678b170SLiang Guostatic enum test_result test_binKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
469b678b170SLiang Guo    ENGINE_ERROR_CODE ret;
470b678b170SLiang Guo
471b678b170SLiang Guo    // binary key with char values beyond 0x7F
472b678b170SLiang Guo    static const char key0[] = "\xe0\xed\xf1\x6f\x7f\xf8\xfa";
473b678b170SLiang Guo    static const char val0[] = "some value val8";
474d8de1991SDave Rigby    check((ret = store(h, h1, NULL, OPERATION_SET, key0, val0)) ==
475d8de1991SDave Rigby                  ENGINE_SUCCESS,
476b678b170SLiang Guo          "Failed set binary key0");
477b678b170SLiang Guo    check_key_value(h, h1, key0, val0, strlen(val0));
478d8de1991SDave Rigby
479b678b170SLiang Guo    // binary keys with char values beyond 0x7F
480b678b170SLiang Guo    static const char key1[] = "\xf1\xfd\xfe\xff\xf0\xf8\xef";
481b678b170SLiang Guo    static const char val1[] = "some value val9";
482d8de1991SDave Rigby    check((ret = store(h, h1, NULL, OPERATION_SET, key1, val1)) ==
483d8de1991SDave Rigby                  ENGINE_SUCCESS,
484b678b170SLiang Guo          "Failed set binary key1");
485b678b170SLiang Guo    check_key_value(h, h1, key1, val1, strlen(val1));
486d8de1991SDave Rigby
487d8de1991SDave Rigby    // binary keys with special utf-8 BOM (Byte Order Mark) values 0xBB 0xBF