1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     PerconaFT is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     PerconaFT is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ----------------------------------------
23 
24     PerconaFT is free software: you can redistribute it and/or modify
25     it under the terms of the GNU Affero General Public License, version 3,
26     as published by the Free Software Foundation.
27 
28     PerconaFT is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Affero General Public License for more details.
32 
33     You should have received a copy of the GNU Affero General Public License
34     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36 
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38 
39 #include "test.h"
40 
41 //
42 // This test verifies that the cleaner thread doesn't call the callback if
43 // nothing needs flushing.
44 //
45 
46 toku_mutex_t attr_mutex;
47 
48 // used to access engine status variables
49 #define STATUS_VALUE(x) ct_test_status.status[CACHETABLE_STATUS_S::x].value.num
50 
51 const PAIR_ATTR attrs[] = {
52     { .size = 20, .nonleaf_size = 13, .leaf_size = 900, .rollback_size = 123, .cache_pressure_size = 403, .is_valid = true },
53     { .size = 21, .nonleaf_size = 16, .leaf_size = 910, .rollback_size = 113, .cache_pressure_size = 401, .is_valid = true },
54     { .size = 22, .nonleaf_size = 17, .leaf_size = 940, .rollback_size = 133, .cache_pressure_size = 402, .is_valid = true },
55     { .size = 23, .nonleaf_size = 18, .leaf_size = 931, .rollback_size = 153, .cache_pressure_size = 404, .is_valid = true },
56     { .size = 25, .nonleaf_size = 19, .leaf_size = 903, .rollback_size = 173, .cache_pressure_size = 413, .is_valid = true },
57     { .size = 26, .nonleaf_size = 10, .leaf_size = 903, .rollback_size = 193, .cache_pressure_size = 423, .is_valid = true },
58     { .size = 20, .nonleaf_size = 11, .leaf_size = 902, .rollback_size = 103, .cache_pressure_size = 433, .is_valid = true },
59     { .size = 29, .nonleaf_size = 12, .leaf_size = 909, .rollback_size = 113, .cache_pressure_size = 443, .is_valid = true }
60 };
61 const int n_pairs = (sizeof attrs) / (sizeof attrs[0]);
62 
63 static void
flush(CACHEFILE f,int UU (fd),CACHEKEY k,void * v,void ** UU (dd),void * e,PAIR_ATTR s,PAIR_ATTR * new_size,bool w,bool keep,bool c,bool UU (is_clone))64 flush (CACHEFILE f __attribute__((__unused__)),
65        int UU(fd),
66        CACHEKEY k  __attribute__((__unused__)),
67        void *v     __attribute__((__unused__)),
68        void** UU(dd),
69        void *e     __attribute__((__unused__)),
70        PAIR_ATTR s      __attribute__((__unused__)),
71        PAIR_ATTR* new_size      __attribute__((__unused__)),
72        bool w      __attribute__((__unused__)),
73        bool keep   __attribute__((__unused__)),
74        bool c      __attribute__((__unused__)),
75         bool UU(is_clone)
76        ) {
77     PAIR_ATTR *CAST_FROM_VOIDP(expect, e);
78     if (!keep) {
79         toku_mutex_lock(&attr_mutex);   // purpose is to make this function single-threaded
80         expect->size -= s.size;
81         expect->nonleaf_size -= s.nonleaf_size;
82         expect->leaf_size -= s.leaf_size;
83         expect->rollback_size -= s.rollback_size;
84         expect->cache_pressure_size -= s.cache_pressure_size;
85         toku_mutex_unlock(&attr_mutex);
86     }
87 }
88 
89 static void
run_test(void)90 run_test (void) {
91     const int test_limit = 1000;
92     int r;
93     CACHETABLE ct;
94     toku_mutex_init(toku_uninstrumented, &attr_mutex, nullptr);
95     toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
96 
97     const char *fname1 = TOKU_TEST_FILENAME;
98     unlink(fname1);
99     CACHEFILE f1;
100     r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
101 
102     CACHETABLE_STATUS_S ct_test_status;
103     toku_cachetable_get_status(ct, &ct_test_status);
104     assert(STATUS_VALUE(CT_SIZE_NONLEAF) == 0);
105     assert(STATUS_VALUE(CT_SIZE_LEAF) == 0);
106     assert(STATUS_VALUE(CT_SIZE_ROLLBACK) == 0);
107     assert(STATUS_VALUE(CT_SIZE_CACHEPRESSURE) == 0);
108 
109     void* vs[n_pairs];
110     PAIR_ATTR expect = { .size = 0, .nonleaf_size = 0, .leaf_size = 0, .rollback_size = 0, .cache_pressure_size = 0 };
111     CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
112     wc.flush_callback = flush;
113     wc.write_extraargs = &expect;
114     for (int i = 0; i < n_pairs; ++i) {
115         r = toku_cachetable_get_and_pin(f1, make_blocknum(i+1), i+1, &vs[i],
116                                         wc,
117                                         def_fetch,
118                                         def_pf_req_callback,
119                                         def_pf_callback,
120                                         true,
121                                         &expect);
122         assert_zero(r);
123         r = toku_test_cachetable_unpin(f1, make_blocknum(i+1), i+1, CACHETABLE_DIRTY, attrs[i]);
124         assert_zero(r);
125         expect.size += attrs[i].size;
126         expect.nonleaf_size += attrs[i].nonleaf_size;
127         expect.leaf_size += attrs[i].leaf_size;
128         expect.rollback_size += attrs[i].rollback_size;
129         expect.cache_pressure_size += attrs[i].cache_pressure_size;
130     }
131 
132     toku_cachetable_get_status(ct, &ct_test_status);
133     assert(STATUS_VALUE(CT_SIZE_NONLEAF      ) == (uint64_t) expect.nonleaf_size);
134     assert(STATUS_VALUE(CT_SIZE_LEAF         ) == (uint64_t) expect.leaf_size);
135     assert(STATUS_VALUE(CT_SIZE_ROLLBACK     ) == (uint64_t) expect.rollback_size);
136     assert(STATUS_VALUE(CT_SIZE_CACHEPRESSURE) == (uint64_t) expect.cache_pressure_size);
137 
138     void *big_v;
139     r = toku_cachetable_get_and_pin(f1, make_blocknum(n_pairs + 1), n_pairs + 1, &big_v,
140                                     wc,
141                                     def_fetch,
142                                     def_pf_req_callback,
143                                     def_pf_callback,
144                                     true,
145                                     &expect);
146     toku_test_cachetable_unpin(f1, make_blocknum(n_pairs + 1), n_pairs + 1, CACHETABLE_CLEAN,
147                           make_pair_attr(test_limit - expect.size + 20));
148 
149     usleep(2*1024*1024);
150 
151     toku_cachetable_get_status(ct, &ct_test_status);
152     assert(STATUS_VALUE(CT_SIZE_NONLEAF      ) == (uint64_t) expect.nonleaf_size);
153     assert(STATUS_VALUE(CT_SIZE_LEAF         ) == (uint64_t) expect.leaf_size);
154     assert(STATUS_VALUE(CT_SIZE_ROLLBACK     ) == (uint64_t) expect.rollback_size);
155     assert(STATUS_VALUE(CT_SIZE_CACHEPRESSURE) == (uint64_t) expect.cache_pressure_size);
156 
157     toku_cachetable_verify(ct);
158     toku_cachefile_close(&f1, false, ZERO_LSN);
159     toku_cachetable_close(&ct);
160 }
161 
162 int
test_main(int argc,const char * argv[])163 test_main(int argc, const char *argv[]) {
164   default_parse_args(argc, argv);
165   run_test();
166   return 0;
167 }
168 
169 #undef STATUS_VALUE
170