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