| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- // Copyright (c) 2020-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- //
- // This file contains classes containing fields to protect individual entries.
- // The classes are named "ProtectionInfo<suffix>", where <suffix> indicates the
- // combination of fields that are covered. Each field has a single letter
- // abbreviation as follows.
- //
- // K = key
- // V = value
- // O = optype aka value type
- // S = seqno
- // C = CF ID
- //
- // Then, for example, a class that protects an entry consisting of key, value,
- // optype, and CF ID (i.e., a `WriteBatch` entry) would be named
- // `ProtectionInfoKVOC`.
- //
- // The `ProtectionInfo.*` classes are templated on the integer type used to hold
- // the XOR of hashes for each field. Only unsigned integer types are supported,
- // and the maximum supported integer width is 64 bits. When the integer type is
- // narrower than the hash values, we lop off the most significant bits to make
- // them fit.
- //
- // The `ProtectionInfo.*` classes are all intended to be non-persistent. We do
- // not currently make the byte order consistent for integer fields before
- // hashing them, so the resulting values are endianness-dependent.
- #pragma once
- #include <type_traits>
- #include "db/dbformat.h"
- #include "rocksdb/types.h"
- #include "util/hash.h"
- namespace ROCKSDB_NAMESPACE {
- template <typename T>
- class ProtectionInfo;
- template <typename T>
- class ProtectionInfoKVO;
- template <typename T>
- class ProtectionInfoKVOC;
- template <typename T>
- class ProtectionInfoKVOS;
- template <typename T>
- class ProtectionInfoKV;
- // Aliases for 64-bit protection infos.
- using ProtectionInfo64 = ProtectionInfo<uint64_t>;
- using ProtectionInfoKVO64 = ProtectionInfoKVO<uint64_t>;
- using ProtectionInfoKVOC64 = ProtectionInfoKVOC<uint64_t>;
- using ProtectionInfoKVOS64 = ProtectionInfoKVOS<uint64_t>;
- template <typename T>
- class ProtectionInfo {
- public:
- ProtectionInfo() = default;
- Status GetStatus() const;
- ProtectionInfoKVO<T> ProtectKVO(const Slice& key, const Slice& value,
- ValueType op_type) const;
- ProtectionInfoKVO<T> ProtectKVO(const SliceParts& key,
- const SliceParts& value,
- ValueType op_type) const;
- ProtectionInfoKV<T> ProtectKV(const Slice& key, const Slice& value) const;
- private:
- friend class ProtectionInfoKVO<T>;
- friend class ProtectionInfoKVOS<T>;
- friend class ProtectionInfoKVOC<T>;
- friend class ProtectionInfoKV<T>;
- // Each field is hashed with an independent value so we can catch fields being
- // swapped. Per the `NPHash64()` docs, using consecutive seeds is a pitfall,
- // and we should instead vary our seeds by a large odd number. This value by
- // which we increment (0xD28AAD72F49BD50B) was taken from
- // `head -c8 /dev/urandom | hexdump`, run repeatedly until it yielded an odd
- // number. The values are computed manually since the Windows C++ compiler
- // complains about the overflow when adding constants.
- static const uint64_t kSeedK = 0;
- static const uint64_t kSeedV = 0xD28AAD72F49BD50B;
- static const uint64_t kSeedO = 0xA5155AE5E937AA16;
- static const uint64_t kSeedS = 0x77A00858DDD37F21;
- static const uint64_t kSeedC = 0x4A2AB5CBD26F542C;
- ProtectionInfo(T val) : val_(val) {
- static_assert(sizeof(ProtectionInfo<T>) == sizeof(T), "");
- }
- T GetVal() const { return val_; }
- void SetVal(T val) { val_ = val; }
- void Encode(uint8_t len, char* dst) const {
- assert(sizeof(val_) >= len);
- switch (len) {
- case 1:
- dst[0] = static_cast<uint8_t>(val_);
- break;
- case 2:
- EncodeFixed16(dst, static_cast<uint16_t>(val_));
- break;
- case 4:
- EncodeFixed32(dst, static_cast<uint32_t>(val_));
- break;
- case 8:
- EncodeFixed64(dst, static_cast<uint64_t>(val_));
- break;
- default:
- assert(false);
- }
- }
- bool Verify(uint8_t len, const char* checksum_ptr) const {
- assert(sizeof(val_) >= len);
- switch (len) {
- case 1:
- return static_cast<uint8_t>(checksum_ptr[0]) ==
- static_cast<uint8_t>(val_);
- case 2:
- return DecodeFixed16(checksum_ptr) == static_cast<uint16_t>(val_);
- case 4:
- return DecodeFixed32(checksum_ptr) == static_cast<uint32_t>(val_);
- case 8:
- return DecodeFixed64(checksum_ptr) == static_cast<uint64_t>(val_);
- default:
- assert(false);
- return false;
- }
- }
- T val_ = 0;
- };
- template <typename T>
- class ProtectionInfoKVO {
- public:
- ProtectionInfoKVO() = default;
- ProtectionInfo<T> StripKVO(const Slice& key, const Slice& value,
- ValueType op_type) const;
- ProtectionInfo<T> StripKVO(const SliceParts& key, const SliceParts& value,
- ValueType op_type) const;
- ProtectionInfoKVOC<T> ProtectC(ColumnFamilyId column_family_id) const;
- ProtectionInfoKVOS<T> ProtectS(SequenceNumber sequence_number) const;
- void UpdateK(const Slice& old_key, const Slice& new_key);
- void UpdateK(const SliceParts& old_key, const SliceParts& new_key);
- void UpdateV(const Slice& old_value, const Slice& new_value);
- void UpdateV(const SliceParts& old_value, const SliceParts& new_value);
- void UpdateO(ValueType old_op_type, ValueType new_op_type);
- // Encode this protection info into `len` bytes and stores them in `dst`.
- void Encode(uint8_t len, char* dst) const { info_.Encode(len, dst); }
- // Verify this protection info against the protection info encoded by Encode()
- // at the first `len` bytes of `checksum_ptr`.
- // Returns true iff the verification is successful.
- bool Verify(uint8_t len, const char* checksum_ptr) const {
- return info_.Verify(len, checksum_ptr);
- }
- private:
- friend class ProtectionInfo<T>;
- friend class ProtectionInfoKVOS<T>;
- friend class ProtectionInfoKVOC<T>;
- explicit ProtectionInfoKVO(T val) : info_(val) {
- static_assert(sizeof(ProtectionInfoKVO<T>) == sizeof(T), "");
- }
- T GetVal() const { return info_.GetVal(); }
- void SetVal(T val) { info_.SetVal(val); }
- ProtectionInfo<T> info_;
- };
- template <typename T>
- class ProtectionInfoKVOC {
- public:
- ProtectionInfoKVOC() = default;
- ProtectionInfoKVO<T> StripC(ColumnFamilyId column_family_id) const;
- void UpdateK(const Slice& old_key, const Slice& new_key) {
- kvo_.UpdateK(old_key, new_key);
- }
- void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
- kvo_.UpdateK(old_key, new_key);
- }
- void UpdateV(const Slice& old_value, const Slice& new_value) {
- kvo_.UpdateV(old_value, new_value);
- }
- void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
- kvo_.UpdateV(old_value, new_value);
- }
- void UpdateO(ValueType old_op_type, ValueType new_op_type) {
- kvo_.UpdateO(old_op_type, new_op_type);
- }
- void UpdateC(ColumnFamilyId old_column_family_id,
- ColumnFamilyId new_column_family_id);
- void Encode(uint8_t len, char* dst) const { kvo_.Encode(len, dst); }
- bool Verify(uint8_t len, const char* checksum_ptr) const {
- return kvo_.Verify(len, checksum_ptr);
- }
- private:
- friend class ProtectionInfoKVO<T>;
- explicit ProtectionInfoKVOC(T val) : kvo_(val) {
- static_assert(sizeof(ProtectionInfoKVOC<T>) == sizeof(T), "");
- }
- T GetVal() const { return kvo_.GetVal(); }
- void SetVal(T val) { kvo_.SetVal(val); }
- ProtectionInfoKVO<T> kvo_;
- };
- template <typename T>
- class ProtectionInfoKVOS {
- public:
- ProtectionInfoKVOS() = default;
- ProtectionInfoKVO<T> StripS(SequenceNumber sequence_number) const;
- void UpdateK(const Slice& old_key, const Slice& new_key) {
- kvo_.UpdateK(old_key, new_key);
- }
- void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
- kvo_.UpdateK(old_key, new_key);
- }
- void UpdateV(const Slice& old_value, const Slice& new_value) {
- kvo_.UpdateV(old_value, new_value);
- }
- void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
- kvo_.UpdateV(old_value, new_value);
- }
- void UpdateO(ValueType old_op_type, ValueType new_op_type) {
- kvo_.UpdateO(old_op_type, new_op_type);
- }
- void UpdateS(SequenceNumber old_sequence_number,
- SequenceNumber new_sequence_number);
- void Encode(uint8_t len, char* dst) const { kvo_.Encode(len, dst); }
- bool Verify(uint8_t len, const char* checksum_ptr) const {
- return kvo_.Verify(len, checksum_ptr);
- }
- private:
- friend class ProtectionInfoKVO<T>;
- explicit ProtectionInfoKVOS(T val) : kvo_(val) {
- static_assert(sizeof(ProtectionInfoKVOS<T>) == sizeof(T), "");
- }
- T GetVal() const { return kvo_.GetVal(); }
- void SetVal(T val) { kvo_.SetVal(val); }
- ProtectionInfoKVO<T> kvo_;
- };
- template <typename T>
- class ProtectionInfoKV {
- public:
- ProtectionInfoKV() = default;
- void Encode(uint8_t len, char* dst) const { info_.Encode(len, dst); }
- bool Verify(uint8_t len, const char* checksum_ptr) const {
- return info_.Verify(len, checksum_ptr);
- }
- private:
- friend class ProtectionInfo<T>;
- explicit ProtectionInfoKV(T val) : info_(val) {
- static_assert(sizeof(ProtectionInfoKV<T>) == sizeof(T));
- }
- ProtectionInfo<T> info_;
- };
- template <typename T>
- Status ProtectionInfo<T>::GetStatus() const {
- if (val_ != 0) {
- return Status::Corruption("ProtectionInfo mismatch");
- }
- return Status::OK();
- }
- template <typename T>
- ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const Slice& key,
- const Slice& value,
- ValueType op_type) const {
- T val = GetVal();
- val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
- val =
- val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
- val = val ^
- static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
- sizeof(op_type), ProtectionInfo<T>::kSeedO));
- return ProtectionInfoKVO<T>(val);
- }
- template <typename T>
- ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const SliceParts& key,
- const SliceParts& value,
- ValueType op_type) const {
- T val = GetVal();
- val = val ^
- static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
- val = val ^
- static_cast<T>(GetSlicePartsNPHash64(value, ProtectionInfo<T>::kSeedV));
- val = val ^
- static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
- sizeof(op_type), ProtectionInfo<T>::kSeedO));
- return ProtectionInfoKVO<T>(val);
- }
- template <typename T>
- ProtectionInfoKV<T> ProtectionInfo<T>::ProtectKV(const Slice& key,
- const Slice& value) const {
- T val = GetVal();
- val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
- val =
- val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
- return ProtectionInfoKV<T>(val);
- }
- template <typename T>
- void ProtectionInfoKVO<T>::UpdateK(const Slice& old_key, const Slice& new_key) {
- T val = GetVal();
- val = val ^
- static_cast<T>(GetSliceNPHash64(old_key, ProtectionInfo<T>::kSeedK));
- val = val ^
- static_cast<T>(GetSliceNPHash64(new_key, ProtectionInfo<T>::kSeedK));
- SetVal(val);
- }
- template <typename T>
- void ProtectionInfoKVO<T>::UpdateK(const SliceParts& old_key,
- const SliceParts& new_key) {
- T val = GetVal();
- val = val ^ static_cast<T>(
- GetSlicePartsNPHash64(old_key, ProtectionInfo<T>::kSeedK));
- val = val ^ static_cast<T>(
- GetSlicePartsNPHash64(new_key, ProtectionInfo<T>::kSeedK));
- SetVal(val);
- }
- template <typename T>
- void ProtectionInfoKVO<T>::UpdateV(const Slice& old_value,
- const Slice& new_value) {
- T val = GetVal();
- val = val ^
- static_cast<T>(GetSliceNPHash64(old_value, ProtectionInfo<T>::kSeedV));
- val = val ^
- static_cast<T>(GetSliceNPHash64(new_value, ProtectionInfo<T>::kSeedV));
- SetVal(val);
- }
- template <typename T>
- void ProtectionInfoKVO<T>::UpdateV(const SliceParts& old_value,
- const SliceParts& new_value) {
- T val = GetVal();
- val = val ^ static_cast<T>(
- GetSlicePartsNPHash64(old_value, ProtectionInfo<T>::kSeedV));
- val = val ^ static_cast<T>(
- GetSlicePartsNPHash64(new_value, ProtectionInfo<T>::kSeedV));
- SetVal(val);
- }
- template <typename T>
- void ProtectionInfoKVO<T>::UpdateO(ValueType old_op_type,
- ValueType new_op_type) {
- T val = GetVal();
- val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&old_op_type),
- sizeof(old_op_type),
- ProtectionInfo<T>::kSeedO));
- val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&new_op_type),
- sizeof(new_op_type),
- ProtectionInfo<T>::kSeedO));
- SetVal(val);
- }
- template <typename T>
- ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const Slice& key,
- const Slice& value,
- ValueType op_type) const {
- T val = GetVal();
- val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
- val =
- val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
- val = val ^
- static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
- sizeof(op_type), ProtectionInfo<T>::kSeedO));
- return ProtectionInfo<T>(val);
- }
- template <typename T>
- ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const SliceParts& key,
- const SliceParts& value,
- ValueType op_type) const {
- T val = GetVal();
- val = val ^
- static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
- val = val ^
- static_cast<T>(GetSlicePartsNPHash64(value, ProtectionInfo<T>::kSeedV));
- val = val ^
- static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
- sizeof(op_type), ProtectionInfo<T>::kSeedO));
- return ProtectionInfo<T>(val);
- }
- template <typename T>
- ProtectionInfoKVOC<T> ProtectionInfoKVO<T>::ProtectC(
- ColumnFamilyId column_family_id) const {
- T val = GetVal();
- val = val ^ static_cast<T>(NPHash64(
- reinterpret_cast<char*>(&column_family_id),
- sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
- return ProtectionInfoKVOC<T>(val);
- }
- template <typename T>
- ProtectionInfoKVO<T> ProtectionInfoKVOC<T>::StripC(
- ColumnFamilyId column_family_id) const {
- T val = GetVal();
- val = val ^ static_cast<T>(NPHash64(
- reinterpret_cast<char*>(&column_family_id),
- sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
- return ProtectionInfoKVO<T>(val);
- }
- template <typename T>
- void ProtectionInfoKVOC<T>::UpdateC(ColumnFamilyId old_column_family_id,
- ColumnFamilyId new_column_family_id) {
- T val = GetVal();
- val = val ^ static_cast<T>(NPHash64(
- reinterpret_cast<char*>(&old_column_family_id),
- sizeof(old_column_family_id), ProtectionInfo<T>::kSeedC));
- val = val ^ static_cast<T>(NPHash64(
- reinterpret_cast<char*>(&new_column_family_id),
- sizeof(new_column_family_id), ProtectionInfo<T>::kSeedC));
- SetVal(val);
- }
- template <typename T>
- ProtectionInfoKVOS<T> ProtectionInfoKVO<T>::ProtectS(
- SequenceNumber sequence_number) const {
- T val = GetVal();
- val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
- sizeof(sequence_number),
- ProtectionInfo<T>::kSeedS));
- return ProtectionInfoKVOS<T>(val);
- }
- template <typename T>
- ProtectionInfoKVO<T> ProtectionInfoKVOS<T>::StripS(
- SequenceNumber sequence_number) const {
- T val = GetVal();
- val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
- sizeof(sequence_number),
- ProtectionInfo<T>::kSeedS));
- return ProtectionInfoKVO<T>(val);
- }
- template <typename T>
- void ProtectionInfoKVOS<T>::UpdateS(SequenceNumber old_sequence_number,
- SequenceNumber new_sequence_number) {
- T val = GetVal();
- val = val ^ static_cast<T>(NPHash64(
- reinterpret_cast<char*>(&old_sequence_number),
- sizeof(old_sequence_number), ProtectionInfo<T>::kSeedS));
- val = val ^ static_cast<T>(NPHash64(
- reinterpret_cast<char*>(&new_sequence_number),
- sizeof(new_sequence_number), ProtectionInfo<T>::kSeedS));
- SetVal(val);
- }
- } // namespace ROCKSDB_NAMESPACE
|