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