diff options
Diffstat (limited to '')
-rw-r--r-- | src/common/Checksummer.h | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/src/common/Checksummer.h b/src/common/Checksummer.h new file mode 100644 index 000000000..a42f5b682 --- /dev/null +++ b/src/common/Checksummer.h @@ -0,0 +1,274 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_OS_BLUESTORE_CHECKSUMMER +#define CEPH_OS_BLUESTORE_CHECKSUMMER + +#include "include/buffer.h" +#include "include/byteorder.h" +#include "include/ceph_assert.h" + +#include "xxHash/xxhash.h" + +class Checksummer { +public: + enum CSumType { + 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 + CSUM_XXHASH32 = 2, + CSUM_XXHASH64 = 3, + CSUM_CRC32C = 4, + CSUM_CRC32C_16 = 5, // low 16 bits of crc32c + CSUM_CRC32C_8 = 6, // low 8 bits of crc32c + CSUM_MAX, + }; + static const char *get_csum_type_string(unsigned t) { + switch (t) { + case CSUM_NONE: return "none"; + case CSUM_XXHASH32: return "xxhash32"; + case CSUM_XXHASH64: return "xxhash64"; + case CSUM_CRC32C: return "crc32c"; + case CSUM_CRC32C_16: return "crc32c_16"; + case CSUM_CRC32C_8: return "crc32c_8"; + default: return "???"; + } + } + static int get_csum_string_type(const std::string &s) { + if (s == "none") + return CSUM_NONE; + if (s == "xxhash32") + return CSUM_XXHASH32; + if (s == "xxhash64") + return CSUM_XXHASH64; + if (s == "crc32c") + return CSUM_CRC32C; + if (s == "crc32c_16") + return CSUM_CRC32C_16; + if (s == "crc32c_8") + return CSUM_CRC32C_8; + return -EINVAL; + } + + static size_t get_csum_init_value_size(int csum_type) { + switch (csum_type) { + case CSUM_NONE: return 0; + case CSUM_XXHASH32: return sizeof(xxhash32::init_value_t); + case CSUM_XXHASH64: return sizeof(xxhash64::init_value_t); + case CSUM_CRC32C: return sizeof(crc32c::init_value_t); + case CSUM_CRC32C_16: return sizeof(crc32c_16::init_value_t); + case CSUM_CRC32C_8: return sizeof(crc32c_8::init_value_t); + default: return 0; + } + } + static size_t get_csum_value_size(int csum_type) { + switch (csum_type) { + case CSUM_NONE: return 0; + case CSUM_XXHASH32: return 4; + case CSUM_XXHASH64: return 8; + case CSUM_CRC32C: return 4; + case CSUM_CRC32C_16: return 2; + case CSUM_CRC32C_8: return 1; + default: return 0; + } + } + + struct crc32c { + typedef uint32_t init_value_t; + typedef ceph_le32 value_t; + + // we have no execution context/state. + typedef int state_t; + static void init(state_t *state) { + } + static void fini(state_t *state) { + } + + static init_value_t calc( + state_t state, + init_value_t init_value, + size_t len, + ceph::buffer::list::const_iterator& p + ) { + return p.crc32c(len, init_value); + } + }; + + struct crc32c_16 { + typedef uint32_t init_value_t; + typedef ceph_le16 value_t; + + // we have no execution context/state. + typedef int state_t; + static void init(state_t *state) { + } + static void fini(state_t *state) { + } + + static init_value_t calc( + state_t state, + init_value_t init_value, + size_t len, + ceph::buffer::list::const_iterator& p + ) { + return p.crc32c(len, init_value) & 0xffff; + } + }; + + struct crc32c_8 { + typedef uint32_t init_value_t; + typedef __u8 value_t; + + // we have no execution context/state. + typedef int state_t; + static void init(state_t *state) { + } + static void fini(state_t *state) { + } + + static init_value_t calc( + state_t state, + init_value_t init_value, + size_t len, + ceph::buffer::list::const_iterator& p + ) { + return p.crc32c(len, init_value) & 0xff; + } + }; + + struct xxhash32 { + typedef uint32_t init_value_t; + typedef ceph_le32 value_t; + + typedef XXH32_state_t *state_t; + static void init(state_t *s) { + *s = XXH32_createState(); + } + static void fini(state_t *s) { + XXH32_freeState(*s); + } + + static init_value_t calc( + state_t state, + init_value_t init_value, + size_t len, + ceph::buffer::list::const_iterator& p + ) { + XXH32_reset(state, init_value); + while (len > 0) { + const char *data; + size_t l = p.get_ptr_and_advance(len, &data); + XXH32_update(state, data, l); + len -= l; + } + return XXH32_digest(state); + } + }; + + struct xxhash64 { + typedef uint64_t init_value_t; + typedef ceph_le64 value_t; + + typedef XXH64_state_t *state_t; + static void init(state_t *s) { + *s = XXH64_createState(); + } + static void fini(state_t *s) { + XXH64_freeState(*s); + } + + static init_value_t calc( + state_t state, + init_value_t init_value, + size_t len, + ceph::buffer::list::const_iterator& p + ) { + XXH64_reset(state, init_value); + while (len > 0) { + const char *data; + size_t l = p.get_ptr_and_advance(len, &data); + XXH64_update(state, data, l); + len -= l; + } + return XXH64_digest(state); + } + }; + + template<class Alg> + static int calculate( + size_t csum_block_size, + size_t offset, + size_t length, + const ceph::buffer::list &bl, + ceph::buffer::ptr* csum_data + ) { + return calculate<Alg>(-1, csum_block_size, offset, length, bl, csum_data); + } + + template<class Alg> + static int calculate( + typename Alg::init_value_t init_value, + size_t csum_block_size, + size_t offset, + size_t length, + const ceph::buffer::list &bl, + ceph::buffer::ptr* csum_data) { + ceph_assert(length % csum_block_size == 0); + size_t blocks = length / csum_block_size; + ceph::buffer::list::const_iterator p = bl.begin(); + ceph_assert(bl.length() >= length); + + typename Alg::state_t state; + Alg::init(&state); + + ceph_assert(csum_data->length() >= (offset + length) / csum_block_size * + sizeof(typename Alg::value_t)); + + typename Alg::value_t *pv = + reinterpret_cast<typename Alg::value_t*>(csum_data->c_str()); + pv += offset / csum_block_size; + while (blocks--) { + *pv = Alg::calc(state, init_value, csum_block_size, p); + ++pv; + } + Alg::fini(&state); + return 0; + } + + template<class Alg> + static int verify( + size_t csum_block_size, + size_t offset, + size_t length, + const ceph::buffer::list &bl, + const ceph::buffer::ptr& csum_data, + uint64_t *bad_csum=0 + ) { + ceph_assert(length % csum_block_size == 0); + ceph::buffer::list::const_iterator p = bl.begin(); + ceph_assert(bl.length() >= length); + + typename Alg::state_t state; + Alg::init(&state); + + const typename Alg::value_t *pv = + reinterpret_cast<const typename Alg::value_t*>(csum_data.c_str()); + pv += offset / csum_block_size; + size_t pos = offset; + while (length > 0) { + typename Alg::init_value_t v = Alg::calc(state, -1, csum_block_size, p); + if (*pv != v) { + if (bad_csum) { + *bad_csum = v; + } + Alg::fini(&state); + return pos; + } + ++pv; + pos += csum_block_size; + length -= csum_block_size; + } + Alg::fini(&state); + return -1; // no errors + } +}; + +#endif |