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 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 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 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 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 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 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