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 // test that corrupt checksums are detected
40
41 #include "test.h"
42
43 #include "serialize/compress.h"
44 #include "serialize/sub_block.h"
45
46 #include <toku_portability.h>
47 #include <util/threadpool.h>
48
49 #include <stdio.h>
50 #include <errno.h>
51 #include <string.h>
52
53 static uint8_t
get_uint8_at_offset(void * vp,size_t offset)54 get_uint8_at_offset(void *vp, size_t offset) {
55 uint8_t *ip = (uint8_t *) vp;
56 return ip[offset];
57 }
58
59 static void
set_uint8_at_offset(void * vp,size_t offset,uint8_t newv)60 set_uint8_at_offset(void *vp, size_t offset, uint8_t newv) {
61 uint8_t *ip = (uint8_t *) vp;
62 ip[offset] = newv;
63 }
64
65 static void
test_sub_block_checksum(void * buf,int total_size,int my_max_sub_blocks,int n_cores,struct toku_thread_pool * pool,enum toku_compression_method method)66 test_sub_block_checksum(void *buf, int total_size, int my_max_sub_blocks, int n_cores, struct toku_thread_pool *pool, enum toku_compression_method method) {
67 if (verbose)
68 printf("%s:%d %d %d\n", __FUNCTION__, __LINE__, total_size, my_max_sub_blocks);
69
70 int r;
71
72 int sub_block_size, n_sub_blocks;
73 r = choose_sub_block_size(total_size, my_max_sub_blocks, &sub_block_size, &n_sub_blocks);
74 assert(r == 0);
75 if (verbose)
76 printf("%s:%d %d %d\n", __FUNCTION__, __LINE__, sub_block_size, n_sub_blocks);
77
78 struct sub_block sub_blocks[n_sub_blocks];
79 set_all_sub_block_sizes(total_size, sub_block_size, n_sub_blocks, sub_blocks);
80
81 size_t cbuf_size_bound = get_sum_compressed_size_bound(n_sub_blocks, sub_blocks, method);
82 void *cbuf = toku_malloc(cbuf_size_bound);
83 assert(cbuf);
84
85 size_t cbuf_size = compress_all_sub_blocks(n_sub_blocks, sub_blocks, (char*)buf, (char*)cbuf, n_cores, pool, method);
86 assert(cbuf_size <= cbuf_size_bound);
87
88 void *ubuf = toku_malloc(total_size);
89 assert(ubuf);
90
91 for (int xidx = 0; xidx < n_sub_blocks; xidx++) {
92 // corrupt a checksum
93 sub_blocks[xidx].xsum += 1;
94
95 r = decompress_all_sub_blocks(n_sub_blocks, sub_blocks, (unsigned char*)cbuf, (unsigned char*)ubuf, n_cores, pool);
96 assert(r != 0);
97
98 // reset the checksums
99 sub_blocks[xidx].xsum -= 1;
100
101 r = decompress_all_sub_blocks(n_sub_blocks, sub_blocks, (unsigned char*)cbuf, (unsigned char*)ubuf, n_cores, pool);
102 assert(r == 0);
103 assert(memcmp(buf, ubuf, total_size) == 0);
104
105 // corrupt the data
106 size_t offset = random() % cbuf_size;
107 unsigned char c = get_uint8_at_offset(cbuf, offset);
108 set_uint8_at_offset(cbuf, offset, c+1);
109
110 r = decompress_all_sub_blocks(n_sub_blocks, sub_blocks, (unsigned char*)cbuf, (unsigned char*)ubuf, n_cores, pool);
111 assert(r != 0);
112
113 // reset the data
114 set_uint8_at_offset(cbuf, offset, c);
115
116 r = decompress_all_sub_blocks(n_sub_blocks, sub_blocks, (unsigned char*)cbuf, (unsigned char*)ubuf, n_cores, pool);
117
118 assert(r == 0);
119 assert(memcmp(buf, ubuf, total_size) == 0);
120 }
121 toku_free(ubuf);
122 toku_free(cbuf);
123 }
124
125 static void
set_random(void * buf,int total_size)126 set_random(void *buf, int total_size) {
127 char *bp = (char *) buf;
128 for (int i = 0; i < total_size; i++)
129 bp[i] = random();
130 }
131
132 static void
run_test(int total_size,int n_cores,struct toku_thread_pool * pool,enum toku_compression_method method)133 run_test(int total_size, int n_cores, struct toku_thread_pool *pool, enum toku_compression_method method) {
134 void *buf = toku_malloc(total_size);
135 assert(buf);
136
137 for (int my_max_sub_blocks = 1; my_max_sub_blocks <= max_sub_blocks; my_max_sub_blocks++) {
138 memset(buf, 0, total_size);
139 test_sub_block_checksum(buf, total_size, my_max_sub_blocks, n_cores, pool, method);
140
141 set_random(buf, total_size);
142 test_sub_block_checksum(buf, total_size, my_max_sub_blocks, n_cores, pool, method);
143 }
144
145 toku_free(buf);
146 }
147 int
test_main(int argc,const char * argv[])148 test_main (int argc, const char *argv[]) {
149 int n_cores = 1;
150 int e = 1;
151
152 for (int i = 1; i < argc; i++) {
153 const char *arg = argv[i];
154 if (strcmp(arg, "-v") == 0 || strcmp(arg, "--verbose") == 0) {
155 verbose++;
156 verbose_decompress_sub_block = 1;
157 continue;
158 }
159 if (strcmp(arg, "-q") == 0) {
160 verbose_decompress_sub_block = 0;
161 continue;
162 }
163 if (strcmp(arg, "-n") == 0) {
164 if (i+1 < argc) {
165 n_cores = atoi(argv[++i]);
166 continue;
167 }
168 }
169 if (strcmp(arg, "-e") == 0) {
170 if (i+1 < argc) {
171 e = atoi(argv[++i]);
172 continue;
173 }
174 }
175 }
176
177 struct toku_thread_pool *pool = NULL;
178 int r = toku_thread_pool_create(&pool, 8); assert(r == 0);
179
180 for (int total_size = 256*1024; total_size <= 4*1024*1024; total_size *= 2) {
181 for (int size = total_size - e; size <= total_size + e; size++) {
182 run_test(size, n_cores, pool, TOKU_NO_COMPRESSION);
183 run_test(size, n_cores, pool, TOKU_ZLIB_METHOD);
184 run_test(size, n_cores, pool, TOKU_ZLIB_WITHOUT_CHECKSUM_METHOD);
185 run_test(size, n_cores, pool, TOKU_QUICKLZ_METHOD);
186 run_test(size, n_cores, pool, TOKU_LZMA_METHOD);
187 }
188 }
189
190 toku_thread_pool_destroy(&pool);
191
192 return 0;
193 }
194