]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/Checksummer.h
6611e8749f4d3a80b622cd8dafcc6492e265fe78
[ceph.git] / ceph / src / common / Checksummer.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #ifndef CEPH_OS_BLUESTORE_CHECKSUMMER
5 #define CEPH_OS_BLUESTORE_CHECKSUMMER
6
7 #include "include/buffer.h"
8 #include "xxHash/xxhash.h"
9
10 class Checksummer {
11 public:
12 enum CSumType {
13 CSUM_NONE = 1, //intentionally set to 1 to be aligned with OSDMnitor's pool_opts_t handling - it treats 0 as unset while we need to distinguish none and unset cases
14 CSUM_XXHASH32 = 2,
15 CSUM_XXHASH64 = 3,
16 CSUM_CRC32C = 4,
17 CSUM_CRC32C_16 = 5, // low 16 bits of crc32c
18 CSUM_CRC32C_8 = 6, // low 8 bits of crc32c
19 CSUM_MAX,
20 };
21 static const char *get_csum_type_string(unsigned t) {
22 switch (t) {
23 case CSUM_NONE: return "none";
24 case CSUM_XXHASH32: return "xxhash32";
25 case CSUM_XXHASH64: return "xxhash64";
26 case CSUM_CRC32C: return "crc32c";
27 case CSUM_CRC32C_16: return "crc32c_16";
28 case CSUM_CRC32C_8: return "crc32c_8";
29 default: return "???";
30 }
31 }
32 static int get_csum_string_type(const std::string &s) {
33 if (s == "none")
34 return CSUM_NONE;
35 if (s == "xxhash32")
36 return CSUM_XXHASH32;
37 if (s == "xxhash64")
38 return CSUM_XXHASH64;
39 if (s == "crc32c")
40 return CSUM_CRC32C;
41 if (s == "crc32c_16")
42 return CSUM_CRC32C_16;
43 if (s == "crc32c_8")
44 return CSUM_CRC32C_8;
45 return -EINVAL;
46 }
47
48 static size_t get_csum_init_value_size(int csum_type) {
49 switch (csum_type) {
50 case CSUM_NONE: return 0;
51 case CSUM_XXHASH32: return sizeof(xxhash32::init_value_t);
52 case CSUM_XXHASH64: return sizeof(xxhash64::init_value_t);
53 case CSUM_CRC32C: return sizeof(crc32c::init_value_t);
54 case CSUM_CRC32C_16: return sizeof(crc32c_16::init_value_t);
55 case CSUM_CRC32C_8: return sizeof(crc32c_8::init_value_t);
56 default: return 0;
57 }
58 }
59 static size_t get_csum_value_size(int csum_type) {
60 switch (csum_type) {
61 case CSUM_NONE: return 0;
62 case CSUM_XXHASH32: return 4;
63 case CSUM_XXHASH64: return 8;
64 case CSUM_CRC32C: return 4;
65 case CSUM_CRC32C_16: return 2;
66 case CSUM_CRC32C_8: return 1;
67 default: return 0;
68 }
69 }
70
71 struct crc32c {
72 typedef uint32_t init_value_t;
73 typedef __le32 value_t;
74
75 // we have no execution context/state.
76 typedef int state_t;
77 static void init(state_t *state) {
78 }
79 static void fini(state_t *state) {
80 }
81
82 static value_t calc(
83 state_t state,
84 init_value_t init_value,
85 size_t len,
86 bufferlist::const_iterator& p
87 ) {
88 return p.crc32c(len, init_value);
89 }
90 };
91
92 struct crc32c_16 {
93 typedef uint32_t init_value_t;
94 typedef __le16 value_t;
95
96 // we have no execution context/state.
97 typedef int state_t;
98 static void init(state_t *state) {
99 }
100 static void fini(state_t *state) {
101 }
102
103 static value_t calc(
104 state_t state,
105 init_value_t init_value,
106 size_t len,
107 bufferlist::const_iterator& p
108 ) {
109 return p.crc32c(len, init_value) & 0xffff;
110 }
111 };
112
113 struct crc32c_8 {
114 typedef uint32_t init_value_t;
115 typedef __u8 value_t;
116
117 // we have no execution context/state.
118 typedef int state_t;
119 static void init(state_t *state) {
120 }
121 static void fini(state_t *state) {
122 }
123
124 static value_t calc(
125 state_t state,
126 init_value_t init_value,
127 size_t len,
128 bufferlist::const_iterator& p
129 ) {
130 return p.crc32c(len, init_value) & 0xff;
131 }
132 };
133
134 struct xxhash32 {
135 typedef uint32_t init_value_t;
136 typedef __le32 value_t;
137
138 typedef XXH32_state_t *state_t;
139 static void init(state_t *s) {
140 *s = XXH32_createState();
141 }
142 static void fini(state_t *s) {
143 XXH32_freeState(*s);
144 }
145
146 static value_t calc(
147 state_t state,
148 init_value_t init_value,
149 size_t len,
150 bufferlist::const_iterator& p
151 ) {
152 XXH32_reset(state, init_value);
153 while (len > 0) {
154 const char *data;
155 size_t l = p.get_ptr_and_advance(len, &data);
156 XXH32_update(state, data, l);
157 len -= l;
158 }
159 return XXH32_digest(state);
160 }
161 };
162
163 struct xxhash64 {
164 typedef uint64_t init_value_t;
165 typedef __le64 value_t;
166
167 typedef XXH64_state_t *state_t;
168 static void init(state_t *s) {
169 *s = XXH64_createState();
170 }
171 static void fini(state_t *s) {
172 XXH64_freeState(*s);
173 }
174
175 static value_t calc(
176 state_t state,
177 init_value_t init_value,
178 size_t len,
179 bufferlist::const_iterator& p
180 ) {
181 XXH64_reset(state, init_value);
182 while (len > 0) {
183 const char *data;
184 size_t l = p.get_ptr_and_advance(len, &data);
185 XXH64_update(state, data, l);
186 len -= l;
187 }
188 return XXH64_digest(state);
189 }
190 };
191
192 template<class Alg>
193 static int calculate(
194 size_t csum_block_size,
195 size_t offset,
196 size_t length,
197 const bufferlist &bl,
198 bufferptr* csum_data
199 ) {
200 return calculate<Alg>(-1, csum_block_size, offset, length, bl, csum_data);
201 }
202
203 template<class Alg>
204 static int calculate(
205 typename Alg::init_value_t init_value,
206 size_t csum_block_size,
207 size_t offset,
208 size_t length,
209 const bufferlist &bl,
210 bufferptr* csum_data) {
211 assert(length % csum_block_size == 0);
212 size_t blocks = length / csum_block_size;
213 bufferlist::const_iterator p = bl.begin();
214 assert(bl.length() >= length);
215
216 typename Alg::state_t state;
217 Alg::init(&state);
218
219 assert(csum_data->length() >= (offset + length) / csum_block_size *
220 sizeof(typename Alg::value_t));
221
222 typename Alg::value_t *pv =
223 reinterpret_cast<typename Alg::value_t*>(csum_data->c_str());
224 pv += offset / csum_block_size;
225 while (blocks--) {
226 *pv = Alg::calc(state, init_value, csum_block_size, p);
227 ++pv;
228 }
229 Alg::fini(&state);
230 return 0;
231 }
232
233 template<class Alg>
234 static int verify(
235 size_t csum_block_size,
236 size_t offset,
237 size_t length,
238 const bufferlist &bl,
239 const bufferptr& csum_data,
240 uint64_t *bad_csum=0
241 ) {
242 assert(length % csum_block_size == 0);
243 bufferlist::const_iterator p = bl.begin();
244 assert(bl.length() >= length);
245
246 typename Alg::state_t state;
247 Alg::init(&state);
248
249 const typename Alg::value_t *pv =
250 reinterpret_cast<const typename Alg::value_t*>(csum_data.c_str());
251 pv += offset / csum_block_size;
252 size_t pos = offset;
253 while (length > 0) {
254 typename Alg::value_t v = Alg::calc(state, -1, csum_block_size, p);
255 if (*pv != v) {
256 if (bad_csum) {
257 *bad_csum = v;
258 }
259 Alg::fini(&state);
260 return pos;
261 }
262 ++pv;
263 pos += csum_block_size;
264 length -= csum_block_size;
265 }
266 Alg::fini(&state);
267 return -1; // no errors
268 }
269 };
270
271 #endif