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 #include "cachetable-test.h"
41 
42 uint64_t clean_val = 0;
43 uint64_t dirty_val = 0;
44 
45 bool check_me;
46 bool flush_called;
47 
48 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))49 flush (CACHEFILE f __attribute__((__unused__)),
50        int UU(fd),
51        CACHEKEY k  __attribute__((__unused__)),
52        void *v     __attribute__((__unused__)),
53        void** UU(dd),
54        void *e     __attribute__((__unused__)),
55        PAIR_ATTR s      __attribute__((__unused__)),
56        PAIR_ATTR* new_size      __attribute__((__unused__)),
57        bool w      __attribute__((__unused__)),
58        bool keep   __attribute__((__unused__)),
59        bool c      __attribute__((__unused__)),
60        bool UU(is_clone)
61        ) {
62   /* Do nothing */
63   if (verbose) { printf("FLUSH: %d\n", (int)k.b); }
64   //usleep (5*1024*1024);
65   // if the checkpoint is pending, assert that it is of what we made dirty
66   if (check_me) {
67     flush_called = true;
68     assert(c);
69     assert(e == &dirty_val);
70     assert(v == &dirty_val);
71     assert(keep);
72     assert(w);
73   }
74 }
75 
76 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)77 fetch (CACHEFILE f        __attribute__((__unused__)),
78        PAIR UU(p),
79        int UU(fd),
80        CACHEKEY k         __attribute__((__unused__)),
81        uint32_t fullhash __attribute__((__unused__)),
82        void **value       __attribute__((__unused__)),
83        void** UU(dd),
84        PAIR_ATTR *sizep        __attribute__((__unused__)),
85        int  *dirtyp,
86        void *extraargs    __attribute__((__unused__))
87        ) {
88   *dirtyp = 0;
89   if (extraargs) {
90       *value = &dirty_val;
91   }
92   else {
93       *value = &clean_val;
94   }
95   *sizep = make_pair_attr(8);
96   return 0;
97 }
98 
99 static void
cachetable_test(void)100 cachetable_test (void) {
101   const int test_limit = 20;
102   int r;
103   CACHETABLE ct;
104   toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
105   const char *fname1 = TOKU_TEST_FILENAME;
106   unlink(fname1);
107   CACHEFILE f1;
108   r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO); assert(r == 0);
109   create_dummy_functions(f1);
110 
111   void* v1;
112   void* v2;
113   CACHETABLE_WRITE_CALLBACK wc = def_write_callback(&dirty_val);
114   wc.flush_callback = flush;
115   r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, fetch, def_pf_req_callback, def_pf_callback, true, &dirty_val);
116   wc.write_extraargs = NULL;
117   r = toku_cachetable_get_and_pin(f1, make_blocknum(2), 2, &v2, wc, fetch, def_pf_req_callback, def_pf_callback, true, NULL);
118 
119   //
120   // Here is the test, we have two pairs, v1 is dirty, v2 is clean, but both are currently pinned
121   // Then we will begin a checkpoint, which should theoretically mark both as pending, but
122   // flush will be called only for v1, because v1 is dirty
123   //
124   CHECKPOINTER cp = toku_cachetable_get_checkpointer(ct);
125   toku_cachetable_begin_checkpoint(cp, NULL);
126 
127 
128   r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_DIRTY, make_pair_attr(8));
129   r = toku_test_cachetable_unpin(f1, make_blocknum(2), 2, CACHETABLE_CLEAN, make_pair_attr(8));
130 
131   check_me = true;
132   flush_called = false;
133   toku_cachetable_end_checkpoint(
134       cp,
135       NULL,
136       NULL,
137       NULL
138       );
139   assert(r==0);
140   assert(flush_called);
141   check_me = false;
142 
143   toku_cachetable_verify(ct);
144   toku_cachefile_close(&f1, false, ZERO_LSN);
145   toku_cachetable_close(&ct);
146 
147 
148 }
149 
150 int
test_main(int argc,const char * argv[])151 test_main(int argc, const char *argv[]) {
152   default_parse_args(argc, argv);
153   cachetable_test();
154   return 0;
155 }
156