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 int num_entries;
42 bool flush_may_occur;
43 int expected_flushed_key;
44 bool check_flush;
45
46
47 //
48 // This test verifies that if partial eviction is expensive and
49 // does not estimate number of freed bytes to be greater than 0,
50 // then partial eviction is not called, and normal eviction
51 // is used. The verification is done ia an assert(false) in
52 // pe_callback.
53 //
54
55
56 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))57 flush (CACHEFILE f __attribute__((__unused__)),
58 int UU(fd),
59 CACHEKEY k __attribute__((__unused__)),
60 void *v __attribute__((__unused__)),
61 void** UU(dd),
62 void *e __attribute__((__unused__)),
63 PAIR_ATTR s __attribute__((__unused__)),
64 PAIR_ATTR* new_size __attribute__((__unused__)),
65 bool w __attribute__((__unused__)),
66 bool keep __attribute__((__unused__)),
67 bool c __attribute__((__unused__)),
68 bool UU(is_clone)
69 ) {
70 /* Do nothing */
71 if (check_flush && !keep) {
72 if (verbose) { printf("FLUSH: %d write_me %d\n", (int)k.b, w); }
73 assert(flush_may_occur);
74 assert(!w);
75 assert(expected_flushed_key == (int)k.b);
76 expected_flushed_key--;
77 }
78 }
79
80 static int
fetch(CACHEFILE f,PAIR UU (p),int UU (fd),CACHEKEY k,uint32_t fullhash,void ** value,void ** UU (dd),PAIR_ATTR * sizep,int * dirtyp,void * extraargs)81 fetch (CACHEFILE f __attribute__((__unused__)),
82 PAIR UU(p),
83 int UU(fd),
84 CACHEKEY k __attribute__((__unused__)),
85 uint32_t fullhash __attribute__((__unused__)),
86 void **value __attribute__((__unused__)),
87 void** UU(dd),
88 PAIR_ATTR *sizep __attribute__((__unused__)),
89 int *dirtyp,
90 void *extraargs __attribute__((__unused__))
91 ) {
92 *dirtyp = 0;
93 *value = NULL;
94 *sizep = make_pair_attr(1);
95 return 0;
96 }
97
98 static void
pe_est_callback(void * UU (ftnode_pv),void * UU (dd),long * bytes_freed_estimate,enum partial_eviction_cost * cost,void * UU (write_extraargs))99 pe_est_callback(
100 void* UU(ftnode_pv),
101 void* UU(dd),
102 long* bytes_freed_estimate,
103 enum partial_eviction_cost *cost,
104 void* UU(write_extraargs)
105 )
106 {
107 *bytes_freed_estimate = 0;
108 *cost = PE_EXPENSIVE;
109 }
110
111 static int
pe_callback(void * ftnode_pv,PAIR_ATTR bytes_to_free,void * extraargs,void (* finalize)(PAIR_ATTR bytes_freed,void * extra),void * finalize_extra)112 pe_callback (
113 void *ftnode_pv __attribute__((__unused__)),
114 PAIR_ATTR bytes_to_free __attribute__((__unused__)),
115 void* extraargs __attribute__((__unused__)),
116 void (*finalize)(PAIR_ATTR bytes_freed, void *extra),
117 void *finalize_extra
118 )
119 {
120 assert(false);
121 finalize(bytes_to_free, finalize_extra);
122 return 0;
123 }
124
125
126 static void
cachetable_test(void)127 cachetable_test (void) {
128 const int test_limit = 4;
129 num_entries = 0;
130 int r;
131 CACHETABLE ct;
132 toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
133 const char *fname1 = TOKU_TEST_FILENAME;
134 unlink(fname1);
135 CACHEFILE f1;
136 r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
137
138 void* v1;
139 void* v2;
140 flush_may_occur = false;
141 check_flush = true;
142 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
143 wc.flush_callback = flush;
144 wc.pe_est_callback = pe_est_callback;
145 wc.pe_callback = pe_callback;
146 for (int i = 0; i < 100000; i++) {
147 r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, fetch, def_pf_req_callback, def_pf_callback, true, NULL);
148 r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(1));
149 }
150 for (int i = 0; i < 8; i++) {
151 r = toku_cachetable_get_and_pin(f1, make_blocknum(2), 2, &v2, wc, fetch, def_pf_req_callback, def_pf_callback, true, NULL);
152 r = toku_test_cachetable_unpin(f1, make_blocknum(2), 2, CACHETABLE_CLEAN, make_pair_attr(1));
153 }
154 for (int i = 0; i < 4; i++) {
155 r = toku_cachetable_get_and_pin(f1, make_blocknum(3), 3, &v2, wc, fetch, def_pf_req_callback, def_pf_callback, true, NULL);
156 r = toku_test_cachetable_unpin(f1, make_blocknum(3), 3, CACHETABLE_CLEAN, make_pair_attr(1));
157 }
158 for (int i = 0; i < 2; i++) {
159 r = toku_cachetable_get_and_pin(f1, make_blocknum(4), 4, &v2, wc, fetch, def_pf_req_callback, def_pf_callback, true, NULL);
160 r = toku_test_cachetable_unpin(f1, make_blocknum(4), 4, CACHETABLE_CLEAN, make_pair_attr(1));
161 }
162 flush_may_occur = true;
163 expected_flushed_key = 4;
164 toku_cachetable_put(f1, make_blocknum(5), 5, NULL, make_pair_attr(4), wc, put_callback_nop);
165 flush_may_occur = true;
166 expected_flushed_key = 5;
167 r = toku_test_cachetable_unpin(f1, make_blocknum(5), 5, CACHETABLE_CLEAN, make_pair_attr(4));
168
169 check_flush = false;
170 toku_cachefile_close(&f1, false, ZERO_LSN);
171 toku_cachetable_close(&ct);
172 }
173
174 int
test_main(int argc,const char * argv[])175 test_main(int argc, const char *argv[]) {
176 default_parse_args(argc, argv);
177 cachetable_test();
178 return 0;
179 }
180