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