16acf968bSDave Rigby/* -*- MODE: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
26acf968bSDave Rigby/*
36acf968bSDave Rigby *     Copyright 2016 Couchbase, Inc
46acf968bSDave Rigby *
56acf968bSDave Rigby *   Licensed under the Apache License, Version 2.0 (the "License");
66acf968bSDave Rigby *   you may not use this file except in compliance with the License.
76acf968bSDave Rigby *   You may obtain a copy of the License at
86acf968bSDave Rigby *
96acf968bSDave Rigby *       http://www.apache.org/licenses/LICENSE-2.0
106acf968bSDave Rigby *
116acf968bSDave Rigby *   Unless required by applicable law or agreed to in writing, software
126acf968bSDave Rigby *   distributed under the License is distributed on an "AS IS" BASIS,
136acf968bSDave Rigby *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
146acf968bSDave Rigby *   See the License for the specific language governing permissions and
156acf968bSDave Rigby *   limitations under the License.
166acf968bSDave Rigby */
176acf968bSDave Rigby
186acf968bSDave Rigby/*
196acf968bSDave Rigby * Testsuite for 'basic' key-value functionality in ep-engine.
206acf968bSDave Rigby */
216acf968bSDave Rigby
226acf968bSDave Rigby#include "config.h"
236acf968bSDave Rigby
246acf968bSDave Rigby#include "ep_test_apis.h"
256acf968bSDave Rigby#include "ep_testsuite_common.h"
266acf968bSDave Rigby
270d150516SDave Rigby#include <platform/cb_malloc.h>
286acf968bSDave Rigby#include <platform/cbassert.h>
296acf968bSDave Rigby#include <JSON_checker.h>
306acf968bSDave Rigby
3136d700b1SJim Walker#include <array>
32b2c84d53STrond Norbye#include <memcached/types.h>
336acf968bSDave Rigby
346acf968bSDave Rigby#define WHITESPACE_DB "whitespace sucks.db"
356acf968bSDave Rigby
366acf968bSDave Rigby// Types //////////////////////////////////////////////////////////////////////
376acf968bSDave Rigby
386acf968bSDave Rigby
396acf968bSDave Rigby// Helper functions ///////////////////////////////////////////////////////////
406acf968bSDave Rigby
416acf968bSDave Rigbystatic bool epsilon(int val, int target, int ep=5) {
426acf968bSDave Rigby    return abs(val - target) < ep;
436acf968bSDave Rigby}
446acf968bSDave Rigby
456acf968bSDave Rigby
466acf968bSDave Rigby// Testcases //////////////////////////////////////////////////////////////////
476acf968bSDave Rigby
486acf968bSDave Rigbystatic enum test_result test_alloc_limit(ENGINE_HANDLE *h,
496acf968bSDave Rigby                                         ENGINE_HANDLE_V1 *h1) {
5004691ad5Solivermd    auto rv = allocate(h,
5104691ad5Solivermd                       h1,
5204691ad5Solivermd                       NULL,
5304691ad5Solivermd                       "key",
5404691ad5Solivermd                       20 * 1024 * 1024,
5504691ad5Solivermd                       0,
5604691ad5Solivermd                       0,
5704691ad5Solivermd                       PROTOCOL_BINARY_RAW_BYTES,
5804691ad5Solivermd                       0);
5904691ad5Solivermd    checkeq(cb::engine_errc::success, rv.first, "Allocated 20MB item");
6104691ad5Solivermd    rv = allocate(h,
6204691ad5Solivermd                  h1,
6304691ad5Solivermd                  NULL,
6404691ad5Solivermd                  "key",
6504691ad5Solivermd                  (20 * 1024 * 1024) + 1,
6604691ad5Solivermd                  0,
6704691ad5Solivermd                  0,
6804691ad5Solivermd                  PROTOCOL_BINARY_RAW_BYTES,
6904691ad5Solivermd                  0);
7004691ad5Solivermd    checkeq(cb::engine_errc::too_big, rv.first, "Object too big");
716acf968bSDave Rigby
726acf968bSDave Rigby    return SUCCESS;
736acf968bSDave Rigby}
746acf968bSDave Rigby
756acf968bSDave Rigbystatic enum test_result test_memory_tracking(ENGINE_HANDLE *h,
766acf968bSDave Rigby                                             ENGINE_HANDLE_V1 *h1) {
776acf968bSDave Rigby    // Need memory tracker to be able to check our memory usage.
786acf968bSDave Rigby    std::string tracker = get_str_stat(h, h1, "ep_mem_tracker_enabled");
796acf968bSDave Rigby    if (tracker == "true") {
806acf968bSDave Rigby        return SUCCESS;
816acf968bSDave Rigby    } else {
826acf968bSDave Rigby        std::cerr << "Memory tracker not enabled ...";
836acf968bSDave Rigby        return SKIPPED;
846acf968bSDave Rigby    }
856acf968bSDave Rigby}
866acf968bSDave Rigby
876acf968bSDave Rigbystatic enum test_result test_max_size_and_water_marks_settings(
886acf968bSDave Rigby                                        ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
896acf968bSDave Rigby    checkeq(1000, get_int_stat(h, h1, "ep_max_size"), "Incorrect initial size.");
906acf968bSDave Rigby    check(epsilon(get_int_stat(h, h1, "ep_mem_low_wat"), 750),
916acf968bSDave Rigby          "Incorrect initial low wat.");
926acf968bSDave Rigby    check(epsilon(get_int_stat(h, h1, "ep_mem_high_wat"), 850),
936acf968bSDave Rigby          "Incorrect initial high wat.");
946acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_low_wat_percent") == (float)0.75),
956acf968bSDave Rigby          "Incorrect initial low wat. percent");
966acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_high_wat_percent") == (float)0.85),
976acf968bSDave Rigby          "Incorrect initial high wat. percent");
986acf968bSDave Rigby
996acf968bSDave Rigby    set_param(h, h1, protocol_binary_engine_param_flush, "max_size", "1000000");
1006acf968bSDave Rigby
1016acf968bSDave Rigby    checkeq(1000000, get_int_stat(h, h1, "ep_max_size"),
1026acf968bSDave Rigby            "Incorrect new size.");
1036acf968bSDave Rigby    check(epsilon(get_int_stat(h, h1, "ep_mem_low_wat"), 750000),
1046acf968bSDave Rigby          "Incorrect larger low wat.");
1056acf968bSDave Rigby    check(epsilon(get_int_stat(h, h1, "ep_mem_high_wat"), 850000),
1066acf968bSDave Rigby          "Incorrect larger high wat.");
1076acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_low_wat_percent") == (float)0.75),
1086acf968bSDave Rigby          "Incorrect larger low wat. percent");
1096acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_high_wat_percent") == (float)0.85),
1106acf968bSDave Rigby          "Incorrect larger high wat. percent");
1116acf968bSDave Rigby
1126acf968bSDave Rigby    set_param(h, h1, protocol_binary_engine_param_flush, "mem_low_wat", "700000");
1136acf968bSDave Rigby    set_param(h, h1, protocol_binary_engine_param_flush, "mem_high_wat", "800000");
1146acf968bSDave Rigby
1156acf968bSDave Rigby    checkeq(700000, get_int_stat(h, h1, "ep_mem_low_wat"),
1166acf968bSDave Rigby            "Incorrect even larger low wat.");
1176acf968bSDave Rigby    checkeq(800000, get_int_stat(h, h1, "ep_mem_high_wat"),
1186acf968bSDave Rigby            "Incorrect even larger high wat.");
1196acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_low_wat_percent") == (float)0.7),
1206acf968bSDave Rigby          "Incorrect even larger low wat. percent");
1216acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_high_wat_percent") == (float)0.8),
1226acf968bSDave Rigby          "Incorrect even larger high wat. percent");
1236acf968bSDave Rigby
1246acf968bSDave Rigby    set_param(h, h1, protocol_binary_engine_param_flush, "max_size", "100");
1256acf968bSDave Rigby
1266acf968bSDave Rigby    checkeq(100, get_int_stat(h, h1, "ep_max_size"),
1276acf968bSDave Rigby            "Incorrect smaller size.");
1286acf968bSDave Rigby    check(epsilon(get_int_stat(h, h1, "ep_mem_low_wat"), 70),
1296acf968bSDave Rigby          "Incorrect smaller low wat.");
1306acf968bSDave Rigby    check(epsilon(get_int_stat(h, h1, "ep_mem_high_wat"), 80),
1316acf968bSDave Rigby          "Incorrect smaller high wat.");
1326acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_low_wat_percent") == (float)0.7),
1336acf968bSDave Rigby          "Incorrect smaller low wat. percent");
1346acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_high_wat_percent") == (float)0.8),
1356acf968bSDave Rigby          "Incorrect smaller high wat. percent");
1366acf968bSDave Rigby
1376acf968bSDave Rigby    set_param(h, h1, protocol_binary_engine_param_flush, "mem_low_wat", "50");
1386acf968bSDave Rigby    set_param(h, h1, protocol_binary_engine_param_flush, "mem_high_wat", "70");
1396acf968bSDave Rigby
1406acf968bSDave Rigby    checkeq(50, get_int_stat(h, h1, "ep_mem_low_wat"),
1416acf968bSDave Rigby            "Incorrect even smaller low wat.");
1426acf968bSDave Rigby    checkeq(70, get_int_stat(h, h1, "ep_mem_high_wat"),
1436acf968bSDave Rigby            "Incorrect even smaller high wat.");
1446acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_low_wat_percent") == (float)0.5),
1456acf968bSDave Rigby          "Incorrect even smaller low wat. percent");
1466acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_high_wat_percent") == (float)0.7),
1476acf968bSDave Rigby          "Incorrect even smaller high wat. percent");
1486acf968bSDave Rigby
1496acf968bSDave Rigby    testHarness.reload_engine(&h, &h1,
1506acf968bSDave Rigby                              testHarness.engine_path,
1516acf968bSDave Rigby                              testHarness.get_current_testcase()->cfg,
1526acf968bSDave Rigby                              true, true);
1536acf968bSDave Rigby    wait_for_warmup_complete(h, h1);
1546acf968bSDave Rigby
1556acf968bSDave Rigby    checkeq(1000, get_int_stat(h, h1, "ep_max_size"),
1566acf968bSDave Rigby            "Incorrect initial size.");
1576acf968bSDave Rigby    check(epsilon(get_int_stat(h, h1, "ep_mem_low_wat"), 750),
1586acf968bSDave Rigby          "Incorrect intial low wat.");
1596acf968bSDave Rigby    check(epsilon(get_int_stat(h, h1, "ep_mem_high_wat"), 850),
1606acf968bSDave Rigby          "Incorrect initial high wat.");
1616acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_low_wat_percent") == (float)0.75),
1626acf968bSDave Rigby          "Incorrect initial low wat. percent");
1636acf968bSDave Rigby    check((get_float_stat(h, h1, "ep_mem_high_wat_percent") == (float)0.85),
1646acf968bSDave Rigby          "Incorrect initial high wat. percent");
1656acf968bSDave Rigby
1666acf968bSDave Rigby    return SUCCESS;
1676acf968bSDave Rigby}
1686acf968bSDave Rigby
1696acf968bSDave Rigbystatic enum test_result test_whitespace_db(ENGINE_HANDLE *h,
1706acf968bSDave Rigby                                           ENGINE_HANDLE_V1 *h1) {
1716acf968bSDave Rigby    vals.clear();
172f9c178f3STrond Norbye
1736acf968bSDave Rigby    checkeq(ENGINE_SUCCESS,
174f9c178f3STrond Norbye            get_stats(h, {}, add_stats),
175f9c178f3STrond Norbye            "Failed to get stats.");
17751cff928Sabhinavdangeti    std::string dbname;
1785a223272SJames Harrison    std::string policy;
1795a223272SJames Harrison    policy = isPersistentBucket(h, h1)
1805a223272SJames Harrison                     ? vals.find("ep_item_eviction_policy")->second
1815a223272SJames Harrison                     : "ephemeral";
18251cff928Sabhinavdangeti    dbname.assign(policy + std::string(WHITESPACE_DB));
18451cff928Sabhinavdangeti    std::string oldparam("dbname=" + vals["ep_dbname"]);
18551cff928Sabhinavdangeti    std::string newparam("dbname=" + dbname);
18651cff928Sabhinavdangeti    std::string config = testHarness.get_current_testcase()->cfg;
18751cff928Sabhinavdangeti    std::string::size_type found = config.find(oldparam);
18851cff928Sabhinavdangeti    if (found != config.npos) {
18951cff928Sabhinavdangeti        config.replace(found, oldparam.size(), newparam);
19051cff928Sabhinavdangeti    }
19151cff928Sabhinavdangeti    testHarness.reload_engine(&h, &h1,
19251cff928Sabhinavdangeti                              testHarness.engine_path,
19351cff928Sabhinavdangeti                              config.c_str(),
19451cff928Sabhinavdangeti                              true, false);
19551cff928Sabhinavdangeti    wait_for_warmup_complete(h, h1);
19751cff928Sabhinavdangeti    vals.clear();
19851cff928Sabhinavdangeti    checkeq(ENGINE_SUCCESS,
199f9c178f3STrond Norbye            get_stats(h, {}, add_stats),
200f9c178f3STrond Norbye            "Failed to get stats.");
20251cff928Sabhinavdangeti    if (vals["ep_dbname"] != dbname) {
20351cff928Sabhinavdangeti        std::cerr << "Expected dbname = '" << dbname << "'"
20451cff928Sabhinavdangeti                  << ", got '" << vals["ep_dbname"] << "'" << std::endl;
2056acf968bSDave Rigby        return FAIL;
2066acf968bSDave Rigby    }
2076acf968bSDave Rigby
20851cff928Sabhinavdangeti    check(access(dbname.c_str(), F_OK) != -1, "I expected the whitespace db to exist");
2096acf968bSDave Rigby    return SUCCESS;
2106acf968bSDave Rigby}
2116acf968bSDave Rigby
2121d92be04SDave Rigbystatic enum test_result test_get_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2131d92be04SDave Rigby    checkeq(ENGINE_KEY_ENOENT, verify_key(h, h1, "k"), "Expected miss.");
2141d92be04SDave Rigby    return SUCCESS;
2151d92be04SDave Rigby}
2161d92be04SDave Rigby
2171d92be04SDave Rigbystatic enum test_result test_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2181d92be04SDave Rigby    item_info info;
2191d92be04SDave Rigby    uint64_t vb_uuid = 0, high_seqno = 0;
2201d92be04SDave Rigby    const int num_sets = 5, num_keys = 4;
2211d92be04SDave Rigby
2221d92be04SDave Rigby    std::string key_arr[num_keys] = { "dummy_key",
2231d92be04SDave Rigby                                      "checkpoint_start",
2241d92be04SDave Rigby                                      "checkpoint_end",
2251d92be04SDave Rigby                                      "key" };
2261d92be04SDave Rigby
2271d92be04SDave Rigby
2281d92be04SDave Rigby    for (int k = 0; k < num_keys; k++) {
2291d92be04SDave Rigby        for (int j = 0; j < num_sets; j++) {
2301d92be04SDave Rigby            memset(&info, 0, sizeof(info));
2311d92be04SDave Rigby            vb_uuid = get_ull_stat(h, h1, "vb_0:0:id", "failovers");
2321d92be04SDave Rigby            high_seqno = get_ull_stat(h, h1, "vb_0:high_seqno",
2331d92be04SDave Rigby                                      "vbucket-seqno");
2341d92be04SDave Rigby
2351d92be04SDave Rigby            std::string err_str_store("Error setting " + key_arr[k]);
2361d92be04SDave Rigby            checkeq(ENGINE_SUCCESS,
237d8de1991SDave Rigby                    store(h,
238d8de1991SDave Rigby                          h1,
239d8de1991SDave Rigby                          NULL,
240d8de1991SDave Rigby                          OPERATION_SET,
241d8de1991SDave Rigby                          key_arr[k].c_str(),
242d8de1991SDave Rigby                          "somevalue"),
2431d92be04SDave Rigby                    err_str_store.c_str());
2441d92be04SDave Rigby
2451d92be04SDave Rigby            std::string err_str_get_item_info("Error getting " + key_arr[k]);
2461d92be04SDave Rigby            checkeq(true, get_item_info(h, h1, &info, key_arr[k].c_str()),
2471d92be04SDave Rigby                  err_str_get_item_info.c_str());
2481d92be04SDave Rigby
2491d92be04SDave Rigby            std::string err_str_vb_uuid("Expected valid vbucket uuid for " +
2501d92be04SDave Rigby                                        key_arr[k]);
2511d92be04SDave Rigby            checkeq(vb_uuid, info.vbucket_uuid, err_str_vb_uuid.c_str());
2521d92be04SDave Rigby
2531d92be04SDave Rigby            std::string err_str_seqno("Expected valid sequence number for " +
2541d92be04SDave Rigby                                        key_arr[k]);
2551d92be04SDave Rigby            checkeq(high_seqno + 1, info.seqno, err_str_seqno.c_str());
2561d92be04SDave Rigby        }
2571d92be04SDave Rigby    }
2581d92be04SDave Rigby
2596c0d02e2SDave Rigby    if (isPersistentBucket(h, h1)) {
2606c0d02e2SDave Rigby        wait_for_flusher_to_settle(h, h1);
2611d92be04SDave Rigby
2626c0d02e2SDave Rigby        std::stringstream error1, error2;
2636c0d02e2SDave Rigby        error1 << "Expected ep_total_persisted >= num_keys (" << num_keys << ")";
2646c0d02e2SDave Rigby        error2 << "Expected ep_total_persisted <= num_sets*num_keys ("
2656c0d02e2SDave Rigby               << num_sets*num_keys << ")";
2666c0d02e2SDave Rigby
2676c0d02e2SDave Rigby        // The flusher could of ran > 1 times. We can only assert
2686c0d02e2SDave Rigby        // that we persisted between num_keys and upto num_keys*num_sets
2696c0d02e2SDave Rigby        check(get_int_stat(h, h1, "ep_total_persisted") >= num_keys,
2706c0d02e2SDave Rigby              error1.str().c_str());
2716c0d02e2SDave Rigby        check(get_int_stat(h, h1, "ep_total_persisted") <= num_sets*num_keys,
2726c0d02e2SDave Rigby              error2.str().c_str());
2736c0d02e2SDave Rigby    }
2741d92be04SDave Rigby    return SUCCESS;
2751d92be04SDave Rigby}
2761d92be04SDave Rigby
2771d92be04SDave Rigbyextern "C" {
2781d92be04SDave Rigby    static void conc_del_set_thread(void *arg) {
2791d92be04SDave Rigby        struct handle_pair *hp = static_cast<handle_pair *>(arg);
2801d92be04SDave Rigby
2811d92be04SDave Rigby        for (int i = 0; i < 5000; ++i) {
282d8de1991SDave Rigby            store(hp->h, hp->h1, NULL, OPERATION_ADD, "key", "somevalue");
2831d92be04SDave Rigby            checkeq(ENGINE_SUCCESS,
284d8de1991SDave Rigby                    store(hp->h,
285d8de1991SDave Rigby                          hp->h1,
286d8de1991SDave Rigby                          NULL,
287d8de1991SDave Rigby                          OPERATION_SET,
288d8de1991SDave Rigby                          "key",
289d8de1991SDave Rigby                          "somevalue"),
2901d92be04SDave Rigby                    "Error setting.");
2911d92be04SDave Rigby            // Ignoring the result here -- we're racing.
2921d92be04SDave Rigby            del(hp->h, hp->h1, "key", 0, 0);
2931d92be04SDave Rigby        }
2941d92be04SDave Rigby    }
2951d92be04SDave Rigby}
2961d92be04SDave Rigby
2971d92be04SDave Rigbystatic enum test_result test_conc_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2981d92be04SDave Rigby
2991d92be04SDave Rigby    const int n_threads = 8;
3001d92be04SDave Rigby    cb_thread_t threads[n_threads];
3011d92be04SDave Rigby    struct handle_pair hp = {h, h1};
3021d92be04SDave Rigby
3031d92be04SDave Rigby    wait_for_persisted_value(h, h1, "key", "value1");
3041d92be04SDave Rigby
3051d92be04SDave Rigby    for (int i = 0; i < n_threads; i++) {
3061d92be04SDave Rigby        int r = cb_create_thread(&threads[i], conc_del_set_thread, &hp, 0);
3071d92be04SDave Rigby        cb_assert(r == 0);
3081d92be04SDave Rigby    }
3091d92be04SDave Rigby
3101d92be04SDave Rigby    for (int i = 0; i < n_threads; i++) {
3111d92be04SDave Rigby        int r = cb_join_thread(threads[i]);
3121d92be04SDave Rigby        cb_assert(r == 0);
3131d92be04SDave Rigby    }
3141d92be04SDave Rigby
3155163fad1SDave Rigby    if (isWarmupEnabled(h, h1)) {
3165163fad1SDave Rigby        wait_for_flusher_to_settle(h, h1);
3171d92be04SDave Rigby
3185163fad1SDave Rigby        testHarness.reload_engine(&h, &h1,
3195163fad1SDave Rigby                                  testHarness.engine_path,
3205163fad1SDave Rigby                                  testHarness.get_current_testcase()->cfg,
3215163fad1SDave Rigby                                  true, false);
3225163fad1SDave Rigby        wait_for_warmup_complete(h, h1);
3231d92be04SDave Rigby
3245163fad1SDave Rigby        cb_assert(0 == get_int_stat(h, h1, "ep_warmup_dups"));
3255163fad1SDave Rigby    }
3261d92be04SDave Rigby
3271d92be04SDave Rigby    return SUCCESS;
3281d92be04SDave Rigby}
3291d92be04SDave Rigby
3301d92be04SDave Rigbystruct multi_set_args {
3311d92be04SDave Rigby    ENGINE_HANDLE *h;
3321d92be04SDave Rigby    ENGINE_HANDLE_V1 *h1;
3331d92be04SDave Rigby    std::string prefix;
3341d92be04SDave Rigby    int count;
3351d92be04SDave Rigby};
3361d92be04SDave Rigby
3371d92be04SDave Rigbyextern "C" {
3381d92be04SDave Rigby    static void multi_set_thread(void *arg) {
3391d92be04SDave Rigby        struct multi_set_args *msa = static_cast<multi_set_args *>(arg);
3401d92be04SDave Rigby
3411d92be04SDave Rigby        for (int i = 0; i < msa->count; i++) {
3421d92be04SDave Rigby            std::stringstream s;
3431d92be04SDave Rigby            s << msa->prefix << i;
3441d92be04SDave Rigby            std::string key(s.str());
3451d92be04SDave Rigby            checkeq(ENGINE_SUCCESS,
346d8de1991SDave Rigby                    store(msa->h,
347d8de1991SDave Rigby                          msa->h1,
348d8de1991SDave Rigby                          NULL,
349d8de1991SDave Rigby                          OPERATION_SET,
350d8de1991SDave Rigby                          key.c_str(),
351d8de1991SDave Rigby                          "somevalue"),
3521d92be04SDave Rigby                    "Set failure!");
3531d92be04SDave Rigby        }
3541d92be04SDave Rigby    }
3551d92be04SDave Rigby}
3561d92be04SDave Rigby
3571d92be04SDave Rigbystatic enum test_result test_multi_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3581d92be04SDave Rigby
3591d92be04SDave Rigby    cb_thread_t thread1, thread2;
3601d92be04SDave Rigby    struct multi_set_args msa1, msa2;
3611d92be04SDave Rigby    msa1.h = h;
3621d92be04SDave Rigby    msa1.h1 = h1;
3631d92be04SDave Rigby    msa1.prefix = "ONE_";
3641d92be04SDave Rigby    msa1.count = 50000;
3651d92be04SDave Rigby    cb_assert(cb_create_thread(&thread1, multi_set_thread, &msa1, 0) == 0);
3661d92be04SDave Rigby
3671d92be04SDave Rigby    msa2.h = h;
3681d92be04SDave Rigby    msa2.h1 = h1;
3691d92be04SDave Rigby    msa2.prefix = "TWO_";
3701d92be04SDave Rigby    msa2.count = 50000;
3711d92be04SDave Rigby    cb_assert(cb_create_thread(&thread2, multi_set_thread, &msa2, 0) == 0);
3721d92be04SDave Rigby
3731d92be04SDave Rigby    cb_assert(cb_join_thread(thread1) == 0);
3741d92be04SDave Rigby    cb_assert(cb_join_thread(thread2) == 0);
3751d92be04SDave Rigby
3761d92be04SDave Rigby    wait_for_flusher_to_settle(h, h1);
3771d92be04SDave Rigby
3781d92be04SDave Rigby    checkeq(100000, get_int_stat(h, h1, "curr_items"),
3791d92be04SDave Rigby            "Mismatch in number of items inserted");
3801d92be04SDave Rigby    checkeq(100000, get_int_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno"),
3811d92be04SDave Rigby            "Unexpected high sequence number");
3821d92be04SDave Rigby
3831d92be04SDave Rigby    return SUCCESS;
3841d92be04SDave Rigby}
3851d92be04SDave Rigby
3861d92be04SDave Rigbystatic enum test_result test_set_get_hit(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3871d92be04SDave Rigby    checkeq(ENGINE_SUCCESS,
388d8de1991SDave Rigby            store(h, h1, NULL, OPERATION_SET, "key", "somevalue"),
3891d92be04SDave Rigby            "store failure");
3901d92be04SDave Rigby    check_key_value(h, h1, "key", "somevalue", 9);
3911d92be04SDave Rigby    return SUCCESS;
3921d92be04SDave Rigby}
3931d92be04SDave Rigby
3941d92be04SDave Rigbystatic enum test_result test_getl_delete_with_cas(ENGINE_HANDLE *h,
3951d92be04SDave Rigby                                                  ENGINE_HANDLE_V1 *h1) {
3961d92be04SDave Rigby    checkeq(ENGINE_SUCCESS,
397d8de1991SDave Rigby            store(h, h1, NULL, OPERATION_SET, "key", "value"),
3981d92be04SDave Rigby            "Failed to set key");
3991d92be04SDave Rigby
40031785d1bSolivermd    auto ret = getl(h, h1, nullptr, "key", 0, 15);
40131785d1bSolivermd    checkeq(cb::engine_errc::success,
40231785d1bSolivermd            ret.first,
403b2c84d53STrond Norbye            "Expected getl to succeed on key");
404b2c84d53STrond Norbye    item_info info;
405a14f9224STrond Norbye    check(h1->get_item_info(h, ret.second.get(), &info),
406b2c84d53STrond Norbye          "Failed to get item info");
4071d92be04SDave Rigby
408b2c84d53STrond Norbye    checkeq(ENGINE_SUCCESS, del(h, h1, "key", info.cas, 0), "Expected SUCCESS");
4091d92be04SDave Rigby
4101d92be04SDave Rigby    return SUCCESS;
4111d92be04SDave Rigby}
4121d92be04SDave Rigby
4131d92be04SDave Rigbystatic enum test_result test_getl_delete_with_bad_cas(ENGINE_HANDLE *h,
4141d92be04SDave Rigby                                                      ENGINE_HANDLE_V1 *h1) {
4151d92be04SDave Rigby    checkeq(ENGINE_SUCCESS,
416d8de1991SDave Rigby            store(h, h1, NULL, OPERATION_SET, "key", "value"),
4171d92be04SDave Rigby            "Failed to set key");
4181d92be04SDave Rigby
4191d92be04SDave Rigby    uint64_t cas = last_cas;
42031785d1bSolivermd    checkeq(cb::engine_errc::success,
42131785d1bSolivermd            getl(h, h1, nullptr, "key", 0, 15).first,
422b2c84d53STrond Norbye            "Expected getl to succeed on key");
4231d92be04SDave Rigby
424f3826934STrond Norbye    checkeq(ENGINE_LOCKED_TMPFAIL, del(h, h1, "key", cas, 0), "Expected TMPFAIL");
4251d92be04SDave Rigby
4261d92be04SDave Rigby    return SUCCESS;
4271d92be04SDave Rigby}
4281d92be04SDave Rigby
4291d92be04SDave Rigbystatic enum test_result test_getl_set_del_with_meta(ENGINE_HANDLE *h,
4301d92be04SDave Rigby                                                    ENGINE_HANDLE_V1 *h1) {
4311d92be04SDave Rigby    const char *key = "key";
4321d92be04SDave Rigby    const char *val = "value";
4331d92be04SDave Rigby    const char *newval = "newvalue";
4341d92be04SDave Rigby    checkeq(ENGINE_SUCCESS,
435d8de1991SDave Rigby            store(h, h1, NULL, OPERATION_SET, key, val),
4361d92be04SDave Rigby            "Failed to set key");
4371d92be04SDave Rigby
43831785d1bSolivermd    checkeq(cb::engine_errc::success,
43931785d1bSolivermd            getl(h, h1, nullptr, key, 0, 15).first,
44031785d1bSolivermd            "Expected getl to succeed on key");
4411d92be04SDave Rigby
4428611dc8cSPaolo Cocchi    cb::EngineErrorMetadataPair errorMetaPair;
4438611dc8cSPaolo Cocchi    check(get_meta(h, h1, key, errorMetaPair), "Expected to get meta");
4441d92be04SDave Rigby
4451d92be04SDave Rigby    //init some random metadata
4468611dc8cSPaolo Cocchi    ItemMetaData itm_meta(0xdeadbeef, 10, 0xdeadbeef, time(NULL) + 300);
4471d92be04SDave Rigby
4481d92be04SDave Rigby    //do a set with meta
4498611dc8cSPaolo Cocchi    set_with_meta(h,
4508611dc8cSPaolo Cocchi                  h1,
4518611dc8cSPaolo Cocchi                  key,
4528611dc8cSPaolo Cocchi                  strlen(key),
4538611dc8cSPaolo Cocchi                  newval,
4548611dc8cSPaolo Cocchi                  strlen(newval),
4558611dc8cSPaolo Cocchi                  0,
4568611dc8cSPaolo Cocchi                  &itm_meta,
4578611dc8cSPaolo Cocchi                  errorMetaPair.second.cas);
458f3826934STrond Norbye    checkeq(PROTOCOL_BINARY_RESPONSE_LOCKED, last_status.load(),
4591d92be04SDave Rigby          "Expected item to be locked");
4601d92be04SDave Rigby
4611d92be04SDave Rigby    //do a del with meta
4621d92be04SDave Rigby    del_with_meta(h, h1, key, strlen(key), 0, &itm_meta, last_cas);
463f3826934STrond Norbye    checkeq(PROTOCOL_BINARY_RESPONSE_LOCKED, last_status.load(),
4641d92be04SDave Rigby          "Expected item to be locked");
4651d92be04SDave Rigby    return SUCCESS;
4661d92be04SDave Rigby}
4671d92be04SDave Rigby
4681d92be04SDave Rigbystatic enum test_result test_getl(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
4691d92be04SDave Rigby    const char *key = "k1";
4701d92be04SDave Rigby    uint16_t vbucketId = 0;
4711d92be04SDave Rigby    uint32_t expiration = 25;
4721d92be04SDave Rigby
473393b038aSTrond Norbye    const void* cookie = testHarness.create_cookie();
474393b038aSTrond Norbye
47531785d1bSolivermd    checkeq(cb::engine_errc::no_such_key,
476393b038aSTrond Norbye            getl(h, h1, cookie, key, vbucketId, expiration).first,
47731785d1bSolivermd            "expected the key to be missing...");
4781d92be04SDave Rigby
4791d92be04SDave Rigby    checkeq(ENGINE_SUCCESS,
480393b038aSTrond Norbye            store(h,
481393b038aSTrond Norbye                  h1,
482393b038aSTrond Norbye                  cookie,
483393b038aSTrond Norbye                  OPERATION_SET,
484393b038aSTrond Norbye                  key,
485393b038aSTrond Norbye                  "{\"lock\":\"data\"}",
486d8de1991SDave Rigby                  nullptr,