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 static void
clone_callback(void * UU (value_data),void ** cloned_value_data,long * clone_size,PAIR_ATTR * new_attr,bool UU (for_checkpoint),void * UU (write_extraargs))43 clone_callback(void* UU(value_data), void** cloned_value_data, long* clone_size, PAIR_ATTR* new_attr, bool UU(for_checkpoint), void* UU(write_extraargs))
44 {
45 *cloned_value_data = (void *)1;
46 *clone_size = 8;
47 new_attr->is_valid = false;
48 }
49
50 bool clone_flush_started;
51 bool clone_flush_completed;
52 CACHETABLE ct;
53
54 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 is_clone)55 flush (
56 CACHEFILE f __attribute__((__unused__)),
57 int UU(fd),
58 CACHEKEY k __attribute__((__unused__)),
59 void *v __attribute__((__unused__)),
60 void** UU(dd),
61 void *e __attribute__((__unused__)),
62 PAIR_ATTR s __attribute__((__unused__)),
63 PAIR_ATTR* new_size __attribute__((__unused__)),
64 bool w __attribute__((__unused__)),
65 bool keep __attribute__((__unused__)),
66 bool c __attribute__((__unused__)),
67 bool is_clone
68 )
69 {
70 if (is_clone) {
71 clone_flush_started = true;
72 usleep(4*1024*1024);
73 clone_flush_completed = true;
74 }
75 }
76
run_end_checkpoint(void * arg)77 static void *run_end_checkpoint(void *arg) {
78 CHECKPOINTER cp = toku_cachetable_get_checkpointer(ct);
79 toku_cachetable_end_checkpoint(
80 cp,
81 NULL,
82 NULL,
83 NULL
84 );
85 return arg;
86 }
87
88 //
89 // this test verifies that a PAIR that undergoes a checkpoint on the checkpoint thread is still pinnable while being written out
90 //
91 static void
cachetable_test(void)92 cachetable_test (void) {
93 const int test_limit = 200;
94 int r;
95 ct = NULL;
96 toku_cachetable_create(&ct, test_limit, ZERO_LSN, nullptr);
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 create_dummy_functions(f1);
102
103 void* v1;
104 CACHETABLE_WRITE_CALLBACK wc = def_write_callback(NULL);
105 wc.flush_callback = flush;
106 wc.clone_callback = clone_callback;
107 r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, def_fetch, def_pf_req_callback, def_pf_callback, true, NULL);
108 assert_zero(r);
109 r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_DIRTY, make_pair_attr(8));
110 assert_zero(r);
111 CHECKPOINTER cp = toku_cachetable_get_checkpointer(ct);
112 toku_cachetable_begin_checkpoint(cp, NULL);
113
114 clone_flush_started = false;
115 clone_flush_completed = false;
116 toku_pthread_t checkpoint_tid;
117 r = toku_pthread_create(toku_uninstrumented,
118 &checkpoint_tid,
119 nullptr,
120 run_end_checkpoint,
121 nullptr);
122 assert_zero(r);
123
124 usleep(1 * 1024 * 1024);
125
126 r = toku_cachetable_get_and_pin(f1, make_blocknum(1), 1, &v1, wc, def_fetch, def_pf_req_callback, def_pf_callback, true, NULL);
127 assert_zero(r);
128 assert(clone_flush_started && !clone_flush_completed);
129 r = toku_test_cachetable_unpin(f1, make_blocknum(1), 1, CACHETABLE_CLEAN, make_pair_attr(8));
130 assert_zero(r);
131
132 void *ret;
133 r = toku_pthread_join(checkpoint_tid, &ret);
134 assert_zero(r);
135 assert(clone_flush_started && clone_flush_completed);
136
137 toku_cachetable_verify(ct);
138 toku_cachefile_close(&f1, false, ZERO_LSN);
139 toku_cachetable_close(&ct);
140 }
141
142 int
test_main(int argc,const char * argv[])143 test_main(int argc, const char *argv[]) {
144 default_parse_args(argc, argv);
145 cachetable_test();
146 return 0;
147 }
148