MB-23719: Add dynamic change of ephemeral_metadata_purge_age
[ep-engine.git] / tests / ep_testsuite.cc
1 /* -*- MODE: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2010 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17
18 // Usage: (to run just a single test case)
19 // make engine_tests EP_TEST_NUM=3
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <condition_variable>
28 #include <cstdlib>
29 #include <chrono>
30 #include <iostream>
31 #include <iomanip>
32 #include <map>
33 #include <mutex>
34 #include <set>
35 #include <sstream>
36 #include <string>
37 #include <thread>
38 #include <unordered_map>
39 #include <unordered_set>
40 #include <vector>
41
42 #include "atomic.h"
43 #include "ep_test_apis.h"
44
45 #include "ep_testsuite_common.h"
46 #include "locks.h"
47 #include <libcouchstore/couch_db.h>
48 #include <memcached/engine.h>
49 #include <memcached/engine_testapp.h>
50 #include <platform/cb_malloc.h>
51 #include <platform/dirutils.h>
52 #include <JSON_checker.h>
53 #include <memcached/types.h>
54 #include <string_utilities.h>
55 #include <xattr/blob.h>
56 #include <xattr/utils.h>
57
58 #ifdef linux
59 /* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
60  * optimize the conversion functions, but the prototypes generate warnings
61  * from gcc. The conversion methods isn't the bottleneck for my app, so
62  * just remove the warnings by undef'ing the optimization ..
63  */
64 #undef ntohs
65 #undef ntohl
66 #undef htons
67 #undef htonl
68 #endif
69
70 // ptr_fun don't like the extern "C" thing for unlock cookie.. cast it
71 // away ;)
72 typedef void (*UNLOCK_COOKIE_T)(const void *cookie);
73
74 #define MULTI_DISPATCHER_CONFIG \
75     "ht_size=129;ht_locks=3;chk_remover_stime=1;chk_period=60"
76
77 class ThreadData {
78 public:
79     ThreadData(ENGINE_HANDLE *eh, ENGINE_HANDLE_V1 *ehv1,
80                int e=0) : h(eh), h1(ehv1), extra(e) {}
81     ENGINE_HANDLE    *h;
82     ENGINE_HANDLE_V1 *h1;
83     int               extra;
84 };
85
86
87 static void check_observe_seqno(bool failover, uint8_t format_type, uint16_t vb_id,
88                                 uint64_t vb_uuid, uint64_t last_persisted_seqno,
89                                 uint64_t current_seqno, uint64_t failover_vbuuid = 0,
90                                 uint64_t failover_seqno = 0) {
91     uint8_t  recv_format_type;
92     uint16_t recv_vb_id;
93     uint64_t recv_vb_uuid;
94     uint64_t recv_last_persisted_seqno;
95     uint64_t recv_current_seqno;
96     uint64_t recv_failover_vbuuid;
97     uint64_t recv_failover_seqno;
98
99     memcpy(&recv_format_type, last_body.data(), sizeof(uint8_t));
100     checkeq(format_type, recv_format_type, "Wrong format type in result");
101     memcpy(&recv_vb_id, last_body.data() + 1, sizeof(uint16_t));
102     checkeq(vb_id, ntohs(recv_vb_id), "Wrong vbucket id in result");
103     memcpy(&recv_vb_uuid, last_body.data() + 3, sizeof(uint64_t));
104     checkeq(vb_uuid, ntohll(recv_vb_uuid), "Wrong vbucket uuid in result");
105     memcpy(&recv_last_persisted_seqno, last_body.data() + 11, sizeof(uint64_t));
106     checkeq(last_persisted_seqno, ntohll(recv_last_persisted_seqno),
107             "Wrong persisted seqno in result");
108     memcpy(&recv_current_seqno, last_body.data() + 19, sizeof(uint64_t));
109     checkeq(current_seqno, ntohll(recv_current_seqno), "Wrong current seqno in result");
110
111     if (failover) {
112         memcpy(&recv_failover_vbuuid, last_body.data() + 27, sizeof(uint64_t));
113         checkeq(failover_vbuuid, ntohll(recv_failover_vbuuid),
114                 "Wrong failover uuid in result");
115         memcpy(&recv_failover_seqno, last_body.data() + 35, sizeof(uint64_t));
116         checkeq(failover_seqno, ntohll(recv_failover_seqno),
117                 "Wrong failover seqno in result");
118     }
119 }
120
121 static enum test_result test_replace_with_eviction(ENGINE_HANDLE *h,
122                                                    ENGINE_HANDLE_V1 *h1) {
123     item *i = NULL;
124     checkeq(ENGINE_SUCCESS,
125             store(h, h1, NULL, OPERATION_SET,"key", "somevalue", &i),
126             "Failed to set value.");
127     h1->release(h, NULL, i);
128     wait_for_flusher_to_settle(h, h1);
129     evict_key(h, h1, "key");
130     int numBgFetched = get_int_stat(h, h1, "ep_bg_fetched");
131
132     checkeq(ENGINE_SUCCESS,
133             store(h, h1, NULL, OPERATION_REPLACE,"key", "somevalue1", &i),
134             "Failed to replace existing value.");
135
136     checkeq(ENGINE_SUCCESS,
137             h1->get_stats(h, NULL, NULL, 0, add_stats),
138             "Failed to get stats.");
139     std::string eviction_policy = vals.find("ep_item_eviction_policy")->second;
140     if (eviction_policy == "full_eviction") {
141         numBgFetched++;
142     }
143
144     checkeq(numBgFetched,
145             get_int_stat(h, h1, "ep_bg_fetched"),
146             "Bg fetched value didn't match");
147
148     h1->release(h, NULL, i);
149     check_key_value(h, h1, "key", "somevalue1", 10);
150     return SUCCESS;
151 }
152
153 static enum test_result test_wrong_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
154                                                ENGINE_STORE_OPERATION op) {
155     item *i = NULL;
156     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
157     uint64_t cas = 11;
158     if (op == OPERATION_ADD) {
159         // Add operation with cas != 0 doesn't make sense
160         cas = 0;
161     }
162     checkeq(ENGINE_NOT_MY_VBUCKET,
163             store(h, h1, NULL, op, "key", "somevalue", &i, cas, 1),
164             "Expected not_my_vbucket");
165     h1->release(h, NULL, i);
166     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
167     return SUCCESS;
168 }
169
170 static enum test_result test_pending_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
171                                                  ENGINE_STORE_OPERATION op) {
172     const void *cookie = testHarness.create_cookie();
173     testHarness.set_ewouldblock_handling(cookie, false);
174     item *i = NULL;
175     check(set_vbucket_state(h, h1, 1, vbucket_state_pending),
176           "Failed to set vbucket state.");
177     check(verify_vbucket_state(h, h1, 1, vbucket_state_pending),
178           "Bucket state was not set to pending.");
179     uint64_t cas = 11;
180     if (op == OPERATION_ADD) {
181         // Add operation with cas != 0 doesn't make sense..
182         cas = 0;
183     }
184     checkeq(ENGINE_EWOULDBLOCK,
185             store(h, h1, cookie, op, "key", "somevalue", &i, cas, 1),
186             "Expected ewouldblock");
187     h1->release(h, NULL, i);
188     testHarness.destroy_cookie(cookie);
189     return SUCCESS;
190 }
191
192 static enum test_result test_replica_vb_mutation(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
193                                                  ENGINE_STORE_OPERATION op) {
194     item *i = NULL;
195     check(set_vbucket_state(h, h1, 1, vbucket_state_replica),
196           "Failed to set vbucket state.");
197     check(verify_vbucket_state(h, h1, 1, vbucket_state_replica),
198           "Bucket state was not set to replica.");
199     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
200
201     uint64_t cas = 11;
202     if (op == OPERATION_ADD) {
203         // performing add with a CAS != 0 doesn't make sense...
204         cas = 0;
205     }
206     checkeq(ENGINE_NOT_MY_VBUCKET,
207             store(h, h1, NULL, op, "key", "somevalue", &i, cas, 1),
208             "Expected not my vbucket");
209     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
210     h1->release(h, NULL, i);
211     return SUCCESS;
212 }
213
214 //
215 // ----------------------------------------------------------------------
216 // The actual tests are below.
217 // ----------------------------------------------------------------------
218 //
219
220 static int checkCurrItemsAfterShutdown(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
221                                        int numItems2Load, bool shutdownForce) {
222     if (!isWarmupEnabled(h, h1)) {
223         return SKIPPED;
224     }
225
226     std::vector<std::string> keys;
227     for (int index = 0; index < numItems2Load; ++index) {
228         std::stringstream s;
229         s << "keys_2_load-" << index;
230         std::string key(s.str());
231         keys.push_back(key);
232     }
233
234     checkeq(0, get_int_stat(h, h1, "ep_total_persisted"),
235             "Expected ep_total_persisted equals 0");
236     checkeq(0, get_int_stat(h, h1, "curr_items"),
237             "Expected curr_items equals 0");
238
239     // stop flusher before loading new items
240     protocol_binary_request_header *pkt = createPacket(PROTOCOL_BINARY_CMD_STOP_PERSISTENCE);
241     checkeq(ENGINE_SUCCESS,
242             h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
243             "CMD_STOP_PERSISTENCE failed!");
244     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS,
245             last_status.load(),
246             "Failed to stop persistence!");
247     cb_free(pkt);
248
249     std::vector<std::string>::iterator itr;
250     for (itr = keys.begin(); itr != keys.end(); ++itr) {
251         item *i;
252         checkeq(ENGINE_SUCCESS,
253                 store(h, h1, NULL, OPERATION_SET, itr->c_str(), "oracle", &i, 0, 0),
254                 "Failed to store a value");
255         h1->release(h, NULL, i);
256     }
257
258     checkeq(0, get_int_stat(h, h1, "ep_total_persisted"),
259             "Incorrect ep_total_persisted, expected 0");
260     std::stringstream ss;
261     ss << "Incorrect curr_items, expected " << numItems2Load;
262     std::string errmsg(ss.str());
263     checkeq(numItems2Load, get_int_stat(h, h1, "curr_items"),
264             errmsg.c_str());
265
266     // resume flusher before shutdown + warmup
267     pkt = createPacket(PROTOCOL_BINARY_CMD_START_PERSISTENCE);
268     checkeq(ENGINE_SUCCESS, h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
269             "CMD_START_PERSISTENCE failed!");
270     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
271           "Failed to start persistence!");
272     cb_free(pkt);
273
274     // shutdown engine force and restart
275     testHarness.reload_engine(&h, &h1,
276                               testHarness.engine_path,
277                               testHarness.get_current_testcase()->cfg,
278                               true, shutdownForce);
279     wait_for_warmup_complete(h, h1);
280     return get_int_stat(h, h1, "curr_items");
281 }
282
283 static enum test_result test_flush_shutdown_force(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
284     if (!isWarmupEnabled(h, h1)) {
285         return SKIPPED;
286     }
287
288     int numItems2load = 3000;
289     bool shutdownForce = true;
290     int currItems = checkCurrItemsAfterShutdown(h, h1, numItems2load, shutdownForce);
291     check (currItems <= numItems2load,
292            "Number of curr items should be <= 3000, unless previous "
293            "shutdown force had to wait for the flusher");
294     return SUCCESS;
295 }
296
297 static enum test_result test_flush_shutdown_noforce(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
298     if (!isWarmupEnabled(h, h1)) {
299         return SKIPPED;
300     }
301
302     int numItems2load = 3000;
303     bool shutdownForce = false;
304     int currItems = checkCurrItemsAfterShutdown(h, h1, numItems2load, shutdownForce);
305     check (currItems == numItems2load,
306            "Number of curr items should be equal to 3000, unless previous "
307            "shutdown did not wait for the flusher");
308     return SUCCESS;
309 }
310
311 static enum test_result test_flush_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
312     if (!isWarmupEnabled(h, h1)) {
313         return SKIPPED;
314     }
315
316     item *i = NULL;
317     // First try to delete something we know to not be there.
318     checkeq(ENGINE_KEY_ENOENT, del(h, h1, "key", 0, 0),
319             "Failed to fail initial delete.");
320     checkeq(ENGINE_SUCCESS,
321             store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
322             "Failed set.");
323     h1->release(h, NULL, i);
324     check_key_value(h, h1, "key", "somevalue", 9);
325
326     // Restart once to ensure written to disk.
327     testHarness.reload_engine(&h, &h1,
328                               testHarness.engine_path,
329                               testHarness.get_current_testcase()->cfg,
330                               true, false);
331     wait_for_warmup_complete(h, h1);
332
333     // Read value from disk.
334     check_key_value(h, h1, "key", "somevalue", 9);
335
336     // Flush
337     set_degraded_mode(h, h1, NULL, true);
338     checkeq(ENGINE_SUCCESS, h1->flush(h, NULL),
339             "Failed to flush");
340     set_degraded_mode(h, h1, NULL, false);
341
342     checkeq(ENGINE_SUCCESS,
343             store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i),
344             "Failed post-flush set.");
345     h1->release(h, NULL, i);
346     check_key_value(h, h1, "key2", "somevalue", 9);
347
348     // Restart again, ensure written to disk.
349     testHarness.reload_engine(&h, &h1,
350                               testHarness.engine_path,
351                               testHarness.get_current_testcase()->cfg,
352                               true, false);
353     wait_for_warmup_complete(h, h1);
354
355     checkeq(ENGINE_SUCCESS,
356             store(h, h1, NULL, OPERATION_SET, "key3", "somevalue", &i),
357             "Failed post-flush, post-restart set.");
358     h1->release(h, NULL, i);
359     check_key_value(h, h1, "key3", "somevalue", 9);
360
361     // Read value again, should not be there.
362     checkeq(ENGINE_KEY_ENOENT, verify_key(h, h1, "key"),
363             "Expected missing key");
364     return SUCCESS;
365 }
366
367 static enum test_result test_shutdown_snapshot_range(ENGINE_HANDLE *h,
368                                                      ENGINE_HANDLE_V1 *h1) {
369     if (!isWarmupEnabled(h, h1)) {
370         return SKIPPED;
371     }
372
373     const int num_items = 100;
374     for (int j = 0; j < num_items; ++j) {
375         item *i = NULL;
376         std::stringstream ss;
377         ss << "key" << j;
378         checkeq(ENGINE_SUCCESS,
379                 store(h, h1, NULL, OPERATION_SET, ss.str().c_str(), "data", &i),
380                 "Failed to store a value");
381         h1->release(h, NULL, i);
382     }
383
384     wait_for_flusher_to_settle(h, h1);
385     int end = get_int_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno");
386
387     /* change vb state to replica before restarting (as it happens in graceful
388        failover)*/
389     check(set_vbucket_state(h, h1, 0, vbucket_state_replica),
390           "Failed set vbucket 0 to replica state.");
391
392     /* trigger persist vb state task */
393     check(set_param(h, h1, protocol_binary_engine_param_flush,
394                     "vb_state_persist_run", "0"),
395           "Failed to trigger vb state persist");
396
397     /* restart the engine */
398     testHarness.reload_engine(&h, &h1,
399                               testHarness.engine_path,
400                               testHarness.get_current_testcase()->cfg,
401                               true, false);
402     wait_for_warmup_complete(h, h1);
403
404     /* Check if snapshot range is persisted correctly */
405     checkeq(end, get_int_stat(h, h1, "vb_0:last_persisted_snap_start",
406                               "vbucket-seqno"),
407             "Wrong snapshot start persisted");
408     checkeq(end, get_int_stat(h, h1, "vb_0:last_persisted_snap_end",
409                                     "vbucket-seqno"),
410             "Wrong snapshot end persisted");
411
412     return SUCCESS;
413 }
414
415 static enum test_result test_flush_multiv_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
416     if (!isWarmupEnabled(h, h1)) {
417         return SKIPPED;
418     }
419
420     item *i = NULL;
421     check(set_vbucket_state(h, h1, 2, vbucket_state_active),
422           "Failed to set vbucket state.");
423     checkeq(ENGINE_SUCCESS,
424             store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i),
425             "Failed set.");
426     h1->release(h, NULL, i);
427     checkeq(ENGINE_SUCCESS,
428             store(h, h1, NULL, OPERATION_SET, "key2", "somevalue", &i, 0, 2),
429             "Failed set in vb2.");
430     h1->release(h, NULL, i);
431
432     // Restart once to ensure written to disk.
433     testHarness.reload_engine(&h, &h1,
434                               testHarness.engine_path,
435                               testHarness.get_current_testcase()->cfg,
436                               true, false);
437     wait_for_warmup_complete(h, h1);
438
439     // Read value from disk.
440     check_key_value(h, h1, "key", "somevalue", 9);
441
442     // Flush
443     set_degraded_mode(h, h1, NULL, true);
444     checkeq(ENGINE_SUCCESS, h1->flush(h, NULL),
445             "Failed to flush");
446     set_degraded_mode(h, h1, NULL, false);
447
448     // Restart again, ensure written to disk.
449     testHarness.reload_engine(&h, &h1,
450                               testHarness.engine_path,
451                               testHarness.get_current_testcase()->cfg,
452                               true, false);
453     wait_for_warmup_complete(h, h1);
454
455     // Read value again, should not be there.
456     checkeq(ENGINE_KEY_ENOENT, verify_key(h, h1, "key"), "Expected missing key");
457     check(verify_vbucket_missing(h, h1, 2), "Bucket 2 came back.");
458     return SUCCESS;
459 }
460
461 static enum test_result test_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
462     if (!isWarmupEnabled(h, h1)) {
463         return SKIPPED;
464     }
465
466     item *i = NULL;
467     static const char val[] = "somevalue";
468     ENGINE_ERROR_CODE ret = store(h, h1, NULL, OPERATION_SET, "key", val, &i);
469     checkeq(ENGINE_SUCCESS, ret, "Failed set.");
470     h1->release(h, NULL, i);
471
472     testHarness.reload_engine(&h, &h1,
473                               testHarness.engine_path,
474                               testHarness.get_current_testcase()->cfg,
475                               true, false);
476     wait_for_warmup_complete(h, h1);
477     check_key_value(h, h1, "key", val, strlen(val));
478     return SUCCESS;
479 }
480
481 static enum test_result test_restart_session_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
482     const void* cookie = createTapConn(h, h1, "tap_client_thread");
483     testHarness.unlock_cookie(cookie);
484     testHarness.destroy_cookie(cookie);
485
486     testHarness.reload_engine(&h, &h1,
487                               testHarness.engine_path,
488                               testHarness.get_current_testcase()->cfg,
489                               true, false);
490     wait_for_warmup_complete(h, h1);
491     cookie = createTapConn(h, h1, "tap_client_thread");
492
493     checkeq(ENGINE_SUCCESS, h1->get_stats(h, NULL, "tap", 3, add_stats),
494             "Failed to get stats.");
495     std::string val = vals["eq_tapq:tap_client_thread:backfill_completed"];
496     checkeq(0, strcmp(val.c_str(), "true"), "Don't expect the backfill upon restart");
497     testHarness.unlock_cookie(cookie);
498     testHarness.destroy_cookie(cookie);
499     return SUCCESS;
500 }
501
502 static enum test_result test_specialKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
503     item *i = NULL;
504     ENGINE_ERROR_CODE ret;
505
506     // Simplified Chinese "Couchbase"
507     static const char key0[] = "沙发数据库";
508     static const char val0[] = "some Chinese value";
509     check((ret = store(h, h1, NULL, OPERATION_SET, key0, val0, &i)) == ENGINE_SUCCESS,
510           "Failed set Chinese key");
511     check_key_value(h, h1, key0, val0, strlen(val0));
512     h1->release(h, NULL, i);
513     // Traditional Chinese "Couchbase"
514     static const char key1[] = "沙發數據庫";
515     static const char val1[] = "some Traditional Chinese value";
516     check((ret = store(h, h1, NULL, OPERATION_SET, key1, val1, &i)) == ENGINE_SUCCESS,
517           "Failed set Traditional Chinese key");
518     h1->release(h, NULL, i);
519     // Korean "couch potato"
520     static const char key2[] = "쇼파감자";
521     static const char val2[] = "some Korean value";
522     check((ret = store(h, h1, NULL, OPERATION_SET, key2, val2, &i)) == ENGINE_SUCCESS,
523           "Failed set Korean key");
524     h1->release(h, NULL, i);
525     // Russian "couch potato"
526     static const char key3[] = "лодырь, лентяй";
527     static const char val3[] = "some Russian value";
528     check((ret = store(h, h1, NULL, OPERATION_SET, key3, val3, &i)) == ENGINE_SUCCESS,
529           "Failed set Russian key");
530     h1->release(h, NULL, i);
531     // Japanese "couch potato"
532     static const char key4[] = "カウチポテト";
533     static const char val4[] = "some Japanese value";
534     check((ret = store(h, h1, NULL, OPERATION_SET, key4, val4, &i)) == ENGINE_SUCCESS,
535           "Failed set Japanese key");
536     h1->release(h, NULL, i);
537     // Indian char key, and no idea what it is
538     static const char key5[] = "हरियानवी";
539     static const char val5[] = "some Indian value";
540     check((ret = store(h, h1, NULL, OPERATION_SET, key5, val5, &i)) == ENGINE_SUCCESS,
541           "Failed set Indian key");
542     h1->release(h, NULL, i);
543     // Portuguese translation "couch potato"
544     static const char key6[] = "sedentário";
545     static const char val6[] = "some Portuguese value";
546     check((ret = store(h, h1, NULL, OPERATION_SET, key6, val6, &i)) == ENGINE_SUCCESS,
547           "Failed set Portuguese key");
548     h1->release(h, NULL, i);
549     // Arabic translation "couch potato"
550     static const char key7[] = "الحافلةالبطاطة";
551     static const char val7[] = "some Arabic value";
552     check((ret = store(h, h1, NULL, OPERATION_SET, key7, val7, &i)) == ENGINE_SUCCESS,
553           "Failed set Arabic key");
554     h1->release(h, NULL, i);
555
556     if (isWarmupEnabled(h, h1)) {
557         // Check that after warmup the keys are still present.
558         testHarness.reload_engine(&h, &h1,
559                                   testHarness.engine_path,
560                                   testHarness.get_current_testcase()->cfg,
561                                   true, false);
562         wait_for_warmup_complete(h, h1);
563         check_key_value(h, h1, key0, val0, strlen(val0));
564         check_key_value(h, h1, key1, val1, strlen(val1));
565         check_key_value(h, h1, key2, val2, strlen(val2));
566         check_key_value(h, h1, key3, val3, strlen(val3));
567         check_key_value(h, h1, key4, val4, strlen(val4));
568         check_key_value(h, h1, key5, val5, strlen(val5));
569         check_key_value(h, h1, key6, val6, strlen(val6));
570         check_key_value(h, h1, key7, val7, strlen(val7));
571     }
572     return SUCCESS;
573 }
574
575 static enum test_result test_binKeys(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
576     item *i = NULL;
577     ENGINE_ERROR_CODE ret;
578
579     // binary key with char values beyond 0x7F
580     static const char key0[] = "\xe0\xed\xf1\x6f\x7f\xf8\xfa";
581     static const char val0[] = "some value val8";
582     check((ret = store(h, h1, NULL, OPERATION_SET, key0, val0, &i)) == ENGINE_SUCCESS,
583           "Failed set binary key0");
584     check_key_value(h, h1, key0, val0, strlen(val0));
585     h1->release(h, NULL, i);
586     // binary keys with char values beyond 0x7F
587     static const char key1[] = "\xf1\xfd\xfe\xff\xf0\xf8\xef";
588     static const char val1[] = "some value val9";
589     check((ret = store(h, h1, NULL, OPERATION_SET, key1, val1, &i)) == ENGINE_SUCCESS,
590           "Failed set binary key1");
591     check_key_value(h, h1, key1, val1, strlen(val1));
592     h1->release(h, NULL, i);
593     // binary keys with special utf-8 BOM (Byte Order Mark) values 0xBB 0xBF 0xEF
594     static const char key2[] = "\xff\xfe\xbb\xbf\xef";
595     static const char val2[] = "some utf-8 bom value";
596     check((ret = store(h, h1, NULL, OPERATION_SET, key2, val2, &i)) == ENGINE_SUCCESS,
597           "Failed set binary utf-8 bom key");
598     check_key_value(h, h1, key2, val2, strlen(val2));
599     h1->release(h, NULL, i);
600     // binary keys with special utf-16BE BOM values "U+FEFF"
601     static const char key3[] = "U+\xfe\xff\xefU+\xff\xfe";
602     static const char val3[] = "some utf-16 bom value";
603     check((ret = store(h, h1, NULL, OPERATION_SET, key3, val3, &i)) == ENGINE_SUCCESS,
604           "Failed set binary utf-16 bom key");
605     check_key_value(h, h1, key3, val3, strlen(val3));
606     h1->release(h, NULL, i);
607
608     if (isWarmupEnabled(h, h1)) {
609         testHarness.reload_engine(&h, &h1,
610                                   testHarness.engine_path,
611                                   testHarness.get_current_testcase()->cfg,
612                                   true, false);
613         wait_for_warmup_complete(h, h1);
614         check_key_value(h, h1, key0, val0, strlen(val0));
615         check_key_value(h, h1, key1, val1, strlen(val1));
616         check_key_value(h, h1, key2, val2, strlen(val2));
617         check_key_value(h, h1, key3, val3, strlen(val3));
618     }
619     return SUCCESS;
620 }
621
622 static enum test_result test_restart_bin_val(ENGINE_HANDLE *h,
623                                              ENGINE_HANDLE_V1 *h1) {
624     if (!isWarmupEnabled(h, h1)) {
625         return SKIPPED;
626     }
627
628     char binaryData[] = "abcdefg\0gfedcba";
629     cb_assert(sizeof(binaryData) != strlen(binaryData));
630
631     item *i = NULL;
632     checkeq(ENGINE_SUCCESS,
633             storeCasVb11(h, h1, NULL, OPERATION_SET, "key",
634                          binaryData, sizeof(binaryData), 82758, &i, 0, 0),
635             "Failed set.");
636     h1->release(h, NULL, i);
637
638     testHarness.reload_engine(&h, &h1,
639                               testHarness.engine_path,
640                               testHarness.get_current_testcase()->cfg,
641                               true, false);
642     wait_for_warmup_complete(h, h1);
643
644     check_key_value(h, h1, "key", binaryData, sizeof(binaryData));
645     return SUCCESS;
646 }
647
648 static enum test_result test_wrong_vb_get(ENGINE_HANDLE *h,
649                                           ENGINE_HANDLE_V1 *h1) {
650     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
651     checkeq(ENGINE_NOT_MY_VBUCKET, verify_key(h, h1, "key", 1),
652             "Expected wrong bucket.");
653     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
654     return SUCCESS;
655 }
656
657 static enum test_result test_vb_get_pending(ENGINE_HANDLE *h,
658                                             ENGINE_HANDLE_V1 *h1) {
659     check(set_vbucket_state(h, h1, 1, vbucket_state_pending),
660           "Failed to set vbucket state.");
661     const void *cookie = testHarness.create_cookie();
662     testHarness.set_ewouldblock_handling(cookie, false);
663
664     item *i = NULL;
665     checkeq(ENGINE_EWOULDBLOCK,
666             get(h, h1, cookie, &i, "key", 1),
667             "Expected woodblock.");
668     h1->release(h, NULL, i);
669
670     testHarness.destroy_cookie(cookie);
671     return SUCCESS;
672 }
673
674 static enum test_result test_vb_get_replica(ENGINE_HANDLE *h,
675                                             ENGINE_HANDLE_V1 *h1) {
676     check(set_vbucket_state(h, h1, 1, vbucket_state_replica),
677           "Failed to set vbucket state.");
678     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
679     checkeq(ENGINE_NOT_MY_VBUCKET,
680             verify_key(h, h1, "key", 1),
681             "Expected not my bucket.");
682     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
683     return SUCCESS;
684 }
685
686 static enum test_result test_wrong_vb_set(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
687     return test_wrong_vb_mutation(h, h1, OPERATION_SET);
688 }
689
690 static enum test_result test_wrong_vb_cas(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
691     return test_wrong_vb_mutation(h, h1, OPERATION_CAS);
692 }
693
694 static enum test_result test_wrong_vb_add(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
695     return test_wrong_vb_mutation(h, h1, OPERATION_ADD);
696 }
697
698 static enum test_result test_wrong_vb_replace(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
699     return test_wrong_vb_mutation(h, h1, OPERATION_REPLACE);
700 }
701
702 static enum test_result test_wrong_vb_del(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
703     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
704     checkeq(ENGINE_NOT_MY_VBUCKET, del(h, h1, "key", 0, 1),
705             "Expected wrong bucket.");
706     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
707     return SUCCESS;
708 }
709
710 /* Returns a string in the format "%Y-%m-%d %H:%M:%S" of the specified
711  * time point.
712  */
713 std::string make_time_string(std::chrono::system_clock::time_point time_point) {
714     time_t tt = std::chrono::system_clock::to_time_t(time_point);
715 #ifdef _MSC_VER
716     // Windows' gmtime() is already thread-safe.
717     struct tm* split = gmtime(&tt);
718 #else
719     struct tm local_storage;
720     struct tm* split = gmtime_r(&tt, &local_storage);
721 #endif
722     char timeStr[20];
723     strftime(timeStr, 20, "%Y-%m-%d %H:%M:%S", split);
724     return timeStr;
725 }
726
727 static enum test_result test_expiry_pager_settings(ENGINE_HANDLE *h,
728                                                    ENGINE_HANDLE_V1 *h1) {
729
730     cb_assert(!get_bool_stat(h, h1, "ep_exp_pager_enabled"));
731     checkeq(3600, get_int_stat(h, h1, "ep_exp_pager_stime"),
732             "Expiry pager sleep time not expected");
733     set_param(h, h1, protocol_binary_engine_param_flush,
734               "exp_pager_stime", "1");
735     checkeq(1, get_int_stat(h, h1, "ep_exp_pager_stime"),
736             "Expiry pager sleep time not updated");
737     cb_assert(!get_bool_stat(h, h1, "ep_exp_pager_enabled"));
738     sleep(1);
739     checkeq(0, get_int_stat(h, h1, "ep_num_expiry_pager_runs"),
740             "Expiry pager run count is not zero");
741
742     set_param(h, h1, protocol_binary_engine_param_flush,
743               "exp_pager_enabled", "true");
744     checkeq(1, get_int_stat(h, h1, "ep_exp_pager_stime"),
745             "Expiry pager sleep time not updated");
746     wait_for_stat_to_be_gte(h, h1, "ep_num_expiry_pager_runs", 1);
747
748     // Reload engine
749     testHarness.reload_engine(&h, &h1,
750                               testHarness.engine_path,
751                               testHarness.get_current_testcase()->cfg,
752                               true, false);
753     wait_for_warmup_complete(h, h1);
754     cb_assert(!get_bool_stat(h, h1, "ep_exp_pager_enabled"));
755
756     // Enable expiry pager again
757     set_param(h, h1, protocol_binary_engine_param_flush,
758               "exp_pager_enabled", "true");
759
760     checkeq(get_int_stat(h, h1, "ep_exp_pager_initial_run_time"), -1,
761             "Task time should be disable upon warmup");
762
763     std::string err_msg;
764     // Update exp_pager_initial_run_time and ensure the update is successful
765     set_param(h, h1, protocol_binary_engine_param_flush,
766               "exp_pager_initial_run_time", "3");
767     std::string expected_time = "03:00";
768     std::string str = get_str_stat(h, h1, "ep_expiry_pager_task_time");
769     err_msg.assign("Updated time incorrect, expect: " +
770                    expected_time + ", actual: " + str.substr(11, 5));
771     checkeq(0, str.substr(11, 5).compare(expected_time), err_msg.c_str());
772
773     // Update exp_pager_stime by 30 minutes and ensure that the update is successful
774     const std::chrono::minutes update_by{30};
775     std::string targetTaskTime1{make_time_string(std::chrono::system_clock::now() +
776                                                  update_by)};
777
778     set_param(h, h1, protocol_binary_engine_param_flush, "exp_pager_stime",
779               std::to_string(update_by.count() * 60).c_str());
780     str = get_str_stat(h, h1, "ep_expiry_pager_task_time");
781
782     std::string targetTaskTime2{make_time_string(std::chrono::system_clock::now() +
783                                                  update_by)};
784
785     // ep_expiry_pager_task_time should fall within the range of
786     // targetTaskTime1 and targetTaskTime2
787     err_msg.assign("Unexpected task time range, expect: " +
788                    targetTaskTime1 + " <= " + str + " <= " + targetTaskTime2);
789     check(targetTaskTime1 <= str, err_msg.c_str());
790     check(str <= targetTaskTime2, err_msg.c_str());
791
792     return SUCCESS;
793 }
794
795 static enum test_result test_expiry_with_xattr(ENGINE_HANDLE* h,
796                                                ENGINE_HANDLE_V1* h1) {
797     const char* key = "test_expiry";
798     cb::xattr::Blob blob;
799
800     //Add a few XAttrs
801     blob.set(to_const_byte_buffer("user"),
802              to_const_byte_buffer("{\"author\":\"bubba\"}"));
803     blob.set(to_const_byte_buffer("_sync"),
804              to_const_byte_buffer("{\"cas\":\"0xdeadbeefcafefeed\"}"));
805     blob.set(to_const_byte_buffer("meta"),
806              to_const_byte_buffer("{\"content-type\":\"text\"}"));
807
808     auto xattr_value = blob.finalize();
809
810     //Now, append user data to the xattrs and store the data
811     std::string value_data("test_expiry_value");
812     std::vector<char> data;
813     std::copy(xattr_value.buf, xattr_value.buf + xattr_value.len,
814               std::back_inserter(data));
815     std::copy(value_data.c_str(), value_data.c_str() + value_data.length(),
816               std::back_inserter(data));
817
818     const void* cookie = testHarness.create_cookie();
819
820     item *itm = nullptr;
821     checkeq(ENGINE_SUCCESS,
822             storeCasVb11(h, h1, cookie, OPERATION_SET, key,
823                          reinterpret_cast<char*>(data.data()),
824                          data.size(), 9258, &itm, 0, 0, 10,
825                          PROTOCOL_BINARY_DATATYPE_XATTR),
826             "Failed to store xattr document");
827     h1->release(h, nullptr, itm);
828
829     if (isPersistentBucket(h, h1)) {
830         wait_for_flusher_to_settle(h, h1);
831     }
832
833     testHarness.time_travel(11);
834
835     checkeq(true,
836             get_meta(h, h1, "test_expiry", true, GetMetaVersion::V2, cookie),
837             "Get meta command failed");
838     auto prev_revseqno = last_meta.revSeqno;
839
840     checkeq(static_cast<uint8_t>(PROTOCOL_BINARY_DATATYPE_XATTR),
841             last_datatype.load(), "Datatype is not XATTR");
842
843     checkeq(ENGINE_SUCCESS,
844             get(h, h1, cookie, &itm, key, 0,
845                 DocStateFilter::AliveOrDeleted),
846                 "Unable to get a deleted item");
847
848     checkeq(true,
849             get_meta(h, h1, "test_expiry", false, GetMetaVersion::V1, cookie),
850             "Get meta command failed");
851
852     checkeq(last_meta.revSeqno, prev_revseqno + 1,
853             "rev seqno must have incremented by 1");
854
855     /* Retrieve the item info and create a new blob out of the data */
856     item_info info;
857     checkeq(true, h1->get_item_info(h, cookie, itm, &info),
858             "Unable to retrieve item info");
859
860     cb::byte_buffer value_buf{static_cast<uint8_t*>(info.value[0].iov_base),
861                               info.value[0].iov_len};
862
863     cb::xattr::Blob new_blob(value_buf);
864
865     /* Only system extended attributes need to be present at this point.
866      * Thus, check the blob length with the system size.
867      */
868     const auto systemsize = new_blob.finalize().len;
869
870     checkeq(systemsize, new_blob.get_system_size(),
871             "The size of the blob doesn't match the size of system attributes");
872
873     const std::string& cas_str{"{\"cas\":\"0xdeadbeefcafefeed\"}"};
874     const std::string& sync_str = to_string(blob.get(to_const_byte_buffer("_sync")));
875
876     checkeq(cas_str, sync_str , "system xattr is invalid");
877
878     h1->release(h, nullptr, itm);
879     testHarness.destroy_cookie(cookie);
880
881     return SUCCESS;
882 }
883
884 static enum test_result test_expiry(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
885     const char *key = "test_expiry";
886     const char *data = "some test data here.";
887
888     item *it = NULL;
889
890     ENGINE_ERROR_CODE rv;
891     rv = allocate(h, h1, NULL, &it, key, strlen(data), 0, 2,
892                   PROTOCOL_BINARY_RAW_BYTES, 0);
893     checkeq(ENGINE_SUCCESS, rv, "Allocation failed.");
894
895     item_info info;
896     if (!h1->get_item_info(h, NULL, it, &info)) {
897         abort();
898     }
899     memcpy(info.value[0].iov_base, data, strlen(data));
900
901     uint64_t cas = 0;
902     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, DocumentState::Alive);
903     checkeq(ENGINE_SUCCESS, rv, "Set failed.");
904     check_key_value(h, h1, key, data, strlen(data));
905     h1->release(h, NULL, it);
906
907     testHarness.time_travel(5);
908     checkeq(ENGINE_KEY_ENOENT,
909             get(h, h1, NULL, &it, key, 0),
910             "Item didn't expire");
911
912     int expired_access = get_int_stat(h, h1, "ep_expired_access");
913     int expired_pager = get_int_stat(h, h1, "ep_expired_pager");
914     int active_expired = get_int_stat(h, h1, "vb_active_expired");
915     checkeq(0, expired_pager, "Expected zero expired item by pager");
916     checkeq(1, expired_access, "Expected an expired item on access");
917     checkeq(1, active_expired, "Expected an expired active item");
918     checkeq(ENGINE_SUCCESS, store(h, h1, NULL, OPERATION_SET, key, data, &it),
919             "Failed set.");
920     h1->release(h, NULL, it);
921
922     // When run under full eviction, the total item stats are set from the
923     // flusher. So we need to wait for it to finish before checking the
924     // total number of items.
925     wait_for_flusher_to_settle(h, h1);
926
927     std::stringstream ss;
928     ss << "curr_items stat should be still 1 after ";
929     ss << "overwriting the key that was expired, but not purged yet";
930     checkeq(1, get_int_stat(h, h1, "curr_items"), ss.str().c_str());
931
932     return SUCCESS;
933 }
934
935 static enum test_result test_expiry_loader(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
936     if (!isWarmupEnabled(h, h1)) {
937         return SKIPPED;
938     }
939     const char *key = "test_expiry_loader";
940     const char *data = "some test data here.";
941
942     item *it = NULL;
943
944     ENGINE_ERROR_CODE rv;
945     rv = allocate(h, h1, NULL, &it, key, strlen(data), 0, 2,
946                   PROTOCOL_BINARY_RAW_BYTES, 0);
947     checkeq(ENGINE_SUCCESS, rv, "Allocation failed.");
948
949     item_info info;
950     if (!h1->get_item_info(h, NULL, it, &info)) {
951         abort();
952     }
953     memcpy(info.value[0].iov_base, data, strlen(data));
954
955     uint64_t cas = 0;
956     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, DocumentState::Alive);
957     checkeq(ENGINE_SUCCESS, rv, "Set failed.");
958     check_key_value(h, h1, key, data, strlen(data));
959     h1->release(h, NULL, it);
960
961     testHarness.time_travel(3);
962
963     checkeq(ENGINE_KEY_ENOENT,
964             get(h, h1, NULL, &it, key, 0),
965             "Item didn't expire");
966
967     // Restart the engine to ensure the above expired item is not loaded
968     testHarness.reload_engine(&h, &h1,
969                               testHarness.engine_path,
970                               testHarness.get_current_testcase()->cfg,
971                               true, false);
972     wait_for_warmup_complete(h, h1);
973     cb_assert(0 == get_int_stat(h, h1, "ep_warmup_value_count", "warmup"));
974
975     return SUCCESS;
976 }
977
978 static enum test_result test_expiration_on_compaction(ENGINE_HANDLE *h,
979                                                       ENGINE_HANDLE_V1 *h1) {
980     if (get_bool_stat(h, h1, "ep_exp_pager_enabled")) {
981         set_param(h, h1, protocol_binary_engine_param_flush,
982                   "exp_pager_enabled", "false");
983     }
984
985     checkeq(1, get_int_stat(h, h1, "vb_0:persistence:num_visits",
986                             "checkpoint"), "Cursor moved before item load");
987
988     for (int i = 0; i < 50; i++) {
989         item *itm = NULL;
990         std::stringstream ss;
991         ss << "key" << i;
992         checkeq(ENGINE_SUCCESS,
993                 store(h, h1, NULL, OPERATION_SET, ss.str().c_str(),
994                       "somevalue", &itm, 0, 0, 10,
995                       PROTOCOL_BINARY_RAW_BYTES),
996                 "Set failed.");
997         h1->release(h, NULL, itm);
998     }
999
1000     wait_for_flusher_to_settle(h, h1);
1001     checkeq(50, get_int_stat(h, h1, "curr_items"),
1002             "Unexpected number of items on database");
1003     check(1 < get_int_stat(h, h1, "vb_0:persistence:num_visits", "checkpoint"),
1004           "Cursor not moved even after flusher runs");
1005
1006     testHarness.time_travel(15);
1007
1008     // Compaction on VBucket
1009     compact_db(h, h1, 0, 0, 0, 0, 0);
1010     wait_for_stat_to_be(h, h1, "ep_pending_compactions", 0);
1011
1012     checkeq(50, get_int_stat(h, h1, "ep_expired_compactor"),
1013             "Unexpected expirations by compactor");
1014
1015     return SUCCESS;
1016 }
1017
1018 static enum test_result test_expiration_on_warmup(ENGINE_HANDLE *h,
1019                                                   ENGINE_HANDLE_V1 *h1) {
1020     if (!isWarmupEnabled(h, h1)) {
1021         return SKIPPED;
1022     }
1023
1024     set_param(h, h1, protocol_binary_engine_param_flush,
1025               "exp_pager_enabled", "false");
1026     int pager_runs = get_int_stat(h, h1, "ep_num_expiry_pager_runs");
1027
1028     const char *key = "KEY";
1029     const char *data = "VALUE";
1030
1031     item *it = NULL;
1032
1033     ENGINE_ERROR_CODE rv;
1034     rv = allocate(h, h1, NULL, &it, key, strlen(data), 0, 10,
1035                       PROTOCOL_BINARY_RAW_BYTES, 0);
1036     checkeq(ENGINE_SUCCESS, rv, "Allocation failed.");
1037
1038     item_info info;
1039     if (!h1->get_item_info(h, NULL, it, &info)) {
1040         abort();
1041     }
1042     memcpy(info.value[0].iov_base, data, strlen(data));
1043
1044     uint64_t cas = 0;
1045     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, DocumentState::Alive);
1046     checkeq(ENGINE_SUCCESS, rv, "Set failed.");
1047     check_key_value(h, h1, key, data, strlen(data));
1048     h1->release(h, NULL, it);
1049     wait_for_flusher_to_settle(h, h1);
1050
1051     checkeq(1, get_int_stat(h, h1, "curr_items"), "Failed store item");
1052     testHarness.time_travel(15);
1053
1054     checkeq(pager_runs, get_int_stat(h, h1, "ep_num_expiry_pager_runs"),
1055             "Expiry pager shouldn't have run during this time");
1056
1057     // Restart the engine to ensure the above item is expired
1058     testHarness.reload_engine(&h, &h1,
1059                               testHarness.engine_path,
1060                               testHarness.get_current_testcase()->cfg,
1061                               true, false);
1062     wait_for_warmup_complete(h, h1);
1063     check(get_bool_stat(h, h1, "ep_exp_pager_enabled"),
1064           "Expiry pager should be enabled on warmup");
1065
1066     // Wait for the expiry pager to run and expire our item.
1067     wait_for_stat_to_be_gte(h, h1, "ep_expired_pager", 1, nullptr, /*secs*/10);
1068
1069     // Note: previously we checked that curr_items was zero here (immediately
1070     // after waiting for ep_expired_pager == 1), however we cannot assume that
1071     // - items are actually expired asynchronously.
1072     // See EPStore::deleteExpiredItem - for non-temporary, expired items we
1073     // call processSoftDelete (soft-marking the item as deleted in the
1074     // hashtable), and then call queueDirty to queue a deletion, and then
1075     // increment the expired stat. Only when that delete is actually persisted
1076     // and the deleted callback is invoked -
1077     // PeristenceCallback::callback(int&) - is curr_items finally decremented.
1078     // Therefore we need to wait for the flusher to settle (i.e. delete
1079     // callback to be called) for the curr_items stat to be accurate.
1080     wait_for_flusher_to_settle(h, h1);
1081
1082     checkeq(0, get_int_stat(h, h1, "curr_items"),
1083             "The item should have been expired.");
1084
1085     return SUCCESS;
1086
1087 }
1088
1089 static enum test_result test_bug3454(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1090     if (!isWarmupEnabled(h, h1)) {
1091         return SKIPPED;
1092     }
1093
1094     const char *key = "test_expiry_duplicate_warmup";
1095     const char *data = "some test data here.";
1096
1097     item *it = NULL;
1098
1099     ENGINE_ERROR_CODE rv;
1100     rv = allocate(h, h1, NULL, &it, key, strlen(data), 0, 5,
1101                       PROTOCOL_BINARY_RAW_BYTES, 0);
1102     checkeq(ENGINE_SUCCESS, rv, "Allocation failed.");
1103
1104     item_info info;
1105     if (!h1->get_item_info(h, NULL, it, &info)) {
1106         abort();
1107     }
1108     memcpy(info.value[0].iov_base, data, strlen(data));
1109
1110     uint64_t cas = 0;
1111     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, DocumentState::Alive);
1112     checkeq(ENGINE_SUCCESS, rv, "Set failed.");
1113     check_key_value(h, h1, key, data, strlen(data));
1114     h1->release(h, NULL, it);
1115     wait_for_flusher_to_settle(h, h1);
1116
1117     // Advance the ep_engine time by 10 sec for the above item to be expired.
1118     testHarness.time_travel(10);
1119     checkeq(ENGINE_KEY_ENOENT,
1120             get(h, h1, NULL, &it, key, 0),
1121             "Item didn't expire");
1122
1123     rv = allocate(h, h1, NULL, &it, key, strlen(data), 0, 0,
1124                       PROTOCOL_BINARY_RAW_BYTES, 0);
1125     checkeq(ENGINE_SUCCESS, rv, "Allocation failed.");
1126
1127     if (!h1->get_item_info(h, NULL, it, &info)) {
1128         abort();
1129     }
1130     memcpy(info.value[0].iov_base, data, strlen(data));
1131
1132     cas = 0;
1133     // Add a new item with the same key.
1134     rv = h1->store(h, NULL, it, &cas, OPERATION_ADD, DocumentState::Alive);
1135     checkeq(ENGINE_SUCCESS, rv, "Add failed.");
1136     check_key_value(h, h1, key, data, strlen(data));
1137     h1->release(h, NULL, it);
1138     wait_for_flusher_to_settle(h, h1);
1139
1140     checkeq(ENGINE_SUCCESS,
1141             get(h, h1, NULL, &it, key, 0),
1142             "Item shouldn't expire");
1143     h1->release(h, NULL, it);
1144
1145     // Restart the engine to ensure the above unexpired new item is loaded
1146     testHarness.reload_engine(&h, &h1,
1147                               testHarness.engine_path,
1148                               testHarness.get_current_testcase()->cfg,
1149                               true, false);
1150     wait_for_warmup_complete(h, h1);
1151     cb_assert(1 == get_int_stat(h, h1, "ep_warmup_value_count", "warmup"));
1152     cb_assert(0 == get_int_stat(h, h1, "ep_warmup_dups", "warmup"));
1153
1154     return SUCCESS;
1155 }
1156
1157 static enum test_result test_bug3522(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1158     if (!isWarmupEnabled(h, h1)) {
1159         return SKIPPED;
1160     }
1161
1162     const char *key = "test_expiry_no_items_warmup";
1163     const char *data = "some test data here.";
1164
1165     item *it = NULL;
1166
1167     ENGINE_ERROR_CODE rv;
1168     rv = allocate(h, h1, NULL, &it, key, strlen(data), 0, 0,
1169                   PROTOCOL_BINARY_RAW_BYTES, 0);
1170     checkeq(ENGINE_SUCCESS, rv, "Allocation failed.");
1171
1172     item_info info;
1173     if (!h1->get_item_info(h, NULL, it, &info)) {
1174         abort();
1175     }
1176     memcpy(info.value[0].iov_base, data, strlen(data));
1177
1178     uint64_t cas = 0;
1179     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, DocumentState::Alive);
1180     checkeq(ENGINE_SUCCESS, rv, "Set failed.");
1181     check_key_value(h, h1, key, data, strlen(data));
1182     h1->release(h, NULL, it);
1183     wait_for_flusher_to_settle(h, h1);
1184
1185     // Add a new item with the same key and 2 sec of expiration.
1186     const char *new_data = "new data here.";
1187     rv = allocate(h, h1, NULL, &it, key, strlen(new_data), 0, 2,
1188                   PROTOCOL_BINARY_RAW_BYTES, 0);
1189     checkeq(ENGINE_SUCCESS, rv, "Allocation failed.");
1190
1191     if (!h1->get_item_info(h, NULL, it, &info)) {
1192         abort();
1193     }
1194     memcpy(info.value[0].iov_base, new_data, strlen(new_data));
1195
1196     int pager_runs = get_int_stat(h, h1, "ep_num_expiry_pager_runs");
1197     cas = 0;
1198     rv = h1->store(h, NULL, it, &cas, OPERATION_SET, DocumentState::Alive);
1199     checkeq(ENGINE_SUCCESS, rv, "Set failed.");
1200     check_key_value(h, h1, key, new_data, strlen(new_data));
1201     h1->release(h, NULL, it);
1202     testHarness.time_travel(3);
1203     wait_for_stat_change(h, h1, "ep_num_expiry_pager_runs", pager_runs);
1204     wait_for_flusher_to_settle(h, h1);
1205
1206     // Restart the engine.
1207     testHarness.reload_engine(&h, &h1,
1208                               testHarness.engine_path,
1209                               testHarness.get_current_testcase()->cfg,
1210                               true, false);
1211     wait_for_warmup_complete(h, h1);
1212     // TODO: modify this for a better test case
1213     cb_assert(0 == get_int_stat(h, h1, "ep_warmup_dups", "warmup"));
1214
1215     return SUCCESS;
1216 }
1217
1218 static enum test_result test_get_replica_active_state(ENGINE_HANDLE *h,
1219                                                       ENGINE_HANDLE_V1 *h1) {
1220     protocol_binary_request_header *pkt;
1221     pkt = prepare_get_replica(h, h1, vbucket_state_active);
1222     checkeq(ENGINE_SUCCESS,
1223             h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
1224             "Get Replica Failed");
1225     checkeq(PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, last_status.load(),
1226             "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
1227
1228     cb_free(pkt);
1229     return SUCCESS;
1230 }
1231
1232 static enum test_result test_get_replica_pending_state(ENGINE_HANDLE *h,
1233                                                        ENGINE_HANDLE_V1 *h1) {
1234     protocol_binary_request_header *pkt;
1235
1236     const void *cookie = testHarness.create_cookie();
1237     testHarness.set_ewouldblock_handling(cookie, false);
1238     pkt = prepare_get_replica(h, h1, vbucket_state_pending);
1239     checkeq(ENGINE_EWOULDBLOCK,
1240             h1->unknown_command(h, cookie, pkt, add_response, testHarness.doc_namespace),
1241             "Should have returned error for pending state");
1242     testHarness.destroy_cookie(cookie);
1243     cb_free(pkt);
1244     return SUCCESS;
1245 }
1246
1247 static enum test_result test_get_replica_dead_state(ENGINE_HANDLE *h,
1248                                                     ENGINE_HANDLE_V1 *h1) {
1249     protocol_binary_request_header *pkt;
1250     pkt = prepare_get_replica(h, h1, vbucket_state_dead);
1251     checkeq(ENGINE_SUCCESS,
1252             h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
1253             "Get Replica Failed");
1254     checkeq(PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, last_status.load(),
1255             "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
1256
1257     cb_free(pkt);
1258     return SUCCESS;
1259 }
1260
1261 static enum test_result test_get_replica(ENGINE_HANDLE *h,
1262                                          ENGINE_HANDLE_V1 *h1) {
1263     protocol_binary_request_header *pkt;
1264     pkt = prepare_get_replica(h, h1, vbucket_state_replica);
1265     checkeq(ENGINE_SUCCESS,
1266             h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
1267             "Get Replica Failed");
1268     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
1269             "Expected PROTOCOL_BINARY_RESPONSE_SUCCESS response.");
1270     checkeq(std::string("replicadata"), last_body,
1271             "Should have returned identical value");
1272
1273     cb_free(pkt);
1274     return SUCCESS;
1275 }
1276
1277 static enum test_result test_get_replica_non_resident(ENGINE_HANDLE *h,
1278                                                       ENGINE_HANDLE_V1 *h1) {
1279
1280     item *i = NULL;
1281     checkeq(ENGINE_SUCCESS,
1282             store(h, h1, NULL, OPERATION_SET, "key", "value", &i, 0, 0),
1283             "Store Failed");
1284     h1->release(h, NULL, i);
1285     wait_for_flusher_to_settle(h, h1);
1286     wait_for_stat_to_be(h, h1, "ep_total_persisted", 1);
1287
1288     evict_key(h, h1, "key", 0, "Ejected.");
1289     check(set_vbucket_state(h, h1, 0, vbucket_state_replica),
1290           "Failed to set vbucket to replica");
1291
1292     get_replica(h, h1, "key", 0);
1293     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
1294             "Expected success");
1295
1296     return SUCCESS;
1297 }
1298
1299 static enum test_result test_get_replica_invalid_key(ENGINE_HANDLE *h,
1300                                                      ENGINE_HANDLE_V1 *h1) {
1301     protocol_binary_request_header *pkt;
1302     bool makeinvalidkey = true;
1303     pkt = prepare_get_replica(h, h1, vbucket_state_replica, makeinvalidkey);
1304     checkeq(ENGINE_SUCCESS,
1305             h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
1306             "Get Replica Failed");
1307     checkeq(PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET, last_status.load(),
1308             "Expected PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET response.");
1309     cb_free(pkt);
1310     return SUCCESS;
1311 }
1312
1313 static enum test_result test_vb_del_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1314     const void *cookie = testHarness.create_cookie();
1315     testHarness.set_ewouldblock_handling(cookie, false);
1316     check(set_vbucket_state(h, h1, 1, vbucket_state_pending),
1317           "Failed to set vbucket state.");
1318     checkeq(ENGINE_EWOULDBLOCK, del(h, h1, "key", 0, 1, cookie),
1319             "Expected woodblock.");
1320     testHarness.destroy_cookie(cookie);
1321     return SUCCESS;
1322 }
1323
1324 static enum test_result test_vb_del_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1325     check(set_vbucket_state(h, h1, 1, vbucket_state_replica),
1326           "Failed to set vbucket state.");
1327     int numNotMyVBucket = get_int_stat(h, h1, "ep_num_not_my_vbuckets");
1328     checkeq(ENGINE_NOT_MY_VBUCKET, del(h, h1, "key", 0, 1),
1329             "Expected not my vbucket.");
1330     wait_for_stat_change(h, h1, "ep_num_not_my_vbuckets", numNotMyVBucket);
1331     return SUCCESS;
1332 }
1333
1334 static enum test_result test_vbucket_get_miss(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1335     return verify_vbucket_missing(h, h1, 1) ? SUCCESS : FAIL;
1336 }
1337
1338 static enum test_result test_vbucket_get(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1339     return verify_vbucket_state(h, h1, 0, vbucket_state_active) ? SUCCESS : FAIL;
1340 }
1341
1342 static enum test_result test_vbucket_create(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1343     if (!verify_vbucket_missing(h, h1, 1)) {
1344         fprintf(stderr, "vbucket wasn't missing.\n");
1345         return FAIL;
1346     }
1347
1348     if (!set_vbucket_state(h, h1, 1, vbucket_state_active)) {
1349         fprintf(stderr, "set state failed.\n");
1350         return FAIL;
1351     }
1352
1353     return verify_vbucket_state(h, h1, 1, vbucket_state_active) ? SUCCESS : FAIL;
1354 }
1355
1356 static enum test_result test_takeover_stats_race_with_vb_create_TAP(
1357                                     ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1358     check(set_vbucket_state(h, h1, 1, vbucket_state_active),
1359           "Failed to set vbucket state information");
1360
1361     checkeq(0,
1362             get_int_stat(h, h1, "on_disk_deletes", "tap-vbtakeover 1"),
1363             "Invalid number of on-disk deletes");
1364
1365     return SUCCESS;
1366 }
1367
1368 static enum test_result test_takeover_stats_race_with_vb_create_DCP(
1369                                     ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1370     check(set_vbucket_state(h, h1, 1, vbucket_state_active),
1371           "Failed to set vbucket state information");
1372
1373     checkeq(0,
1374             get_int_stat(h, h1, "on_disk_deletes", "dcp-vbtakeover 1"),
1375             "Invalid number of on-disk deletes");
1376
1377     return SUCCESS;
1378 }
1379
1380 static enum test_result test_takeover_stats_num_persisted_deletes(
1381                                     ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1382     /* set an item */
1383     std::string key("key");
1384     checkeq(ENGINE_SUCCESS,
1385             store(h, h1, NULL, OPERATION_SET, key.c_str(), "data", nullptr),
1386             "Failed to store an item");
1387
1388     /* delete the item */
1389     checkeq(ENGINE_SUCCESS, del(h, h1, key.c_str(), 0, 0),
1390             "Failed to delete the item");
1391
1392     /* wait for persistence */
1393     wait_for_flusher_to_settle(h, h1);
1394
1395     /* check if persisted deletes stats is got correctly */
1396     checkeq(1,
1397             get_int_stat(h, h1, "on_disk_deletes", "dcp-vbtakeover 0"),
1398             "Invalid number of on-disk deletes");
1399
1400     return SUCCESS;
1401 }
1402
1403 static enum test_result test_vbucket_compact(ENGINE_HANDLE *h,
1404                                              ENGINE_HANDLE_V1 *h1) {
1405     const char *key = "Carss";
1406     const char *value = "pollute";
1407     if (!verify_vbucket_missing(h, h1, 0)) {
1408         fprintf(stderr, "vbucket wasn't missing.\n");
1409         return FAIL;
1410     }
1411
1412     if (!set_vbucket_state(h, h1, 0, vbucket_state_active)) {
1413         fprintf(stderr, "set state failed.\n");
1414         return FAIL;
1415     }
1416
1417     check(verify_vbucket_state(h, h1, 0, vbucket_state_active),
1418             "VBucket state not active");
1419
1420     // Set two keys - one to be expired and other to remain...
1421     item *itm = NULL;
1422     checkeq(ENGINE_SUCCESS,
1423             store(h, h1, NULL, OPERATION_SET, key, value, &itm),
1424             "Failed set.");
1425     h1->release(h, NULL, itm);
1426
1427     check_key_value(h, h1, key, value, strlen(value));
1428
1429     // Set a non-expiring key...
1430     checkeq(ENGINE_SUCCESS,
1431             store(h, h1, NULL, OPERATION_SET, "trees", "cleanse", &itm),
1432             "Failed set.");
1433     h1->release(h, NULL, itm);
1434
1435     check_key_value(h, h1, "trees", "cleanse", strlen("cleanse"));
1436
1437     touch(h, h1, key, 0, 11);
1438     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
1439             "touch Carss");
1440
1441     testHarness.time_travel(12);
1442     wait_for_flusher_to_settle(h, h1);
1443
1444     // Store a dummy item since we do not purge the item with highest seqno
1445     checkeq(ENGINE_SUCCESS,
1446             store(h, h1, NULL, OPERATION_SET, "dummykey", "dummyvalue", &itm,
1447                   0, 0, 0),
1448             "Error setting.");
1449     h1->release(h, NULL, itm);
1450
1451     wait_for_flusher_to_settle(h, h1);
1452
1453     checkeq(0, get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno"),
1454             "purge_seqno not found to be zero before compaction");
1455
1456     // Compaction on VBucket
1457     compact_db(h, h1, 0, 0, 2, 3, 1);
1458
1459     wait_for_stat_to_be(h, h1, "ep_pending_compactions", 0);
1460
1461     // the key tree and its value should be intact...
1462     checkeq(ENGINE_SUCCESS, verify_key(h, h1, "trees"),
1463             "key trees should be found.");
1464     // the key Carrs should have disappeared...
1465     ENGINE_ERROR_CODE val = verify_key(h, h1, "Carss");
1466     checkeq(ENGINE_KEY_ENOENT, val, "Key Carss has not expired.");
1467
1468     checkeq(4, get_int_stat(h, h1, "vb_0:purge_seqno", "vbucket-seqno"),
1469             "purge_seqno didn't match expected value");
1470
1471     return SUCCESS;
1472 }
1473
1474 static enum test_result test_compaction_config(ENGINE_HANDLE *h,
1475                                                ENGINE_HANDLE_V1 *h1) {
1476
1477     checkeq(10000,
1478             get_int_stat(h, h1, "ep_compaction_write_queue_cap"),
1479             "Expected compaction queue cap to be 10000");
1480     set_param(h, h1, protocol_binary_engine_param_flush,
1481               "compaction_write_queue_cap", "100000");
1482     checkeq(100000, get_int_stat(h, h1, "ep_compaction_write_queue_cap"),
1483             "Expected compaction queue cap to be 100000");
1484     return SUCCESS;
1485 }
1486
1487 struct comp_thread_ctx {
1488     ENGINE_HANDLE *h;
1489     ENGINE_HANDLE_V1 *h1;
1490     uint16_t vbid;
1491     uint16_t db_file_id;
1492 };
1493
1494 extern "C" {
1495     static void compaction_thread(void *arg) {
1496         struct comp_thread_ctx *ctx = static_cast<comp_thread_ctx *>(arg);
1497         compact_db(ctx->h, ctx->h1, ctx->vbid, ctx->db_file_id, 0, 0, 0);
1498     }
1499 }
1500
1501 static enum test_result test_multiple_vb_compactions(ENGINE_HANDLE *h,
1502                                                      ENGINE_HANDLE_V1 *h1) {
1503     for (uint16_t i = 0; i < 4; ++i) {
1504         if (!set_vbucket_state(h, h1, i, vbucket_state_active)) {
1505             fprintf(stderr, "set state failed for vbucket %d.\n", i);
1506             return FAIL;
1507         }
1508         check(verify_vbucket_state(h, h1, i, vbucket_state_active),
1509               "VBucket state not active");
1510     }
1511
1512     std::vector<std::string> keys;
1513     for (int j = 0; j < 20000; ++j) {
1514         std::stringstream ss;
1515         ss << "key" << j;
1516         std::string key(ss.str());
1517         keys.push_back(key);
1518     }
1519
1520     int count = 0;
1521     std::vector<std::string>::iterator it;
1522     for (it = keys.begin(); it != keys.end(); ++it) {
1523         uint16_t vbid = count % 4;
1524         item *i;
1525         checkeq(ENGINE_SUCCESS,
1526                 store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(), &i, 0, vbid),
1527                 "Failed to store a value");
1528         h1->release(h, NULL, i);
1529         ++count;
1530     }
1531
1532     // Compact multiple vbuckets.
1533     const int n_threads = 4;
1534     cb_thread_t threads[n_threads];
1535     struct comp_thread_ctx ctx[n_threads];
1536
1537     const int num_shards = get_int_stat(h, h1, "ep_workload:num_shards",
1538                                         "workload");
1539
1540     for (int i = 0; i < n_threads; i++) {
1541         ctx[i].h = h;
1542         ctx[i].h1 = h1;
1543         ctx[i].vbid = static_cast<uint16_t>(i);
1544         ctx[i].db_file_id = ctx[i].vbid % num_shards;
1545         int r = cb_create_thread(&threads[i], compaction_thread, &ctx[i], 0);
1546         cb_assert(r == 0);
1547     }
1548
1549     for (int i = 0; i < n_threads; i++) {
1550         int r = cb_join_thread(threads[i]);
1551         cb_assert(r == 0);
1552     }
1553
1554     wait_for_stat_to_be(h, h1, "ep_pending_compactions", 0);
1555
1556     return SUCCESS;
1557 }
1558
1559 static enum test_result
1560 test_multi_vb_compactions_with_workload(ENGINE_HANDLE *h,
1561                                         ENGINE_HANDLE_V1 *h1) {
1562     for (uint16_t i = 0; i < 4; ++i) {
1563         if (!set_vbucket_state(h, h1, i, vbucket_state_active)) {
1564             fprintf(stderr, "set state failed for vbucket %d.\n", i);
1565             return FAIL;
1566         }
1567         check(verify_vbucket_state(h, h1, i, vbucket_state_active),
1568               "VBucket state not active");
1569     }
1570
1571     std::vector<std::string> keys;
1572     for (int j = 0; j < 10000; ++j) {
1573         std::stringstream ss;
1574         ss << "key" << j;
1575         std::string key(ss.str());
1576         keys.push_back(key);
1577     }
1578
1579     int count = 0;
1580     std::vector<std::string>::iterator it;
1581     for (it = keys.begin(); it != keys.end(); ++it) {
1582         uint16_t vbid = count % 4;
1583         item *i;
1584         checkeq(ENGINE_SUCCESS,
1585                 store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(),
1586                       &i, 0, vbid),
1587                 "Failed to store a value");
1588         h1->release(h, NULL, i);
1589         ++count;
1590     }
1591     wait_for_flusher_to_settle(h, h1);
1592
1593     for (int i = 0; i < 2; ++i) {
1594         count = 0;
1595         for (it = keys.begin(); it != keys.end(); ++it) {
1596             uint16_t vbid = count % 4;
1597             item *i = NULL;
1598             checkeq(ENGINE_SUCCESS,
1599                     get(h, h1, NULL, &i, it->c_str(), vbid),
1600                     "Unable to get stored item");
1601             h1->release(h, NULL, i);
1602             ++count;
1603         }
1604     }
1605     wait_for_stat_to_be(h, h1, "ep_workload_pattern", std::string{"read_heavy"});
1606
1607     // Compact multiple vbuckets.
1608     const int n_threads = 4;
1609     cb_thread_t threads[n_threads];
1610     struct comp_thread_ctx ctx[n_threads];
1611
1612     for (int i = 0; i < n_threads; i++) {
1613         ctx[i].h = h;
1614         ctx[i].h1 = h1;
1615         ctx[i].vbid = static_cast<uint16_t>(i);
1616         int r = cb_create_thread(&threads[i], compaction_thread, &ctx[i], 0);
1617         cb_assert(r == 0);
1618     }
1619
1620     for (int i = 0; i < n_threads; i++) {
1621         int r = cb_join_thread(threads[i]);
1622         cb_assert(r == 0);
1623     }
1624
1625     wait_for_stat_to_be(h, h1, "ep_pending_compactions", 0);
1626
1627     return SUCCESS;
1628 }
1629
1630 static enum test_result vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
1631                                              const char* value = NULL) {
1632     check(set_vbucket_state(h, h1, 1, vbucket_state_active),
1633           "Failed to set vbucket state.");
1634
1635     vbucketDelete(h, h1, 2, value);
1636     checkeq(PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET,
1637             last_status.load(),
1638             "Expected failure deleting non-existent bucket.");
1639
1640     check(set_vbucket_state(h, h1, 1, vbucket_state_dead),
1641           "Failed set set vbucket 1 state.");
1642
1643     vbucketDelete(h, h1, 1, value);
1644     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
1645             "Expected failure deleting non-existent bucket.");
1646
1647     check(verify_vbucket_missing(h, h1, 1),
1648           "vbucket 0 was not missing after deleting it.");
1649
1650     return SUCCESS;
1651 }
1652
1653 static enum test_result test_vbucket_destroy_stats(ENGINE_HANDLE *h,
1654                                                    ENGINE_HANDLE_V1 *h1) {
1655
1656     int cacheSize = get_int_stat(h, h1, "ep_total_cache_size");
1657     int overhead = get_int_stat(h, h1, "ep_overhead");
1658     int nonResident = get_int_stat(h, h1, "ep_num_non_resident");
1659
1660     check(set_vbucket_state(h, h1, 1, vbucket_state_active),
1661           "Failed to set vbucket state.");
1662
1663     std::vector<std::string> keys;
1664     for (int j = 0; j < 2000; ++j) {
1665         std::stringstream ss;
1666         ss << "key" << j;
1667         std::string key(ss.str());
1668         keys.push_back(key);
1669     }
1670
1671     int itemsRemoved = get_int_stat(h, h1, "ep_items_rm_from_checkpoints");
1672     std::vector<std::string>::iterator it;
1673     for (it = keys.begin(); it != keys.end(); ++it) {
1674         item *i;
1675         checkeq(ENGINE_SUCCESS,
1676                 store(h, h1, NULL, OPERATION_SET, it->c_str(), it->c_str(),
1677                       &i, 0, 1),
1678                 "Failed to store a value");
1679         h1->release(h, NULL, i);
1680     }
1681     wait_for_flusher_to_settle(h, h1);
1682     testHarness.time_travel(65);
1683     wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
1684
1685     check(set_vbucket_state(h, h1, 1, vbucket_state_dead),
1686           "Failed set set vbucket 1 state.");
1687
1688     int vbucketDel = get_int_stat(h, h1, "ep_vbucket_del");
1689     vbucketDelete(h, h1, 1);
1690     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS,
1691             last_status.load(),
1692             "Expected failure deleting non-existent bucket.");
1693
1694     check(verify_vbucket_missing(h, h1, 1),
1695           "vbucket 1 was not missing after deleting it.");
1696
1697     wait_for_stat_change(h, h1, "ep_vbucket_del", vbucketDel);
1698
1699     wait_for_stat_to_be(h, h1, "ep_total_cache_size", cacheSize);
1700     wait_for_stat_to_be(h, h1, "ep_overhead", overhead);
1701     wait_for_stat_to_be(h, h1, "ep_num_non_resident", nonResident);
1702
1703     return SUCCESS;
1704 }
1705
1706 static enum test_result vbucket_destroy_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1,
1707                                                 const char* value = NULL) {
1708     if (!isWarmupEnabled(h, h1)) {
1709         return SKIPPED;
1710     }
1711
1712     check(set_vbucket_state(h, h1, 1, vbucket_state_active),
1713           "Failed to set vbucket state.");
1714
1715     // Store a value so the restart will try to resurrect it.
1716     item *i = NULL;
1717     checkeq(ENGINE_SUCCESS,
1718             store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i, 0, 1),
1719             "Failed to set a value");
1720     check_key_value(h, h1, "key", "somevalue", 9, 1);
1721     h1->release(h, NULL, i);
1722
1723     // Reload to get a flush forced.
1724     testHarness.reload_engine(&h, &h1,
1725                               testHarness.engine_path,
1726                               testHarness.get_current_testcase()->cfg,
1727                               true, false);
1728     wait_for_warmup_complete(h, h1);
1729
1730     check(verify_vbucket_state(h, h1, 1, vbucket_state_active),
1731           "Bucket state was what it was initially, after restart.");
1732     check(set_vbucket_state(h, h1, 1, vbucket_state_active),
1733           "Failed to set vbucket state.");
1734     check_key_value(h, h1, "key", "somevalue", 9, 1);
1735
1736     check(set_vbucket_state(h, h1, 1, vbucket_state_dead),
1737           "Failed set set vbucket 1 state.");
1738
1739     vbucketDelete(h, h1, 1, value);
1740     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
1741             "Expected failure deleting non-existent bucket.");
1742
1743     check(verify_vbucket_missing(h, h1, 1),
1744           "vbucket 1 was not missing after deleting it.");
1745
1746     testHarness.reload_engine(&h, &h1,
1747                               testHarness.engine_path,
1748                               testHarness.get_current_testcase()->cfg,
1749                               true, false);
1750     wait_for_warmup_complete(h, h1);
1751
1752     if (verify_vbucket_state(h, h1, 1, vbucket_state_pending, true)) {
1753         std::cerr << "Bucket came up in pending state after delete." << std::endl;
1754         abort();
1755     }
1756
1757     check(verify_vbucket_missing(h, h1, 1),
1758           "vbucket 1 was not missing after restart.");
1759
1760     return SUCCESS;
1761 }
1762
1763 static enum test_result test_async_vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1764     return vbucket_destroy(h, h1);
1765 }
1766
1767 static enum test_result test_sync_vbucket_destroy(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1768     return vbucket_destroy(h, h1, "async=0");
1769 }
1770
1771 static enum test_result test_async_vbucket_destroy_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1772     return vbucket_destroy_restart(h, h1);
1773 }
1774
1775 static enum test_result test_sync_vbucket_destroy_restart(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1776     return vbucket_destroy_restart(h, h1, "async=0");
1777 }
1778
1779 static enum test_result test_vb_set_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1780     return test_pending_vb_mutation(h, h1, OPERATION_SET);
1781 }
1782
1783 static enum test_result test_vb_add_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1784     return test_pending_vb_mutation(h, h1, OPERATION_ADD);
1785 }
1786
1787 static enum test_result test_vb_cas_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1788     return test_pending_vb_mutation(h, h1, OPERATION_CAS);
1789 }
1790
1791 static enum test_result test_vb_set_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1792     return test_replica_vb_mutation(h, h1, OPERATION_SET);
1793 }
1794
1795 static enum test_result test_vb_replace_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1796     return test_replica_vb_mutation(h, h1, OPERATION_REPLACE);
1797 }
1798
1799 static enum test_result test_vb_replace_pending(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1800     return test_pending_vb_mutation(h, h1, OPERATION_REPLACE);
1801 }
1802
1803 static enum test_result test_vb_add_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1804     return test_replica_vb_mutation(h, h1, OPERATION_ADD);
1805 }
1806
1807 static enum test_result test_vb_cas_replica(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1808     return test_replica_vb_mutation(h, h1, OPERATION_CAS);
1809 }
1810
1811 static enum test_result test_stats_seqno(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1812     check(set_vbucket_state(h, h1, 1, vbucket_state_active),
1813           "Failed to set vbucket state.");
1814
1815     int num_keys = 100;
1816     for (int ii = 0; ii < num_keys; ++ii) {
1817         std::stringstream ss;
1818         ss << "key" << ii;
1819         checkeq(ENGINE_SUCCESS,
1820                 store(h, h1, NULL, OPERATION_SET, ss.str().c_str(),
1821                       "value", NULL, 0, 0),
1822                 "Failed to store an item.");
1823     }
1824     wait_for_flusher_to_settle(h, h1);
1825
1826     checkeq(100, get_int_stat(h, h1, "vb_0:high_seqno", "vbucket-seqno"),
1827             "Invalid seqno");
1828
1829     if (isPersistentBucket(h, h1)) {
1830         checkeq(100,
1831                 get_int_stat(h, h1, "vb_0:last_persisted_seqno", "vbucket-seqno"),
1832                 "Unexpected last_persisted_seqno");
1833     }
1834     checkeq(0, get_int_stat(h, h1, "vb_1:high_seqno", "vbucket-seqno"),
1835             "Invalid seqno");
1836     checkeq(0, get_int_stat(h, h1, "vb_1:high_seqno", "vbucket-seqno 1"),
1837             "Invalid seqno");
1838     if (isPersistentBucket(h, h1)) {
1839         checkeq(0,
1840                 get_int_stat(h, h1, "vb_1:last_persisted_seqno", "vbucket-seqno 1"),
1841                 "Invalid last_persisted_seqno");
1842     }
1843
1844     uint64_t vb_uuid = get_ull_stat(h, h1, "vb_1:0:id", "failovers");
1845
1846     auto seqno_stats = get_all_stats(h, h1, "vbucket-seqno 1");
1847     checkeq(vb_uuid, uint64_t(std::stoull(seqno_stats.at("vb_1:uuid"))),
1848             "Invalid uuid");
1849
1850     checkeq(size_t(7), seqno_stats.size(), "Expected seven stats");
1851
1852     // Check invalid vbucket
1853     checkeq(ENGINE_NOT_MY_VBUCKET,
1854             h1->get_stats(h, NULL, "vbucket-seqno 2", 15, add_stats),
1855             "Expected not my vbucket");
1856
1857     // Check bad vbucket parameter (not numeric)
1858     checkeq(ENGINE_EINVAL,
1859             h1->get_stats(h, NULL, "vbucket-seqno tt2", 17, add_stats),
1860             "Expected invalid");
1861
1862     // Check extra spaces at the end
1863     checkeq(ENGINE_EINVAL,
1864             h1->get_stats(h, NULL, "vbucket-seqno    ", 17, add_stats),
1865             "Expected invalid");
1866
1867     return SUCCESS;
1868 }
1869
1870 static enum test_result test_stats_diskinfo(ENGINE_HANDLE *h,
1871                                             ENGINE_HANDLE_V1 *h1) {
1872     check(set_vbucket_state(h, h1, 1, vbucket_state_active),
1873           "Failed to set vbucket state.");
1874
1875     int num_keys = 100;
1876     for (int ii = 0; ii < num_keys; ++ii) {
1877         std::stringstream ss;
1878         ss << "key" << ii;
1879         checkeq(ENGINE_SUCCESS,
1880                 store(h, h1, NULL, OPERATION_SET, ss.str().c_str(),
1881                       "value", NULL, 0, 1),
1882                 "Failed to store an item.");
1883     }
1884     wait_for_flusher_to_settle(h, h1);
1885
1886     size_t file_size = get_int_stat(h, h1, "ep_db_file_size", "diskinfo");
1887     size_t data_size = get_int_stat(h, h1, "ep_db_data_size", "diskinfo");
1888     check(file_size > 0, "DB file size should be greater than 0");
1889     check(data_size > 0, "DB data size should be greater than 0");
1890     check(file_size >= data_size, "DB file size should be >= DB data size");
1891     check(get_int_stat(h, h1, "vb_1:data_size", "diskinfo detail") > 0,
1892           "VB 1 data size should be greater than 0");
1893
1894     checkeq(ENGINE_EINVAL,
1895             h1->get_stats(h, NULL, "diskinfo ", 9, add_stats),
1896             "Expected invalid");
1897
1898     checkeq(ENGINE_EINVAL,
1899             h1->get_stats(h, NULL, "diskinfo detai", 14, add_stats),
1900             "Expected invalid");
1901
1902     checkeq(ENGINE_EINVAL,
1903             h1->get_stats(h, NULL, "diskinfo detaillll", 18, add_stats),
1904             "Expected invalid");
1905
1906     return SUCCESS;
1907 }
1908
1909 static enum test_result test_uuid_stats(ENGINE_HANDLE *h,
1910                                         ENGINE_HANDLE_V1 *h1)
1911 {
1912     vals.clear();
1913     checkeq(ENGINE_SUCCESS,
1914             h1->get_stats(h, NULL, "uuid", 4, add_stats),
1915             "Failed to get stats.");
1916     check(vals["uuid"] == "foobar", "Incorrect uuid");
1917     return SUCCESS;
1918 }
1919
1920 static enum test_result test_item_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1921     item *i = NULL;
1922     checkeq(ENGINE_SUCCESS,
1923             store(h, h1, NULL, OPERATION_SET, "key", "somevalue", &i, 0, 0),
1924             "Failed set.");
1925     h1->release(h, NULL, i);
1926     wait_for_flusher_to_settle(h, h1);
1927     checkeq(ENGINE_SUCCESS,
1928             store(h, h1, NULL, OPERATION_SET, "key", "somevalueX", &i, 0, 0),
1929             "Failed set.");
1930     h1->release(h, NULL, i);
1931     wait_for_flusher_to_settle(h, h1);
1932     checkeq(ENGINE_SUCCESS,
1933             store(h, h1, NULL, OPERATION_SET, "key1", "somevalueY", &i, 0, 0),
1934             "Failed set.");
1935     h1->release(h, NULL, i);
1936     wait_for_flusher_to_settle(h, h1);
1937
1938     check_key_value(h, h1, "key", "somevalueX", 10);
1939     check_key_value(h, h1, "key1", "somevalueY", 10);
1940
1941     checkeq(ENGINE_SUCCESS, del(h, h1, "key1", 0, 0),
1942             "Failed remove with value.");
1943     wait_for_flusher_to_settle(h, h1);
1944
1945     checkeq(ENGINE_SUCCESS,
1946             store(h, h1, NULL, OPERATION_SET, "key1", "someothervalue", &i, 0, 0),
1947             "Failed set.");
1948     h1->release(h, NULL, i);
1949     wait_for_flusher_to_settle(h, h1);
1950
1951     check_key_value(h, h1, "key1", "someothervalue", 14);
1952
1953     checkeq(3,
1954             get_int_stat(h, h1, "vb_active_ops_create"),
1955             "Expected 3 creations");
1956     checkeq(1,
1957             get_int_stat(h, h1, "vb_active_ops_update"),
1958             "Expected 1 updation");
1959     checkeq(1,
1960             get_int_stat(h, h1, "vb_active_ops_delete"),
1961             "Expected 1 deletion");
1962
1963     return SUCCESS;
1964 }
1965
1966 static enum test_result test_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1967     vals.clear();
1968     checkeq(ENGINE_SUCCESS,
1969             h1->get_stats(h, NULL, NULL, 0, add_stats),
1970             "Failed to get stats.");
1971     check(vals.size() > 10, "Kind of expected more stats than that.");
1972     check(vals.find("ep_version") != vals.end(), "Found no ep_version.");
1973
1974     return SUCCESS;
1975 }
1976
1977 static enum test_result test_mem_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
1978     char value[2048];
1979     memset(value, 'b', sizeof(value));
1980     strcpy(value + sizeof(value) - 4, "\r\n");
1981     int itemsRemoved = get_int_stat(h, h1, "ep_items_rm_from_checkpoints");
1982     wait_for_persisted_value(h, h1, "key", value);
1983     testHarness.time_travel(65);
1984     if (isPersistentBucket(h, h1)) {
1985         wait_for_stat_change(h, h1, "ep_items_rm_from_checkpoints", itemsRemoved);
1986     }
1987     int mem_used = get_int_stat(h, h1, "mem_used");
1988     int cache_size = get_int_stat(h, h1, "ep_total_cache_size");
1989     int overhead = get_int_stat(h, h1, "ep_overhead");
1990     int value_size = get_int_stat(h, h1, "ep_value_size");
1991     check((mem_used - overhead) > cache_size,
1992           "ep_kv_size should be greater than the hashtable cache size due to the checkpoint overhead");
1993
1994     if (isPersistentBucket(h, h1)) {
1995         evict_key(h, h1, "key", 0, "Ejected.");
1996
1997         check(get_int_stat(h, h1, "ep_total_cache_size") <= cache_size,
1998               "Evict a value shouldn't increase the total cache size");
1999         check(get_int_stat(h, h1, "mem_used") < mem_used,
2000               "Expected mem_used to decrease when an item is evicted");
2001
2002         check_key_value(h, h1, "key", value, strlen(value), 0); // Load an item from disk again.
2003
2004         check(get_int_stat(h, h1, "mem_used") >= mem_used,
2005               "Expected mem_used to remain the same after an item is loaded from disk");
2006         check(get_int_stat(h, h1, "ep_value_size") == value_size,
2007               "Expected ep_value_size to remain the same after item is loaded from disk");
2008     }
2009
2010     return SUCCESS;
2011 }
2012
2013 static enum test_result test_io_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2014     int exp_read_bytes = 4, exp_write_bytes;
2015     std::string backend = get_str_stat(h, h1, "ep_backend");
2016     if (backend == "forestdb") {
2017         exp_write_bytes = 35; /* TBD: Do not hard code the value */
2018     } else if (backend == "couchdb") {
2019         exp_write_bytes = 22; /* TBD: Do not hard code the value */
2020     } else {
2021         return SKIPPED;
2022     }
2023
2024     h1->reset_stats(h, NULL);
2025
2026     checkeq(0, get_int_stat(h, h1, "rw_0:io_num_read", "kvstore"),
2027             "Expected reset stats to set io_num_read to zero");
2028     checkeq(0, get_int_stat(h, h1, "rw_0:io_num_write", "kvstore"),
2029             "Expected reset stats to set io_num_write to zero");
2030     checkeq(0, get_int_stat(h, h1, "rw_0:io_read_bytes", "kvstore"),
2031             "Expected reset stats to set io_read_bytes to zero");
2032     checkeq(0, get_int_stat(h, h1, "rw_0:io_write_bytes", "kvstore"),
2033             "Expected reset stats to set io_write_bytes to zero");
2034
2035     wait_for_persisted_value(h, h1, "a", "b\r\n");
2036     checkeq(0, get_int_stat(h, h1, "rw_0:io_num_read", "kvstore"),
2037             "Expected storing one value to not change the read counter");
2038     checkeq(0, get_int_stat(h, h1, "rw_0:io_read_bytes", "kvstore"),
2039             "Expected storing one value to not change the read bytes");
2040     checkeq(1, get_int_stat(h, h1, "rw_0:io_num_write", "kvstore"),
2041             "Expected storing the key to update the write counter");
2042     checkeq(exp_write_bytes,
2043             get_int_stat(h, h1, "rw_0:io_write_bytes", "kvstore"),
2044             "Expected storing the key to update the write bytes");
2045
2046     evict_key(h, h1, "a", 0, "Ejected.");
2047
2048     check_key_value(h, h1, "a", "b\r\n", 3, 0);
2049
2050     std::stringstream numReadStatStr;
2051     std::stringstream readBytesStatStr;
2052
2053     if (backend == "couchdb") {
2054         numReadStatStr << "ro_" << 0 << ":io_num_read";
2055         readBytesStatStr << "ro_" << 0 << ":io_read_bytes";
2056     } else if (backend == "forestdb") {
2057         numReadStatStr << "rw_" << 0 << ":io_num_read";
2058         readBytesStatStr << "rw_" << 0 << ":io_read_bytes";
2059     } else {
2060         cb_assert(false);
2061     }
2062
2063     checkeq(1, get_int_stat(h, h1, numReadStatStr.str().c_str(), "kvstore"),
2064             "Expected reading the value back in to update the read counter");
2065     checkeq(exp_read_bytes,
2066             get_int_stat(h, h1, readBytesStatStr.str().c_str(), "kvstore"),
2067             "Expected reading the value back in to update the read bytes");
2068     checkeq(1, get_int_stat(h, h1, "rw_0:io_num_write", "kvstore"),
2069             "Expected reading the value back in to not update the write counter");
2070     checkeq(exp_write_bytes,
2071             get_int_stat(h, h1, "rw_0:io_write_bytes", "kvstore"),
2072             "Expected reading the value back in to not update the write bytes");
2073
2074     return SUCCESS;
2075 }
2076
2077 static enum test_result test_vb_file_stats(ENGINE_HANDLE *h,
2078                                         ENGINE_HANDLE_V1 *h1) {
2079     wait_for_flusher_to_settle(h, h1);
2080     wait_for_stat_change(h, h1, "ep_db_data_size", 0);
2081
2082     int old_data_size = get_int_stat(h, h1, "ep_db_data_size");
2083     int old_file_size = get_int_stat(h, h1, "ep_db_file_size");
2084     check(old_file_size != 0, "Expected a non-zero value for ep_db_file_size");
2085
2086     // Write a value and test ...
2087     wait_for_persisted_value(h, h1, "a", "b\r\n");
2088     check(get_int_stat(h, h1, "ep_db_data_size") > old_data_size,
2089           "Expected the DB data size to increase");
2090     check(get_int_stat(h, h1, "ep_db_file_size") > old_file_size,
2091           "Expected the DB file size to increase");
2092
2093     check(get_int_stat(h, h1, "vb_0:db_data_size", "vbucket-details 0") > 0,
2094           "Expected the vbucket DB data size to non-zero");
2095     check(get_int_stat(h, h1, "vb_0:db_file_size", "vbucket-details 0") > 0,
2096           "Expected the vbucket DB file size to non-zero");
2097     return SUCCESS;
2098 }
2099
2100 static enum test_result test_vb_file_stats_after_warmup(ENGINE_HANDLE *h,
2101                                                         ENGINE_HANDLE_V1 *h1) {
2102     if (!isWarmupEnabled(h, h1)) {
2103         return SKIPPED;
2104     }
2105
2106     item *it = NULL;
2107     for (int i = 0; i < 100; ++i) {
2108         std::stringstream key;
2109         key << "key-" << i;
2110         checkeq(ENGINE_SUCCESS,
2111                 store(h, h1, NULL, OPERATION_SET, key.str().c_str(), "somevalue", &it),
2112                 "Error setting.");
2113         h1->release(h, NULL, it);
2114     }
2115     wait_for_flusher_to_settle(h, h1);
2116
2117     int fileSize = get_int_stat(h, h1, "vb_0:db_file_size", "vbucket-details 0");
2118     int spaceUsed = get_int_stat(h, h1, "vb_0:db_data_size", "vbucket-details 0");
2119
2120     // Restart the engine.
2121     testHarness.reload_engine(&h, &h1,
2122                               testHarness.engine_path,
2123                               testHarness.get_current_testcase()->cfg,
2124                               true, false);
2125     wait_for_warmup_complete(h, h1);
2126
2127     int newFileSize = get_int_stat(h, h1, "vb_0:db_file_size", "vbucket-details 0");
2128     int newSpaceUsed = get_int_stat(h, h1, "vb_0:db_data_size", "vbucket-details 0");
2129
2130     check((float)newFileSize >= 0.9 * fileSize, "Unexpected fileSize for vbucket");
2131     check((float)newSpaceUsed >= 0.9 * spaceUsed, "Unexpected spaceUsed for vbucket");
2132
2133     return SUCCESS;
2134 }
2135
2136 static enum test_result test_bg_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2137     h1->reset_stats(h, NULL);
2138     wait_for_persisted_value(h, h1, "a", "b\r\n");
2139     evict_key(h, h1, "a", 0, "Ejected.");
2140     testHarness.time_travel(43);
2141     check_key_value(h, h1, "a", "b\r\n", 3, 0);
2142
2143     auto stats = get_all_stats(h, h1);
2144     checkeq(1, std::stoi(stats.at("ep_bg_num_samples")),
2145                "Expected one sample");
2146
2147     const char* bg_keys[] = { "ep_bg_min_wait",
2148                               "ep_bg_max_wait",
2149                               "ep_bg_wait_avg",
2150                               "ep_bg_min_load",
2151                               "ep_bg_max_load",
2152                               "ep_bg_load_avg"};
2153     for (const auto* key : bg_keys) {
2154         check(stats.find(key) != stats.end(),
2155               (std::string("Found no ") + key).c_str());
2156     }
2157
2158     evict_key(h, h1, "a", 0, "Ejected.");
2159     check_key_value(h, h1, "a", "b\r\n", 3, 0);
2160     check(get_int_stat(h, h1, "ep_bg_num_samples") == 2,
2161           "Expected one sample");
2162
2163     h1->reset_stats(h, NULL);
2164     checkeq(0, get_int_stat(h, h1, "ep_bg_fetched"),
2165             "ep_bg_fetched is not reset to 0");
2166     return SUCCESS;
2167 }
2168
2169 static enum test_result test_bg_meta_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2170     item *itm = NULL;
2171     h1->reset_stats(h, NULL);
2172
2173     wait_for_persisted_value(h, h1, "k1", "v1");
2174     wait_for_persisted_value(h, h1, "k2", "v2");
2175
2176     evict_key(h, h1, "k1", 0, "Ejected.");
2177     checkeq(ENGINE_SUCCESS,
2178             del(h, h1, "k2", 0, 0), "Failed remove with value.");
2179     wait_for_stat_to_be(h, h1, "curr_items", 1);
2180
2181     checkeq(0, get_int_stat(h, h1, "ep_bg_fetched"), "Expected bg_fetched to be 0");
2182     checkeq(0, get_int_stat(h, h1, "ep_bg_meta_fetched"), "Expected bg_meta_fetched to be 0");
2183
2184     check(get_meta(h, h1, "k2"), "Get meta failed");
2185     checkeq(0, get_int_stat(h, h1, "ep_bg_fetched"), "Expected bg_fetched to be 0");
2186     checkeq(1, get_int_stat(h, h1, "ep_bg_meta_fetched"), "Expected bg_meta_fetched to be 1");
2187
2188     checkeq(ENGINE_SUCCESS, get(h, h1, NULL, &itm, "k1", 0), "Missing key");
2189     checkeq(1, get_int_stat(h, h1, "ep_bg_fetched"), "Expected bg_fetched to be 1");
2190     checkeq(1, get_int_stat(h, h1, "ep_bg_meta_fetched"), "Expected bg_meta_fetched to be 1");
2191     h1->release(h, NULL, itm);
2192
2193     // store new key with some random metadata
2194     const size_t keylen = strlen("k3");
2195     ItemMetaData itemMeta;
2196     itemMeta.revSeqno = 10;
2197     itemMeta.cas = 0xdeadbeef;
2198     itemMeta.exptime = 0;
2199     itemMeta.flags = 0xdeadbeef;
2200
2201     add_with_meta(h, h1, "k3", keylen, NULL, 0, 0, &itemMeta);
2202     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(), "Set meta failed");
2203
2204     check(get_meta(h, h1, "k2"), "Get meta failed");
2205     checkeq(1, get_int_stat(h, h1, "ep_bg_fetched"), "Expected bg_fetched to be 1");
2206     checkeq(1, get_int_stat(h, h1, "ep_bg_meta_fetched"),
2207             "Expected bg_meta_fetched to remain at 1");
2208
2209     return SUCCESS;
2210 }
2211
2212 static enum test_result test_key_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2213     item *i = NULL;
2214
2215     check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed set vbucket 1 state.");
2216
2217     // set (k1,v1) in vbucket 0
2218     checkeq(ENGINE_SUCCESS,
2219             store(h, h1, NULL, OPERATION_SET,"k1", "v1", &i, 0, 0),
2220             "Failed to store an item.");
2221     h1->release(h, NULL, i);
2222     // set (k2,v2) in vbucket 1
2223     checkeq(ENGINE_SUCCESS,
2224             store(h, h1, NULL, OPERATION_SET,"k2", "v2", &i, 0, 1),
2225             "Failed to store an item.");
2226     h1->release(h, NULL, i);
2227
2228     const void *cookie = testHarness.create_cookie();
2229
2230     // stat for key "k1" and vbucket "0"
2231     const char *statkey1 = "key k1 0";
2232     checkeq(ENGINE_SUCCESS,
2233             h1->get_stats(h, cookie, statkey1, strlen(statkey1), add_stats),
2234             "Failed to get stats.");
2235     check(vals.find("key_is_dirty") != vals.end(), "Found no key_is_dirty");
2236     check(vals.find("key_exptime") != vals.end(), "Found no key_exptime");
2237     check(vals.find("key_flags") != vals.end(), "Found no key_flags");
2238     check(vals.find("key_cas") != vals.end(), "Found no key_cas");
2239     check(vals.find("key_vb_state") != vals.end(), "Found no key_vb_state");
2240
2241     // stat for key "k2" and vbucket "1"
2242     const char *statkey2 = "key k2 1";
2243     checkeq(ENGINE_SUCCESS,
2244             h1->get_stats(h, cookie, statkey2, strlen(statkey2), add_stats),
2245             "Failed to get stats.");
2246     check(vals.find("key_is_dirty") != vals.end(), "Found no key_is_dirty");
2247     check(vals.find("key_exptime") != vals.end(), "Found no key_exptime");
2248     check(vals.find("key_flags") != vals.end(), "Found no key_flags");
2249     check(vals.find("key_cas") != vals.end(), "Found no key_cas");
2250     check(vals.find("key_vb_state") != vals.end(), "Found no key_vb_state");
2251
2252     testHarness.destroy_cookie(cookie);
2253     return SUCCESS;
2254 }
2255
2256 static enum test_result test_vkey_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2257     check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed set vbucket 1 state.");
2258     check(set_vbucket_state(h, h1, 2, vbucket_state_active), "Failed set vbucket 2 state.");
2259     check(set_vbucket_state(h, h1, 3, vbucket_state_active), "Failed set vbucket 3 state.");
2260     check(set_vbucket_state(h, h1, 4, vbucket_state_active), "Failed set vbucket 4 state.");
2261
2262     wait_for_persisted_value(h, h1, "k1", "v1");
2263     wait_for_persisted_value(h, h1, "k2", "v2", 1);
2264     wait_for_persisted_value(h, h1, "k3", "v3", 2);
2265     wait_for_persisted_value(h, h1, "k4", "v4", 3);
2266     wait_for_persisted_value(h, h1, "k5", "v5", 4);
2267
2268     check(set_vbucket_state(h, h1, 2, vbucket_state_replica), "Failed to set VB2 state.");
2269     check(set_vbucket_state(h, h1, 3, vbucket_state_pending), "Failed to set VB3 state.");
2270     check(set_vbucket_state(h, h1, 4, vbucket_state_dead), "Failed to set VB4 state.");
2271
2272     const void *cookie = testHarness.create_cookie();
2273
2274     // stat for key "k1" and vbucket "0"
2275     const char *statkey1 = "vkey k1 0";
2276     checkeq(ENGINE_SUCCESS,
2277             h1->get_stats(h, cookie, statkey1, strlen(statkey1), add_stats),
2278             "Failed to get stats.");
2279     check(vals.find("key_is_dirty") != vals.end(), "Found no key_is_dirty");
2280     check(vals.find("key_exptime") != vals.end(), "Found no key_exptime");
2281     check(vals.find("key_flags") != vals.end(), "Found no key_flags");
2282     check(vals.find("key_cas") != vals.end(), "Found no key_cas");
2283     check(vals.find("key_vb_state") != vals.end(), "Found no key_vb_state");
2284     check(vals.find("key_valid") != vals.end(), "Found no key_valid");
2285
2286     // stat for key "k2" and vbucket "1"
2287     const char *statkey2 = "vkey k2 1";
2288     checkeq(ENGINE_SUCCESS,
2289             h1->get_stats(h, cookie, statkey2, strlen(statkey2), add_stats),
2290             "Failed to get stats.");
2291     check(vals.find("key_is_dirty") != vals.end(), "Found no key_is_dirty");
2292     check(vals.find("key_exptime") != vals.end(), "Found no key_exptime");
2293     check(vals.find("key_flags") != vals.end(), "Found no key_flags");
2294     check(vals.find("key_cas") != vals.end(), "Found no key_cas");
2295     check(vals.find("key_vb_state") != vals.end(), "Found no key_vb_state");
2296     check(vals.find("key_valid") != vals.end(), "Found no key_valid");
2297
2298     // stat for key "k3" and vbucket "2"
2299     const char *statkey3 = "vkey k3 2";
2300     checkeq(ENGINE_SUCCESS,
2301             h1->get_stats(h, cookie, statkey3, strlen(statkey3), add_stats),
2302             "Failed to get stats.");
2303     check(vals.find("key_is_dirty") != vals.end(), "Found no key_is_dirty");
2304     check(vals.find("key_exptime") != vals.end(), "Found no key_exptime");
2305     check(vals.find("key_flags") != vals.end(), "Found no key_flags");
2306     check(vals.find("key_cas") != vals.end(), "Found no key_cas");
2307     check(vals.find("key_vb_state") != vals.end(), "Found no key_vb_state");
2308     check(vals.find("key_valid") != vals.end(), "Found no key_valid");
2309
2310     // stat for key "k4" and vbucket "3"
2311     const char *statkey4 = "vkey k4 3";
2312     checkeq(ENGINE_SUCCESS,
2313             h1->get_stats(h, cookie, statkey4, strlen(statkey4), add_stats),
2314             "Failed to get stats.");
2315     check(vals.find("key_is_dirty") != vals.end(), "Found no key_is_dirty");
2316     check(vals.find("key_exptime") != vals.end(), "Found no key_exptime");
2317     check(vals.find("key_flags") != vals.end(), "Found no key_flags");
2318     check(vals.find("key_cas") != vals.end(), "Found no key_cas");
2319     check(vals.find("key_vb_state") != vals.end(), "Found no key_vb_state");
2320     check(vals.find("key_valid") != vals.end(), "Found no key_valid");
2321
2322     // stat for key "k5" and vbucket "4"
2323     const char *statkey5 = "vkey k5 4";
2324     checkeq(ENGINE_SUCCESS,
2325             h1->get_stats(h, cookie, statkey5, strlen(statkey5), add_stats),
2326             "Failed to get stats.");
2327     check(vals.find("key_is_dirty") != vals.end(), "Found no key_is_dirty");
2328     check(vals.find("key_exptime") != vals.end(), "Found no key_exptime");
2329     check(vals.find("key_flags") != vals.end(), "Found no key_flags");
2330     check(vals.find("key_cas") != vals.end(), "Found no key_cas");
2331     check(vals.find("key_vb_state") != vals.end(), "Found no key_vb_state");
2332     check(vals.find("key_valid") != vals.end(), "Found no key_valid");
2333
2334     testHarness.destroy_cookie(cookie);
2335     return SUCCESS;
2336 }
2337
2338 static enum test_result test_warmup_conf(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2339     if (!isWarmupEnabled(h, h1)) {
2340         return SKIPPED;
2341     }
2342
2343     checkeq(100, get_int_stat(h, h1, "ep_warmup_min_items_threshold"),
2344             "Incorrect initial warmup min items threshold.");
2345     checkeq(100, get_int_stat(h, h1, "ep_warmup_min_memory_threshold"),
2346             "Incorrect initial warmup min memory threshold.");
2347
2348     check(!set_param(h, h1, protocol_binary_engine_param_flush,
2349                      "warmup_min_items_threshold", "a"),
2350           "Set warmup_min_items_threshold should have failed");
2351     check(!set_param(h, h1, protocol_binary_engine_param_flush,
2352                      "warmup_min_items_threshold", "a"),
2353           "Set warmup_min_memory_threshold should have failed");
2354
2355     check(set_param(h, h1, protocol_binary_engine_param_flush,
2356                     "warmup_min_items_threshold", "80"),
2357           "Set warmup_min_items_threshold should have worked");
2358     check(set_param(h, h1, protocol_binary_engine_param_flush,
2359                     "warmup_min_memory_threshold", "80"),
2360           "Set warmup_min_memory_threshold should have worked");
2361
2362     checkeq(80, get_int_stat(h, h1, "ep_warmup_min_items_threshold"),
2363             "Incorrect smaller warmup min items threshold.");
2364     checkeq(80, get_int_stat(h, h1, "ep_warmup_min_memory_threshold"),
2365             "Incorrect smaller warmup min memory threshold.");
2366
2367     item *it = NULL;
2368     for (int i = 0; i < 100; ++i) {
2369         std::stringstream key;
2370         key << "key-" << i;
2371         checkeq(ENGINE_SUCCESS,
2372                 store(h, h1, NULL, OPERATION_SET, key.str().c_str(), "somevalue", &it),
2373                 "Error setting.");
2374         h1->release(h, NULL, it);
2375     }
2376
2377     // Restart the server.
2378     std::string config(testHarness.get_current_testcase()->cfg);
2379     config = config + "warmup_min_memory_threshold=0";
2380     testHarness.reload_engine(&h, &h1,
2381                               testHarness.engine_path,
2382                               config.c_str(),
2383                               true, false);
2384     wait_for_warmup_complete(h, h1);
2385
2386     const std::string eviction_policy = get_str_stat(h, h1, "ep_item_eviction_policy");
2387     if (eviction_policy == "value_only") {
2388         checkeq(100, get_int_stat(h, h1, "ep_warmup_key_count", "warmup"),
2389                 "Expected 100 keys loaded after warmup");
2390     } else { // Full eviction mode
2391         checkeq(0, get_int_stat(h, h1, "ep_warmup_key_count", "warmup"),
2392                 "Expected 0 keys loaded after warmup");
2393     }
2394
2395     checkeq(0, get_int_stat(h, h1, "ep_warmup_value_count", "warmup"),
2396             "Expected 0 values loaded after warmup");
2397
2398     return SUCCESS;
2399 }
2400
2401 static enum test_result test_bloomfilter_conf(ENGINE_HANDLE *h,
2402                                               ENGINE_HANDLE_V1 *h1) {
2403
2404     if (get_bool_stat(h, h1, "ep_bfilter_enabled") == false) {
2405         check(set_param(h, h1, protocol_binary_engine_param_flush,
2406                         "bfilter_enabled", "true"),
2407               "Set bloomfilter_enabled should have worked");
2408     }
2409     check(get_bool_stat(h, h1, "ep_bfilter_enabled"),
2410           "Bloom filter wasn't enabled");
2411
2412     check(get_float_stat(h, h1, "ep_bfilter_residency_threshold") == (float)0.1,
2413           "Incorrect initial bfilter_residency_threshold.");
2414
2415     check(set_param(h, h1, protocol_binary_engine_param_flush,
2416           "bfilter_enabled", "false"),
2417           "Set bloomfilter_enabled should have worked.");
2418     check(set_param(h, h1, protocol_binary_engine_param_flush,
2419           "bfilter_residency_threshold", "0.15"),
2420           "Set bfilter_residency_threshold should have worked.");
2421
2422     check(get_bool_stat(h, h1, "ep_bfilter_enabled") == false,
2423           "Bloom filter should have been disabled.");
2424     check(get_float_stat(h, h1, "ep_bfilter_residency_threshold") == (float)0.15,
2425           "Incorrect bfilter_residency_threshold.");
2426
2427     return SUCCESS;
2428 }
2429
2430 static enum test_result test_bloomfilters(ENGINE_HANDLE *h,
2431                                           ENGINE_HANDLE_V1 *h1) {
2432
2433     if (get_bool_stat(h, h1, "ep_bfilter_enabled") == false) {
2434         check(set_param(h, h1, protocol_binary_engine_param_flush,
2435                     "bfilter_enabled", "true"),
2436                 "Set bloomfilter_enabled should have worked");
2437     }
2438     check(get_bool_stat(h, h1, "ep_bfilter_enabled"),
2439             "Bloom filter wasn't enabled");
2440
2441     // Key is only present if bgOperations is non-zero.
2442     int num_read_attempts = get_int_stat_or_default(h, h1, 0,
2443                                                     "ep_bg_num_samples");
2444
2445     // Ensure vbucket's bloom filter is enabled
2446     checkeq(std::string("ENABLED"),
2447             get_str_stat(h, h1, "vb_0:bloom_filter", "vbucket-details 0"),
2448             "Vbucket 0's bloom filter wasn't enabled upon setup!");
2449
2450     int i;
2451     item *it = NULL;
2452
2453     // Insert 10 items.
2454     for (i = 0; i < 10; ++i) {
2455         std::stringstream key;
2456         key << "key-" << i;
2457         checkeq(ENGINE_SUCCESS,
2458                 store(h, h1, NULL, OPERATION_SET, key.str().c_str(),
2459                       "somevalue", &it),
2460                 "Error setting.");
2461         h1->release(h, NULL, it);
2462     }
2463     wait_for_flusher_to_settle(h, h1);
2464
2465     // Evict all 10 items.
2466     for (i = 0; i < 10; ++i) {
2467         std::stringstream key;
2468         key << "key-" << i;
2469         evict_key(h, h1, key.str().c_str(), 0, "Ejected.");
2470     }
2471     wait_for_flusher_to_settle(h, h1);
2472
2473     // Ensure 10 items are non-resident.
2474     cb_assert(10 == get_int_stat(h, h1, "ep_num_non_resident"));
2475
2476     // Issue delete on first 5 items.
2477     for (i = 0; i < 5; ++i) {
2478         std::stringstream key;
2479         key << "key-" << i;
2480         checkeq(ENGINE_SUCCESS,
2481                 del(h, h1, key.str().c_str(), 0, 0),
2482                 "Failed remove with value.");
2483     }
2484     wait_for_flusher_to_settle(h, h1);
2485
2486     // Ensure that there are 5 non-resident items
2487     cb_assert(5 == get_int_stat(h, h1, "ep_num_non_resident"));
2488     cb_assert(5 == get_int_stat(h, h1, "curr_items"));
2489
2490     checkeq(ENGINE_SUCCESS,
2491             h1->get_stats(h, NULL, NULL, 0, add_stats),
2492             "Failed to get stats.");
2493     std::string eviction_policy = vals.find("ep_item_eviction_policy")->second;
2494
2495     useconds_t sleepTime = 128;
2496
2497     if (eviction_policy == "value_only") {  // VALUE-ONLY EVICTION MODE
2498
2499         checkeq(5,
2500                 get_int_stat(h, h1, "vb_0:bloom_filter_key_count",
2501                              "vbucket-details 0"),
2502                 "Unexpected no. of keys in bloom filter");
2503
2504         checkeq(num_read_attempts,
2505                 get_int_stat_or_default(h, h1, 0, "ep_bg_num_samples"),
2506                 "Expected bgFetch attempts to remain unchanged");
2507
2508         for (i = 0; i < 5; ++i) {
2509             std::stringstream key;
2510             key << "key-" << i;
2511             check(get_meta(h, h1, key.str().c_str()), "Get meta failed");
2512         }
2513
2514         // GetMeta would cause bgFetches as bloomfilter contains
2515         // the deleted items.
2516         checkeq(num_read_attempts + 5,
2517                 get_int_stat(h, h1, "ep_bg_num_samples"),
2518                 "Expected bgFetch attempts to increase by five");
2519
2520         // Run compaction, with drop_deletes
2521         compact_db(h, h1, 0, 0, 15, 15, 1);
2522         while (get_int_stat(h, h1, "ep_pending_compactions") != 0) {
2523             decayingSleep(&sleepTime);
2524         }
2525
2526         for (i = 0; i < 5; ++i) {
2527             std::stringstream key;
2528             key << "key-" << i;
2529             check(get_meta(h, h1, key.str().c_str()), "Get meta failed");
2530         }
2531         checkeq(num_read_attempts + 5,
2532                 get_int_stat(h, h1, "ep_bg_num_samples"),
2533                 "Expected bgFetch attempts to stay as before");
2534
2535     } else {                                // FULL EVICTION MODE
2536
2537         checkeq(10,
2538                 get_int_stat(h, h1, "vb_0:bloom_filter_key_count",
2539                              "vbucket-details 0"),
2540                 "Unexpected no. of keys in bloom filter");
2541
2542
2543         // Because of issuing deletes on non-resident items
2544         checkeq(num_read_attempts + 5,
2545                 get_int_stat(h, h1, "ep_bg_num_samples"),
2546                 "Expected bgFetch attempts to increase by five, after deletes");
2547
2548         // Run compaction, with drop_deletes, to exclude deleted items
2549         // from bloomfilter.
2550         compact_db(h, h1, 0, 0, 15, 15, 1);
2551         while (get_int_stat(h, h1, "ep_pending_compactions") != 0) {
2552             decayingSleep(&sleepTime);
2553         }
2554
2555         for (i = 0; i < 5; i++) {
2556             std::stringstream key;
2557             key << "key-" << i;
2558             checkeq(ENGINE_KEY_ENOENT,
2559                     get(h, h1, NULL, &it, key.str(), 0),
2560                     "Unable to get stored item");
2561         }
2562         // + 6 because last delete is not purged by the compactor
2563         checkeq(num_read_attempts + 6,
2564                 get_int_stat(h, h1, "ep_bg_num_samples"),
2565                 "Expected bgFetch attempts to stay as before");
2566     }
2567
2568     return SUCCESS;
2569 }
2570
2571 static enum test_result test_bloomfilters_with_store_apis(ENGINE_HANDLE *h,
2572                                                           ENGINE_HANDLE_V1 *h1) {
2573     if (get_bool_stat(h, h1, "ep_bfilter_enabled") == false) {
2574         check(set_param(h, h1, protocol_binary_engine_param_flush,
2575                     "bfilter_enabled", "true"),
2576                 "Set bloomfilter_enabled should have worked");
2577     }
2578     check(get_bool_stat(h, h1, "ep_bfilter_enabled"),
2579             "Bloom filter wasn't enabled");
2580
2581     int num_read_attempts = get_int_stat_or_default(h, h1, 0,
2582                                                     "ep_bg_num_samples");
2583
2584     // Ensure vbucket's bloom filter is enabled
2585     checkeq(std::string("ENABLED"),
2586             get_str_stat(h, h1, "vb_0:bloom_filter", "vbucket-details 0"),
2587             "Vbucket 0's bloom filter wasn't enabled upon setup!");
2588
2589     for (int i = 0; i < 1000; i++) {
2590         std::stringstream key;
2591         key << "key-" << i;
2592         check(!get_meta(h, h1, key.str().c_str()),
2593                 "Get meta should fail.");
2594     }
2595
2596     checkeq(num_read_attempts,
2597             get_int_stat_or_default(h, h1, 0, "ep_bg_num_samples"),
2598             "Expected no bgFetch attempts");
2599
2600     checkeq(ENGINE_SUCCESS,
2601             h1->get_stats(h, NULL, NULL, 0, add_stats),
2602             "Failed to get stats.");
2603     std::string eviction_policy = vals.find("ep_item_eviction_policy")->second;
2604
2605     if (eviction_policy == "full_eviction") {  // FULL EVICTION MODE
2606         // Set with Meta
2607         int j;
2608         for (j = 0; j < 10; j++) {
2609             uint64_t cas_for_set = last_cas;
2610             // init some random metadata
2611             ItemMetaData itm_meta;
2612             itm_meta.revSeqno = 10;
2613             itm_meta.cas = 0xdeadbeef;
2614             itm_meta.exptime = time(NULL) + 300;
2615             itm_meta.flags = 0xdeadbeef;
2616
2617             std::stringstream key;
2618             key << "swm-" << j;
2619             set_with_meta(h, h1, key.str().c_str(), key.str().length(),
2620                           "somevalue", 9, 0, &itm_meta, cas_for_set);
2621         }
2622
2623         checkeq(num_read_attempts,
2624                 get_int_stat_or_default(h, h1, 0, "ep_bg_num_samples"),
2625                 "Expected no bgFetch attempts");
2626
2627         item *itm = NULL;
2628         // Add
2629         for (j = 0; j < 10; j++) {
2630             std::stringstream key;
2631             key << "add-" << j;
2632
2633             checkeq(ENGINE_SUCCESS,
2634                     store(h, h1, NULL, OPERATION_ADD, key.str().c_str(),
2635                           "newvalue", &itm),
2636                     "Failed to add value again.");
2637             h1->release(h, NULL, itm);
2638         }
2639
2640         checkeq(num_read_attempts,
2641                 get_int_stat_or_default(h, h1, 0, "ep_bg_num_samples"),
2642                 "Expected no bgFetch attempts");
2643
2644         // Delete
2645         for (j = 0; j < 10; j++) {
2646             std::stringstream key;
2647             key << "del-" << j;
2648             checkeq(ENGINE_KEY_ENOENT,
2649                     del(h, h1, key.str().c_str(), 0, 0),
2650                     "Failed remove with value.");
2651         }
2652
2653         checkeq(num_read_attempts,
2654                 get_int_stat_or_default(h, h1, 0, "ep_bg_num_samples"),
2655                 "Expected no bgFetch attempts");
2656
2657     }
2658
2659     return SUCCESS;
2660 }
2661
2662 static enum test_result test_bloomfilter_delete_plus_set_scenario(
2663                                        ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2664     if (get_bool_stat(h, h1, "ep_bfilter_enabled") == false) {
2665         check(set_param(h, h1, protocol_binary_engine_param_flush,
2666                     "bfilter_enabled", "true"),
2667                 "Set bloomfilter_enabled should have worked");
2668     }
2669     check(get_bool_stat(h, h1, "ep_bfilter_enabled"),
2670             "Bloom filter wasn't enabled");
2671
2672     // Ensure vbucket's bloom filter is enabled
2673     checkeq(std::string("ENABLED"),
2674             get_str_stat(h, h1, "vb_0:bloom_filter", "vbucket-details 0"),
2675             "Vbucket 0's bloom filter wasn't enabled upon setup!");
2676
2677     item *itm = NULL;
2678     checkeq(ENGINE_SUCCESS,
2679             store(h, h1, NULL, OPERATION_SET,"k1", "v1", &itm),
2680             "Failed to fail to store an item.");
2681     h1->release(h, NULL, itm);
2682
2683     wait_for_flusher_to_settle(h, h1);
2684     int num_writes = get_int_stat(h, h1, "rw_0:io_num_write", "kvstore");
2685     int num_persisted = get_int_stat(h, h1, "ep_total_persisted");
2686     cb_assert(num_writes == 1 && num_persisted == 1);
2687
2688     checkeq(ENGINE_SUCCESS,
2689             del(h, h1, "k1", 0, 0), "Failed remove with value.");
2690     stop_persistence(h, h1);
2691     checkeq(ENGINE_SUCCESS,
2692             store(h, h1, NULL, OPERATION_SET,"k1", "v2", &itm, 0, 0),
2693             "Failed to fail to store an item.");
2694     h1->release(h, NULL, itm);
2695     int key_count = get_int_stat(h, h1, "vb_0:bloom_filter_key_count",
2696                                  "vbucket-details 0");
2697
2698     if (key_count == 0) {
2699         check(get_int_stat(h, h1, "rw_0:io_num_write", "kvstore") <= 2,
2700                 "Unexpected number of writes");
2701         start_persistence(h, h1);
2702         wait_for_flusher_to_settle(h, h1);
2703         checkeq(0, get_int_stat(h, h1, "vb_0:bloom_filter_key_count",
2704                                 "vbucket-details 0"),
2705                 "Unexpected number of keys in bloomfilter");
2706     } else {
2707         cb_assert(key_count == 1);
2708         checkeq(2, get_int_stat(h, h1, "rw_0:io_num_write", "kvstore"),
2709                 "Unexpected number of writes");
2710         start_persistence(h, h1);
2711         wait_for_flusher_to_settle(h, h1);
2712         checkeq(1, get_int_stat(h, h1, "vb_0:bloom_filter_key_count",
2713                                 "vbucket-details 0"),
2714                 "Unexpected number of keys in bloomfilter");
2715     }
2716
2717     return SUCCESS;
2718 }
2719
2720 static enum test_result test_datatype(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
2721     const void *cookie = testHarness.create_cookie();
2722     testHarness.set_datatype_support(cookie, true);
2723
2724     item *itm = NULL;
2725     const std::string key("{\"foo\":\"bar\"}");
2726     const protocol_binary_datatype_t datatype = PROTOCOL_BINARY_DATATYPE_JSON;
2727     uint64_t cas = 0;
2728     std::string value("x");
2729     checkeq(ENGINE_SUCCESS,
2730             storeCasOut(h, h1, NULL, 0, key, value, datatype, itm, cas),
2731             "Expected set to succeed");
2732
2733     checkeq(ENGINE_SUCCESS,
2734             get(h, h1, cookie, &itm, key, 0),
2735             "Unable to get stored item");
2736
2737     item_info info;
2738     h1->get_item_info(h, cookie, itm, &info);
2739     h1->release(h, cookie, itm);
2740     checkeq(static_cast<uint8_t>(PROTOCOL_BINARY_DATATYPE_JSON),
2741             info.datatype, "Invalid datatype");
2742
2743     const char* key1 = "foo";
2744     const char* val1 = "{\"foo1\":\"bar1\"}";
2745     ItemMetaData itm_meta;
2746     itm_meta.revSeqno = 10;
2747     itm_meta.cas = info.cas;
2748     itm_meta.exptime = info.exptime;
2749     itm_meta.flags = info.flags;
2750     set_with_meta(h, h1, key1, strlen(key1), val1, strlen(val1), 0, &itm_meta,
2751                   last_cas, 0, info.datatype, cookie);
2752
2753     checkeq(ENGINE_SUCCESS,
2754             get(h, h1, cookie, &itm, key1, 0),
2755             "Unable to get stored item");
2756
2757     h1->get_item_info(h, cookie, itm, &info);
2758     h1->release(h, cookie, itm);
2759     checkeq(static_cast<uint8_t>(PROTOCOL_BINARY_DATATYPE_JSON),
2760             info.datatype, "Invalid datatype, when setWithMeta");
2761
2762     testHarness.destroy_cookie(cookie);
2763     return SUCCESS;
2764 }
2765
2766 static enum test_result test_datatype_with_unknown_command(ENGINE_HANDLE *h,
2767                                                            ENGINE_HANDLE_V1 *h1) {
2768     const void *cookie = testHarness.create_cookie();
2769     testHarness.set_datatype_support(cookie, true);
2770     item *itm = NULL;
2771     const char* key = "foo";
2772     const char* val = "{\"foo\":\"bar\"}";
2773     uint8_t datatype = PROTOCOL_BINARY_DATATYPE_JSON;
2774
2775     ItemMetaData itm_meta;
2776     itm_meta.revSeqno = 10;
2777     itm_meta.cas = 0x1;
2778     itm_meta.exptime = 0;
2779     itm_meta.flags = 0;
2780
2781     //SET_WITH_META
2782     set_with_meta(h, h1, key, strlen(key), val, strlen(val), 0, &itm_meta,
2783                   0, 0, datatype, cookie);
2784
2785     checkeq(ENGINE_SUCCESS,
2786             get(h, h1, cookie, &itm, key, 0),
2787             "Unable to get stored item");
2788
2789     item_info info;
2790     h1->get_item_info(h, cookie, itm, &info);
2791     h1->release(h, NULL, itm);
2792     checkeq(static_cast<uint8_t>(PROTOCOL_BINARY_DATATYPE_JSON),
2793             info.datatype, "Invalid datatype, when setWithMeta");
2794
2795     //SET_RETURN_META
2796     set_ret_meta(h, h1, "foo1", 4, val, strlen(val), 0, 0, 0, 0, datatype,
2797                  cookie);
2798     checkeq(PROTOCOL_BINARY_RESPONSE_SUCCESS, last_status.load(),
2799             "Expected set returing meta to succeed");
2800     checkeq(static_cast<uint8_t>(PROTOCOL_BINARY_DATATYPE_JSON),
2801             last_datatype.load(), "Invalid datatype, when set_return_meta");
2802
2803     testHarness.destroy_cookie(cookie);
2804     return SUCCESS;
2805 }
2806
2807 static enum test_result test_session_cas_validation(ENGINE_HANDLE *h,
2808                                                     ENGINE_HANDLE_V1 *h1) {
2809     //Testing PROTOCOL_BINARY_CMD_SET_VBUCKET..
2810     char ext[4];
2811     protocol_binary_request_header *pkt;
2812     vbucket_state_t state = vbucket_state_active;
2813     uint32_t val = static_cast<uint32_t>(state);
2814     val = htonl(val);
2815     memcpy(ext, (char*)&val, sizeof(val));
2816
2817     uint64_t cas = 0x0101010101010101;
2818     pkt = createPacket(PROTOCOL_BINARY_CMD_SET_VBUCKET, 0, cas, ext, 4);
2819     checkeq(ENGINE_SUCCESS,
2820             h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
2821             "SET_VBUCKET command failed");
2822     cb_free(pkt);
2823     cb_assert(last_status == PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS);
2824
2825     cas = 0x0102030405060708;
2826     pkt = createPacket(PROTOCOL_BINARY_CMD_SET_VBUCKET, 0, cas, ext, 4);
2827     checkeq(ENGINE_SUCCESS,
2828             h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
2829             "SET_VBUCKET command failed");
2830     cb_free(pkt);
2831     cb_assert(last_status == PROTOCOL_BINARY_RESPONSE_SUCCESS);
2832
2833     return SUCCESS;
2834 }
2835
2836 static enum test_result test_access_scanner_settings(ENGINE_HANDLE *h,
2837                                                      ENGINE_HANDLE_V1 *h1) {
2838     if (!isWarmupEnabled(h, h1)) {
2839         // Access scanner n/a without warmup.
2840         return SKIPPED;
2841     }
2842
2843     // Create a unique access log path by combining with the db path.
2844     checkeq(ENGINE_SUCCESS,
2845             h1->get_stats(h, NULL, NULL, 0, add_stats),
2846             "Failed to get stats.");
2847     std::string dbname = vals.find("ep_dbname")->second;
2848
2849     const auto alog_path = std::string("alog_path=") + dbname +
2850             DIRECTORY_SEPARATOR_CHARACTER + "access.log";
2851     std::string newconfig = std::string(testHarness.get_current_testcase()->cfg)
2852                             + alog_path;
2853
2854     testHarness.reload_engine(&h, &h1,
2855                               testHarness.engine_path,
2856                               newconfig.c_str(),
2857                               true, false);
2858     wait_for_warmup_complete(h, h1);
2859
2860     std::string err_msg;
2861     // Check access scanner is enabled and alog_task_time is at default
2862     checkeq(true, get_bool_stat(h, h1, "ep_access_scanner_enabled"),
2863             "Expected access scanner to be enabled");
2864     cb_assert(get_int_stat(h, h1, "ep_alog_task_time") == 2);
2865
2866     // Ensure access_scanner_task_time is what its expected to be.
2867     // Need to wait until the AccessScanner task has been setup.
2868     wait_for_stat_change(h, h1, "ep_access_scanner_task_time",
2869                          std::string{"NOT_SCHEDULED"});
2870
2871     std::string str = get_str_stat(h, h1, "ep_access_scanner_task_time");
2872     std::string expected_time = "02:00";
2873     err_msg.assign("Initial time incorrect, expect: " +
2874                    expected_time + ", actual: " + str.substr(11, 5));
2875     checkeq(0, str.substr(11, 5).compare(expected_time), err_msg.c_str());
2876
2877     // Update alog_task_time and ensure the update is successful
2878     set_param(h, h1, protocol_binary_engine_param_flush, "alog_task_time", "5");
2879     expected_time = "05:00";
2880     str = get_str_stat(h, h1, "ep_access_scanner_task_time");
2881     err_msg.assign("Updated time incorrect, expect: " +
2882                    expected_time + ", actual: " + str.substr(11, 5));
2883     checkeq(0, str.substr(11, 5).compare(expected_time), err_msg.c_str());
2884
2885     // Update alog_sleep_time by 10 mins and ensure the update is successful.
2886     const std::chrono::minutes update_by{10};
2887     std::string targetTaskTime1{make_time_string(std::chrono::system_clock::now() +
2888                                                  update_by)};
2889
2890     set_param(h, h1, protocol_binary_engine_param_flush, "alog_sleep_time",
2891               std::to_string(update_by.count()).c_str());
2892     str = get_str_stat(h, h1, "ep_access_scanner_task_time");
2893
2894     // Recalculate now() + 10mins as upper bound on when the task should be
2895     // scheduled.
2896     std::string targetTaskTime2{make_time_string(std::chrono::system_clock::now() +
2897                                                  update_by)};
2898
2899     // ep_access_scanner_task_time should fall within the range of
2900     // targetTaskTime1 and targetTaskTime2
2901     err_msg.assign("Unexpected task time range, expect: " +
2902                    targetTaskTime1 + " <= " + str + " <= " + targetTaskTime2);
2903     check(targetTaskTime1 <= str, err_msg.c_str());
2904     check(str <= targetTaskTime2, err_msg.c_str());
2905
2906     return SUCCESS;
2907 }
2908
2909 static enum test_result test_access_scanner(ENGINE_HANDLE *h,
2910                                             ENGINE_HANDLE_V1 *h1) {
2911     if (!isWarmupEnabled(h, h1)) {
2912         // Access scanner not applicable without warmup.
2913         return SKIPPED;
2914     }
2915
2916     // Create a unique access log path by combining with the db path.
2917     checkeq(ENGINE_SUCCESS,
2918             h1->get_stats(h, NULL, NULL, 0, add_stats),
2919             "Failed to get stats.");
2920     const auto dbname = vals.find("ep_dbname")->second;
2921
2922     const auto alog_path = std::string("alog_path=") + dbname +
2923             DIRECTORY_SEPARATOR_CHARACTER + "access.log";
2924
2925     /* We do not want the access scanner task to be running while we initiate it
2926        explicitly below. Hence set the alog_task_time to about 1 ~ 2 hours
2927        from now */
2928     const time_t now = time(nullptr);
2929     struct tm tm_now;
2930     cb_gmtime_r(&now, &tm_now);
2931     const auto two_hours_hence = (tm_now.tm_hour + 2) % 24;
2932
2933     const auto alog_task_time = std::string("alog_task_time=") +
2934             std::to_string(two_hours_hence);
2935
2936     const auto newconfig = std::string(testHarness.get_current_testcase()->cfg)
2937                            + alog_path + ";" + alog_task_time;
2938
2939     testHarness.reload_engine(&h, &h1,
2940                               testHarness.engine_path,
2941                               newconfig.c_str(),
2942                               true, false);
2943     wait_for_warmup_complete(h, h1);
2944
2945     /* Check that alog_task_time was correctly updated. */
2946     checkeq(get_int_stat(h, h1, "ep_alog_task_time"),
2947             two_hours_hence,
2948             "Failed to set alog_task_time to 2 hours in the future");
2949
2950     checkeq(ENGINE_SUCCESS,
2951             h1->get_stats(h, NULL, NULL, 0, add_stats),
2952             "Failed to get stats.");
2953     std::string name = vals.find("ep_alog_path")->second;
2954
2955     /* Check access scanner is enabled */
2956     checkeq(true, get_bool_stat(h, h1, "ep_access_scanner_enabled"),
2957             "Access scanner task not enabled by default. Check test config");
2958
2959     const int num_shards = get_int_stat(h, h1, "ep_workload:num_shards",
2960                                         "workload");
2961     name = name + ".0";
2962     std::string prev(name + ".old");
2963
2964     /* Get the resident ratio down to below 95% - point at which access.log
2965      * generation occurs.
2966      */
2967     int num_items = 0;
2968     // Size chosen to create ~2000 items (i.e. 2x more than we sanity-check below)
2969     // with the given max_size for this test.
2970     const std::string value(2000, 'x');
2971     while (true) {
2972         // Gathering stats on every store is expensive, just check every 100 iterations
2973         if ((num_items % 100) == 0) {
2974             if (get_int_stat(h, h1, "vb_active_perc_mem_resident") < 94) {
2975                 break;
2976             }
2977         }
2978
2979         item *itm = NULL;
2980         std::string key("key" + std::to_string(num_items));
2981         ENGINE_ERROR_CODE ret = store(h, h1, NULL, OPERATION_SET,
2982                                       key.c_str(), value.c_str(), &itm);
2983         switch (ret) {
2984             case ENGINE_SUCCESS:
2985                 num_items++;
2986                 h1->release(h, NULL, itm);
2987                 break;
2988
2989             case ENGINE_ENOMEM:
2990             case ENGINE_TMPFAIL:
2991                 // Returned when at high watermark; simply retry the op.
2992                 h1->release(h, NULL, itm);
2993                 break;
2994
2995             default:
2996                 fprintf(stderr, "test_access_scanner: Unexpected result from store(): %d\n",
2997                         ret);
2998                 abort();
2999         }
3000
3001     }
3002
3003     // Sanity check - ensure we have enough vBucket quota (max_size)
3004     // such that we have 1000 items - enough to give us 0.1%
3005     // granuarity in any residency calculations. */
3006     if (num_items < 1000) {
3007         std::cerr << "Error: test_access_scanner: "
3008             "expected at least 1000 items after filling vbucket, "
3009             "but only have " << num_items << ". "
3010             "Check max_size setting for test." << std::endl;
3011         return FAIL;
3012     }
3013
3014     wait_for_flusher_to_settle(h, h1);
3015     verify_curr_items(h, h1, num_items, "Wrong number of items");
3016     int num_non_resident = get_int_stat(h, h1, "vb_active_num_non_resident");
3017     checkge(num_non_resident, num_items * 6 / 100,
3018             "Expected num_non_resident to be at least 6% of total items");
3019
3020     /* Run access scanner task once and expect it to generate access log */
3021     check(set_param(h, h1, protocol_binary_engine_param_flush,
3022                     "access_scanner_run", "true"),
3023           "Failed to trigger access scanner");
3024
3025     // Wait for the number of runs to equal the number of shards.
3026     wait_for_stat_to_be(h, h1, "ep_num_access_scanner_runs", num_shards);
3027
3028     /* This time since resident ratio is < 95% access log should be generated */
3029     checkeq(0, access(name.c_str(), F_OK),
3030             (std::string("access log file (") + name +
3031              ") should exist (got errno:" + std::to_string(errno)).c_str());
3032
3033     /* Increase resident ratio by deleting items */
3034     vbucketDelete(h, h1, 0);
3035     check(set_vbucket_state(h, h1, 0, vbucket_state_active),
3036           "Failed to set VB0 state.");
3037
3038     /* Run access scanner task once */
3039     const int access_scanner_skips =
3040             get_int_stat(h, h1, "ep_num_access_scanner_skips");
3041     check(set_param(h, h1, protocol_binary_engine_param_flush,
3042                     "access_scanner_run", "true"),
3043           "Failed to trigger access scanner");
3044     wait_for_stat_to_be(h, h1, "ep_num_access_scanner_skips",
3045                         access_scanner_skips + num_shards);
3046
3047     /* Access log files should be removed because resident ratio > 95% */
3048     checkeq(-1, access(prev.c_str(), F_OK),
3049             ".old access log file should not exist");
3050     checkeq(-1, access(name.c_str(), F_OK), "access log file should not exist");
3051
3052     return SUCCESS;
3053 }
3054
3055 static enum test_result test_set_param_message(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3056     set_param(h, h1, protocol_binary_engine_param_flush, "alog_task_time", "50");
3057
3058     checkeq(PROTOCOL_BINARY_RESPONSE_EINVAL, last_status.load(),
3059         "Expected an invalid value error for an out of bounds alog_task_time");
3060     check(std::string("Validation Error").compare(last_body), "Expected a "
3061             "validation error in the response body");
3062     return SUCCESS;
3063 }
3064
3065 static enum test_result test_warmup_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3066     if (!isWarmupEnabled(h, h1)) {
3067         return SKIPPED;
3068     }
3069
3070     item *it = NULL;
3071     check(set_vbucket_state(h, h1, 0, vbucket_state_active), "Failed to set VB0 state.");
3072     check(set_vbucket_state(h, h1, 1, vbucket_state_replica), "Failed to set VB1 state.");
3073
3074     for (int i = 0; i < 5000; ++i) {
3075         std::stringstream key;
3076         key << "key-" << i;
3077         checkeq(ENGINE_SUCCESS,
3078                 store(h, h1, NULL, OPERATION_SET, key.str().c_str(),
3079                       "somevalue", &it),
3080                 "Error setting.");
3081         h1->release(h, NULL, it);
3082     }
3083
3084     // Restart the server.
3085     testHarness.reload_engine(&h, &h1,
3086                               testHarness.engine_path,
3087                               testHarness.get_current_testcase()->cfg,
3088                               true, false);
3089
3090     wait_for_warmup_complete(h, h1);
3091
3092     const auto warmup_stats = get_all_stats(h, h1, "warmup");
3093
3094     // Check all expected warmup stats exists.
3095     const char* warmup_keys[] = { "ep_warmup_thread",
3096                                   "ep_warmup_value_count",
3097                                   "ep_warmup_key_count",
3098                                   "ep_warmup_dups",
3099                                   "ep_warmup_oom",
3100                                   "ep_warmup_time"};
3101     for (const auto* key : warmup_keys) {
3102         check(warmup_stats.find(key) != warmup_stats.end(),
3103               (std::string("Found no ") + key).c_str());
3104     }
3105
3106     std::string warmup_time = warmup_stats.at("ep_warmup_time");
3107     cb_assert(std::stoi(warmup_time) > 0);
3108
3109     const auto prev_vb_stats = get_all_stats(h, h1, "prev-vbucket");
3110
3111     check(prev_vb_stats.find("vb_0") != prev_vb_stats.end(),
3112           "Found no previous state for VB0");
3113     check(prev_vb_stats.find("vb_1") != prev_vb_stats.end(),
3114           "Found no previous state for VB1");
3115
3116     checkeq(std::string("active"), prev_vb_stats.at("vb_0"),
3117             "Unexpected stats for vb 0");
3118     checkeq(std::string("replica"), prev_vb_stats.at("vb_1"),
3119             "Unexpected stats for vb 1");
3120
3121     const auto vb_details_stats = get_all_stats(h, h1, "vbucket-details");
3122     checkeq(5000, std::stoi(vb_details_stats.at("vb_0:num_items")),
3123             "Unexpected item count for vb 0");
3124     checkeq(0, std::stoi(vb_details_stats.at("vb_1:num_items")),
3125             "Unexpected item count for vb 1");
3126
3127     return SUCCESS;
3128 }
3129
3130 static enum test_result test_warmup_with_threshold(ENGINE_HANDLE *h,
3131                                                    ENGINE_HANDLE_V1 *h1) {
3132     if (!isWarmupEnabled(h, h1)) {
3133         return SKIPPED;
3134     }
3135
3136     item *it = NULL;
3137     check(set_vbucket_state(h, h1, 0, vbucket_state_active), "Failed set vbucket 1 state.");
3138     check(set_vbucket_state(h, h1, 1, vbucket_state_active), "Failed set vbucket 2 state.");
3139     check(set_vbucket_state(h, h1, 2, vbucket_state_active), "Failed set vbucket 3 state.");
3140     check(set_vbucket_state(h, h1, 3, vbucket_state_active), "Failed set vbucket 4 state.");
3141
3142     for (int i = 0; i < 10000; ++i) {
3143         std::stringstream key;
3144         key << "key+" << i;
3145         checkeq(ENGINE_SUCCESS,
3146                 store(h, h1, NULL, OPERATION_SET, key.str().c_str(), "somevalue", &it,
3147                      0, (i % 4)),
3148                 "Error setting.");
3149         h1->release(h, NULL, it);
3150     }
3151
3152     // Restart the server.
3153     testHarness.reload_engine(&h, &h1,
3154                               testHarness.engine_path,
3155                               testHarness.get_current_testcase()->cfg,
3156                               true, false);
3157
3158     wait_for_warmup_complete(h, h1);
3159
3160     checkeq(1,
3161             get_int_stat(h, h1, "ep_warmup_min_item_threshold", "warmup"),
3162             "Unable to set warmup_min_item_threshold to 1%");
3163
3164     const std::string policy = get_str_stat(h, h1, "ep_item_eviction_policy");
3165
3166     if (policy == "full_eviction") {
3167         checkeq(get_int_stat(h, h1, "ep_warmup_key_count", "warmup"),
3168                 get_int_stat(h, h1, "ep_warmup_value_count", "warmup"),
3169                 "Warmed up key count didn't match warmed up value count");
3170     } else {
3171         checkeq(10000, get_int_stat(h, h1, "ep_warmup_key_count", "warmup"),
3172                 "Warmup didn't warmup all keys");
3173     }
3174     check(get_int_stat(h, h1, "ep_warmup_value_count", "warmup") <= 110,
3175             "Warmed up value count found to be greater than 1%");
3176
3177     cb_assert(get_int_stat(h, h1, "ep_warmup_time", "warmup") > 0);
3178
3179     return SUCCESS;
3180 }
3181
3182 #if 0
3183 // Comment out the entire test since the hack gave warnings on win32
3184 static enum test_result test_warmup_accesslog(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3185 #ifdef __APPLE__
3186     /* I'm getting a weird link error from clang.. disable the test until I
3187     ** understand why
3188     */
3189     return SKIPPED;
3190 #else
3191     item *it = NULL;
3192
3193     int n_items_to_store1 = 10;
3194     for (int i = 0; i < n_items_to_store1; ++i) {
3195         std::stringstream key;
3196         key << "key-" << i;
3197         const char* keystr = key.str().c_str();
3198         checkeq(ENGINE_SUCCESS,
3199                 store(h, h1, NULL, OPERATION_SET, keystr, "somevalue", &it, 0, 0),
3200                 "Error setting.");
3201         h1->release(h, NULL, it);
3202     }
3203
3204     wait_for_flusher_to_settle(h, h1);
3205
3206     int n_items_to_access = 10;
3207     for (int i = 0; i < n_items_to_access; ++i) {
3208         std::stringstream key;
3209         key << "key-" << i;
3210         const char* keystr = key.str().c_str();
3211         checkeq(ENGINE_SUCCESS,
3212                 get(h, h1, NULL, &it, keystr, 0),
3213                 "Error getting.");
3214         h1->release(h, NULL, it);
3215     }
3216
3217     // sleep so that scanner task can have timew to generate access log
3218     sleep(61);
3219
3220     // store additional items
3221     int n_items_to_store2 = 10;
3222     for (int i = 0; i < n_items_to_store2; ++i) {
3223         std::stringstream key;
3224         key << "key2-" << i;
3225         const char* keystr = key.str().c_str();
3226         checkeq(ENGINE_SUCCESS,
3227                 store(h, h1, NULL, OPERATION_SET, keystr, "somevalue", &it, 0, 0),
3228                 "Error setting.");
3229         h1->release(h, NULL, it);
3230     }
3231
3232     // Restart the server.
3233     testHarness.reload_engine(&h, &h1,
3234                               testHarness.engine_path,
3235                               testHarness.get_current_testcase()->cfg,
3236                               true, false);
3237
3238     wait_for_warmup_complete(h, h1);
3239     // n_items_to_access items should be loaded from access log first
3240     // but we continue to load until we hit 75% item watermark
3241
3242     int warmedup = get_int_stat(h, h1, "ep_warmup_value_count", "warmup");
3243     //    std::cout << "ep_warmup_value_count = " << warmedup << std::endl;
3244     int expected = (n_items_to_store1 + n_items_to_store2) * 0.75 + 1;
3245
3246     check(warmedup == expected, "Expected 16 items to be resident");
3247     return SUCCESS;
3248 #endif
3249 }
3250 #endif
3251
3252 static enum test_result test_warmup_oom(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3253     if (!isWarmupEnabled(h, h1)) {
3254         return SKIPPED;
3255     }
3256
3257     write_items(h, h1, 20000, 0, "superlongnameofkey1234567890123456789012345678902");
3258
3259     wait_for_flusher_to_settle(h, h1);
3260
3261     std::string config(testHarness.get_current_testcase()->cfg);
3262     config = config + "max_size=2097152;item_eviction_policy=value_only";
3263
3264     testHarness.reload_engine(&h, &h1,
3265                               testHarness.engine_path,
3266                               config.c_str(),
3267                               true, false);
3268
3269     wait_for_warmup_complete(h, h1);
3270
3271     protocol_binary_request_header *pkt = createPacket(PROTOCOL_BINARY_CMD_ENABLE_TRAFFIC);
3272     checkeq(ENGINE_SUCCESS,
3273             h1->unknown_command(h, NULL, pkt, add_response, testHarness.doc_namespace),
3274             "Failed to send data traffic command to the services");
3275     checkeq(PROTOCOL_BINARY_RESPONSE_ENOMEM, last_status.load(),
3276             "Data traffic command should have failed with enomem");
3277     cb_free(pkt);
3278
3279     return SUCCESS;
3280 }
3281
3282 static enum test_result test_cbd_225(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3283     item *i = NULL;
3284
3285     // get engine startup token
3286     time_t token1 = get_int_stat(h, h1, "ep_startup_time");
3287     check(token1 != 0, "Expected non-zero startup token");
3288
3289     // store some random data
3290     checkeq(ENGINE_SUCCESS,
3291             store(h, h1, NULL, OPERATION_SET,"k1", "v1", &i),
3292             "Failed to fail to store an item.");
3293     h1->release(h, NULL, i);
3294     checkeq(ENGINE_SUCCESS,
3295             store(h, h1, NULL, OPERATION_SET,"k2", "v2", &i),
3296             "Failed to fail to store an item.");
3297     h1->release(h, NULL, i);
3298     wait_for_flusher_to_settle(h, h1);
3299
3300     // check token again, which should be the same as before
3301     time_t token2 = get_int_stat(h, h1, "ep_startup_time");
3302     check(token2 == token1, "Expected the same startup token");
3303
3304     // reload the engine
3305     testHarness.time_travel(10);
3306     testHarness.reload_engine(&h, &h1,
3307                               testHarness.engine_path,
3308                               testHarness.get_current_testcase()->cfg,
3309                               true, false);
3310     wait_for_warmup_complete(h, h1);
3311
3312     // check token, this time we should get a different one
3313     time_t token3 = get_int_stat(h, h1, "ep_startup_time");
3314     check(token3 != token1, "Expected a different startup token");
3315
3316     return SUCCESS;
3317 }
3318
3319 static enum test_result test_workload_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3320     const void* cookie = testHarness.create_cookie();
3321     checkeq(ENGINE_SUCCESS,
3322             h1->get_stats(h, cookie, "workload",
3323                           strlen("workload"), add_stats),
3324             "Falied to get workload stats");
3325     testHarness.destroy_cookie(cookie);
3326     int num_read_threads = get_int_stat(h, h1, "ep_workload:num_readers",
3327                                                "workload");
3328     int num_write_threads = get_int_stat(h, h1, "ep_workload:num_writers",
3329                                                 "workload");
3330     int num_auxio_threads = get_int_stat(h, h1, "ep_workload:num_auxio",
3331                                                 "workload");
3332     int num_nonio_threads = get_int_stat(h, h1, "ep_workload:num_nonio",
3333                                                 "workload");
3334     int max_read_threads = get_int_stat(h, h1, "ep_workload:max_readers",
3335                                                "workload");
3336     int max_write_threads = get_int_stat(h, h1, "ep_workload:max_writers",
3337                                                 "workload");
3338     int max_auxio_threads = get_int_stat(h, h1, "ep_workload:max_auxio",
3339                                                 "workload");
3340     int max_nonio_threads = get_int_stat(h, h1, "ep_workload:max_nonio",
3341                                                 "workload");
3342     int num_shards = get_int_stat(h, h1, "ep_workload:num_shards", "workload");
3343     checkeq(4, num_read_threads, "Incorrect number of readers");
3344     // MB-12279: limiting max writers to 4 for DGM bgfetch performance
3345     checkeq(4, num_write_threads, "Incorrect number of writers");
3346     checkeq(1, num_auxio_threads, "Incorrect number of auxio threads");
3347     check(num_nonio_threads > 1 && num_nonio_threads <= 8,
3348           "Incorrect number of nonio threads");
3349     checkeq(4, max_read_threads, "Incorrect limit of readers");
3350     // MB-12279: limiting max writers to 4 for DGM bgfetch performance
3351     checkeq(4, max_write_threads, "Incorrect limit of writers");
3352     checkeq(1, max_auxio_threads, "Incorrect limit of auxio threads");
3353     check(max_nonio_threads > 1 && max_nonio_threads <=8,
3354           "Incorrect limit of nonio threads");
3355     checkeq(5, num_shards, "Incorrect number of shards");
3356     return SUCCESS;
3357 }
3358
3359 static enum test_result test_max_workload_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3360     const void* cookie = testHarness.create_cookie();
3361     checkeq(ENGINE_SUCCESS,
3362             h1->get_stats(h, cookie, "workload",
3363                           strlen("workload"), add_stats),
3364             "Failed to get workload stats");
3365     testHarness.destroy_cookie(cookie);
3366     int num_read_threads = get_int_stat(h, h1, "ep_workload:num_readers",
3367                                                "workload");
3368     int num_write_threads = get_int_stat(h, h1, "ep_workload:num_writers",
3369                                                 "workload");
3370     int num_auxio_threads = get_int_stat(h, h1, "ep_workload:num_auxio",
3371                                                 "workload");
3372     int num_nonio_threads = get_int_stat(h, h1, "ep_workload:num_nonio",
3373                                                 "workload");
3374     int max_read_threads = get_int_stat(h, h1, "ep_workload:max_readers",
3375                                                "workload");
3376     int max_write_threads = get_int_stat(h, h1, "ep_workload:max_writers",
3377                                                 "workload");
3378     int max_auxio_threads = get_int_stat(h, h1, "ep_workload:max_auxio",
3379                                                 "workload");
3380     int max_nonio_threads = get_int_stat(h, h1, "ep_workload:max_nonio",
3381                                                 "workload");
3382     int num_shards = get_int_stat(h, h1, "ep_workload:num_shards", "workload");
3383     // if max limit on other groups missing use remaining for readers & writers
3384     checkeq(5, num_read_threads, "Incorrect number of readers");
3385     // MB-12279: limiting max writers to 4 for DGM bgfetch performance
3386     checkeq(4, num_write_threads, "Incorrect number of writers");
3387
3388     checkeq(1, num_auxio_threads, "Incorrect number of auxio threads");// config
3389     checkeq(4, num_nonio_threads, "Incorrect number of nonio threads");// config
3390     checkeq(5, max_read_threads, "Incorrect limit of readers");// derived
3391     // MB-12279: limiting max writers to 4 for DGM bgfetch performance
3392     checkeq(4, max_write_threads, "Incorrect limit of writers");// max-capped
3393     checkeq(1, max_auxio_threads, "Incorrect limit of auxio threads");// config
3394     checkeq(4, max_nonio_threads, "Incorrect limit of nonio threads");// config
3395     checkeq(5, num_shards, "Incorrect number of shards");
3396     return SUCCESS;
3397 }
3398
3399 static enum test_result test_worker_stats(ENGINE_HANDLE *h, ENGINE_HANDLE_V1 *h1) {
3400     checkeq(ENGINE_SUCCESS,
3401             h1->get_stats(h, NULL, "dispatcher",
3402                           strlen("dispatcher"), add_stats),
3403             "Failed to get worker stats");
3404
3405     std::set<std::string> tasklist;
3406     tasklist.insert("Running a flusher loop");
3407     tasklist.insert("Snapshotting vbucket states for the shard");
3408     tasklist.insert("Deleting VBucket");
3409     tasklist.insert("Updating stat snapshot on disk");
3410     tasklist.insert("Batching background fetch");
3411     tasklist.insert("Fetching item from disk for vkey stat");
3412     tasklist.insert("Fetching item from disk");
3413     tasklist.insert("Loading TAP backfill from disk");
3414     tasklist.insert("Tap connection notifier");
3415     tasklist.insert("Generating access log");
3416     tasklist.insert("Fetching item from disk for tap");
3417     tasklist.insert("Snapshotting vbucket states");
3418     tasklist.insert("Persisting a vbucket state for vbucket");
3419     tasklist.insert("Reaping tap or dcp connection");
3420     tasklist.insert("Warmup - initialize");
3421     tasklist.insert("Warmup - creating vbuckets");
3422     tasklist.insert("Warmup - estimate item count");
3423     tasklist.insert("Warmup - key dump");
3424     tasklist.insert("Warmup - check for access log");