initial code repo
[stor4nfv.git] / src / ceph / src / common / Checksummer.h
diff --git a/src/ceph/src/common/Checksummer.h b/src/ceph/src/common/Checksummer.h
new file mode 100644 (file)
index 0000000..c303ae2
--- /dev/null
@@ -0,0 +1,270 @@
+// -*- 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 "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 __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 value_t calc(
+      state_t state,
+      init_value_t init_value,
+      size_t len,
+      bufferlist::const_iterator& p
+      ) {
+      return p.crc32c(len, init_value);
+    }
+  };
+
+  struct crc32c_16 {
+    typedef uint32_t init_value_t;
+    typedef __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 value_t calc(
+      state_t state,
+      init_value_t init_value,
+      size_t len,
+      bufferlist::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 value_t calc(
+      state_t state,
+      init_value_t init_value,
+      size_t len,
+      bufferlist::const_iterator& p
+      ) {
+      return p.crc32c(len, init_value) & 0xff;
+    }
+  };
+
+  struct xxhash32 {
+    typedef uint32_t init_value_t;
+    typedef __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 value_t calc(
+      state_t state,
+      init_value_t init_value,
+      size_t len,
+      bufferlist::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 __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 value_t calc(
+      state_t state,
+      init_value_t init_value,
+      size_t len,
+      bufferlist::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 bufferlist &bl,
+    bufferptr* 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 bufferlist &bl,
+      bufferptr* csum_data) {
+    assert(length % csum_block_size == 0);
+    size_t blocks = length / csum_block_size;
+    bufferlist::const_iterator p = bl.begin();
+    assert(bl.length() >= length);
+
+    typename Alg::state_t state;
+    Alg::init(&state);
+
+    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 bufferlist &bl,
+    const bufferptr& csum_data,
+    uint64_t *bad_csum=0
+    ) {
+    assert(length % csum_block_size == 0);
+    bufferlist::const_iterator p = bl.begin();
+    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::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