kv_checksum.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. // Copyright (c) 2020-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // This file contains classes containing fields to protect individual entries.
  7. // The classes are named "ProtectionInfo<suffix>", where <suffix> indicates the
  8. // combination of fields that are covered. Each field has a single letter
  9. // abbreviation as follows.
  10. //
  11. // K = key
  12. // V = value
  13. // O = optype aka value type
  14. // S = seqno
  15. // C = CF ID
  16. //
  17. // Then, for example, a class that protects an entry consisting of key, value,
  18. // optype, and CF ID (i.e., a `WriteBatch` entry) would be named
  19. // `ProtectionInfoKVOC`.
  20. //
  21. // The `ProtectionInfo.*` classes are templated on the integer type used to hold
  22. // the XOR of hashes for each field. Only unsigned integer types are supported,
  23. // and the maximum supported integer width is 64 bits. When the integer type is
  24. // narrower than the hash values, we lop off the most significant bits to make
  25. // them fit.
  26. //
  27. // The `ProtectionInfo.*` classes are all intended to be non-persistent. We do
  28. // not currently make the byte order consistent for integer fields before
  29. // hashing them, so the resulting values are endianness-dependent.
  30. #pragma once
  31. #include <type_traits>
  32. #include "db/dbformat.h"
  33. #include "rocksdb/types.h"
  34. #include "util/hash.h"
  35. namespace ROCKSDB_NAMESPACE {
  36. template <typename T>
  37. class ProtectionInfo;
  38. template <typename T>
  39. class ProtectionInfoKVO;
  40. template <typename T>
  41. class ProtectionInfoKVOC;
  42. template <typename T>
  43. class ProtectionInfoKVOS;
  44. template <typename T>
  45. class ProtectionInfoKV;
  46. // Aliases for 64-bit protection infos.
  47. using ProtectionInfo64 = ProtectionInfo<uint64_t>;
  48. using ProtectionInfoKVO64 = ProtectionInfoKVO<uint64_t>;
  49. using ProtectionInfoKVOC64 = ProtectionInfoKVOC<uint64_t>;
  50. using ProtectionInfoKVOS64 = ProtectionInfoKVOS<uint64_t>;
  51. template <typename T>
  52. class ProtectionInfo {
  53. public:
  54. ProtectionInfo() = default;
  55. Status GetStatus() const;
  56. ProtectionInfoKVO<T> ProtectKVO(const Slice& key, const Slice& value,
  57. ValueType op_type) const;
  58. ProtectionInfoKVO<T> ProtectKVO(const SliceParts& key,
  59. const SliceParts& value,
  60. ValueType op_type) const;
  61. ProtectionInfoKV<T> ProtectKV(const Slice& key, const Slice& value) const;
  62. private:
  63. friend class ProtectionInfoKVO<T>;
  64. friend class ProtectionInfoKVOS<T>;
  65. friend class ProtectionInfoKVOC<T>;
  66. friend class ProtectionInfoKV<T>;
  67. // Each field is hashed with an independent value so we can catch fields being
  68. // swapped. Per the `NPHash64()` docs, using consecutive seeds is a pitfall,
  69. // and we should instead vary our seeds by a large odd number. This value by
  70. // which we increment (0xD28AAD72F49BD50B) was taken from
  71. // `head -c8 /dev/urandom | hexdump`, run repeatedly until it yielded an odd
  72. // number. The values are computed manually since the Windows C++ compiler
  73. // complains about the overflow when adding constants.
  74. static const uint64_t kSeedK = 0;
  75. static const uint64_t kSeedV = 0xD28AAD72F49BD50B;
  76. static const uint64_t kSeedO = 0xA5155AE5E937AA16;
  77. static const uint64_t kSeedS = 0x77A00858DDD37F21;
  78. static const uint64_t kSeedC = 0x4A2AB5CBD26F542C;
  79. ProtectionInfo(T val) : val_(val) {
  80. static_assert(sizeof(ProtectionInfo<T>) == sizeof(T), "");
  81. }
  82. T GetVal() const { return val_; }
  83. void SetVal(T val) { val_ = val; }
  84. void Encode(uint8_t len, char* dst) const {
  85. assert(sizeof(val_) >= len);
  86. switch (len) {
  87. case 1:
  88. dst[0] = static_cast<uint8_t>(val_);
  89. break;
  90. case 2:
  91. EncodeFixed16(dst, static_cast<uint16_t>(val_));
  92. break;
  93. case 4:
  94. EncodeFixed32(dst, static_cast<uint32_t>(val_));
  95. break;
  96. case 8:
  97. EncodeFixed64(dst, static_cast<uint64_t>(val_));
  98. break;
  99. default:
  100. assert(false);
  101. }
  102. }
  103. bool Verify(uint8_t len, const char* checksum_ptr) const {
  104. assert(sizeof(val_) >= len);
  105. switch (len) {
  106. case 1:
  107. return static_cast<uint8_t>(checksum_ptr[0]) ==
  108. static_cast<uint8_t>(val_);
  109. case 2:
  110. return DecodeFixed16(checksum_ptr) == static_cast<uint16_t>(val_);
  111. case 4:
  112. return DecodeFixed32(checksum_ptr) == static_cast<uint32_t>(val_);
  113. case 8:
  114. return DecodeFixed64(checksum_ptr) == static_cast<uint64_t>(val_);
  115. default:
  116. assert(false);
  117. return false;
  118. }
  119. }
  120. T val_ = 0;
  121. };
  122. template <typename T>
  123. class ProtectionInfoKVO {
  124. public:
  125. ProtectionInfoKVO() = default;
  126. ProtectionInfo<T> StripKVO(const Slice& key, const Slice& value,
  127. ValueType op_type) const;
  128. ProtectionInfo<T> StripKVO(const SliceParts& key, const SliceParts& value,
  129. ValueType op_type) const;
  130. ProtectionInfoKVOC<T> ProtectC(ColumnFamilyId column_family_id) const;
  131. ProtectionInfoKVOS<T> ProtectS(SequenceNumber sequence_number) const;
  132. void UpdateK(const Slice& old_key, const Slice& new_key);
  133. void UpdateK(const SliceParts& old_key, const SliceParts& new_key);
  134. void UpdateV(const Slice& old_value, const Slice& new_value);
  135. void UpdateV(const SliceParts& old_value, const SliceParts& new_value);
  136. void UpdateO(ValueType old_op_type, ValueType new_op_type);
  137. // Encode this protection info into `len` bytes and stores them in `dst`.
  138. void Encode(uint8_t len, char* dst) const { info_.Encode(len, dst); }
  139. // Verify this protection info against the protection info encoded by Encode()
  140. // at the first `len` bytes of `checksum_ptr`.
  141. // Returns true iff the verification is successful.
  142. bool Verify(uint8_t len, const char* checksum_ptr) const {
  143. return info_.Verify(len, checksum_ptr);
  144. }
  145. private:
  146. friend class ProtectionInfo<T>;
  147. friend class ProtectionInfoKVOS<T>;
  148. friend class ProtectionInfoKVOC<T>;
  149. explicit ProtectionInfoKVO(T val) : info_(val) {
  150. static_assert(sizeof(ProtectionInfoKVO<T>) == sizeof(T), "");
  151. }
  152. T GetVal() const { return info_.GetVal(); }
  153. void SetVal(T val) { info_.SetVal(val); }
  154. ProtectionInfo<T> info_;
  155. };
  156. template <typename T>
  157. class ProtectionInfoKVOC {
  158. public:
  159. ProtectionInfoKVOC() = default;
  160. ProtectionInfoKVO<T> StripC(ColumnFamilyId column_family_id) const;
  161. void UpdateK(const Slice& old_key, const Slice& new_key) {
  162. kvo_.UpdateK(old_key, new_key);
  163. }
  164. void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
  165. kvo_.UpdateK(old_key, new_key);
  166. }
  167. void UpdateV(const Slice& old_value, const Slice& new_value) {
  168. kvo_.UpdateV(old_value, new_value);
  169. }
  170. void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
  171. kvo_.UpdateV(old_value, new_value);
  172. }
  173. void UpdateO(ValueType old_op_type, ValueType new_op_type) {
  174. kvo_.UpdateO(old_op_type, new_op_type);
  175. }
  176. void UpdateC(ColumnFamilyId old_column_family_id,
  177. ColumnFamilyId new_column_family_id);
  178. void Encode(uint8_t len, char* dst) const { kvo_.Encode(len, dst); }
  179. bool Verify(uint8_t len, const char* checksum_ptr) const {
  180. return kvo_.Verify(len, checksum_ptr);
  181. }
  182. private:
  183. friend class ProtectionInfoKVO<T>;
  184. explicit ProtectionInfoKVOC(T val) : kvo_(val) {
  185. static_assert(sizeof(ProtectionInfoKVOC<T>) == sizeof(T), "");
  186. }
  187. T GetVal() const { return kvo_.GetVal(); }
  188. void SetVal(T val) { kvo_.SetVal(val); }
  189. ProtectionInfoKVO<T> kvo_;
  190. };
  191. template <typename T>
  192. class ProtectionInfoKVOS {
  193. public:
  194. ProtectionInfoKVOS() = default;
  195. ProtectionInfoKVO<T> StripS(SequenceNumber sequence_number) const;
  196. void UpdateK(const Slice& old_key, const Slice& new_key) {
  197. kvo_.UpdateK(old_key, new_key);
  198. }
  199. void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
  200. kvo_.UpdateK(old_key, new_key);
  201. }
  202. void UpdateV(const Slice& old_value, const Slice& new_value) {
  203. kvo_.UpdateV(old_value, new_value);
  204. }
  205. void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
  206. kvo_.UpdateV(old_value, new_value);
  207. }
  208. void UpdateO(ValueType old_op_type, ValueType new_op_type) {
  209. kvo_.UpdateO(old_op_type, new_op_type);
  210. }
  211. void UpdateS(SequenceNumber old_sequence_number,
  212. SequenceNumber new_sequence_number);
  213. void Encode(uint8_t len, char* dst) const { kvo_.Encode(len, dst); }
  214. bool Verify(uint8_t len, const char* checksum_ptr) const {
  215. return kvo_.Verify(len, checksum_ptr);
  216. }
  217. private:
  218. friend class ProtectionInfoKVO<T>;
  219. explicit ProtectionInfoKVOS(T val) : kvo_(val) {
  220. static_assert(sizeof(ProtectionInfoKVOS<T>) == sizeof(T), "");
  221. }
  222. T GetVal() const { return kvo_.GetVal(); }
  223. void SetVal(T val) { kvo_.SetVal(val); }
  224. ProtectionInfoKVO<T> kvo_;
  225. };
  226. template <typename T>
  227. class ProtectionInfoKV {
  228. public:
  229. ProtectionInfoKV() = default;
  230. void Encode(uint8_t len, char* dst) const { info_.Encode(len, dst); }
  231. bool Verify(uint8_t len, const char* checksum_ptr) const {
  232. return info_.Verify(len, checksum_ptr);
  233. }
  234. private:
  235. friend class ProtectionInfo<T>;
  236. explicit ProtectionInfoKV(T val) : info_(val) {
  237. static_assert(sizeof(ProtectionInfoKV<T>) == sizeof(T));
  238. }
  239. ProtectionInfo<T> info_;
  240. };
  241. template <typename T>
  242. Status ProtectionInfo<T>::GetStatus() const {
  243. if (val_ != 0) {
  244. return Status::Corruption("ProtectionInfo mismatch");
  245. }
  246. return Status::OK();
  247. }
  248. template <typename T>
  249. ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const Slice& key,
  250. const Slice& value,
  251. ValueType op_type) const {
  252. T val = GetVal();
  253. val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
  254. val =
  255. val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
  256. val = val ^
  257. static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
  258. sizeof(op_type), ProtectionInfo<T>::kSeedO));
  259. return ProtectionInfoKVO<T>(val);
  260. }
  261. template <typename T>
  262. ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const SliceParts& key,
  263. const SliceParts& value,
  264. ValueType op_type) const {
  265. T val = GetVal();
  266. val = val ^
  267. static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
  268. val = val ^
  269. static_cast<T>(GetSlicePartsNPHash64(value, ProtectionInfo<T>::kSeedV));
  270. val = val ^
  271. static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
  272. sizeof(op_type), ProtectionInfo<T>::kSeedO));
  273. return ProtectionInfoKVO<T>(val);
  274. }
  275. template <typename T>
  276. ProtectionInfoKV<T> ProtectionInfo<T>::ProtectKV(const Slice& key,
  277. const Slice& value) const {
  278. T val = GetVal();
  279. val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
  280. val =
  281. val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
  282. return ProtectionInfoKV<T>(val);
  283. }
  284. template <typename T>
  285. void ProtectionInfoKVO<T>::UpdateK(const Slice& old_key, const Slice& new_key) {
  286. T val = GetVal();
  287. val = val ^
  288. static_cast<T>(GetSliceNPHash64(old_key, ProtectionInfo<T>::kSeedK));
  289. val = val ^
  290. static_cast<T>(GetSliceNPHash64(new_key, ProtectionInfo<T>::kSeedK));
  291. SetVal(val);
  292. }
  293. template <typename T>
  294. void ProtectionInfoKVO<T>::UpdateK(const SliceParts& old_key,
  295. const SliceParts& new_key) {
  296. T val = GetVal();
  297. val = val ^ static_cast<T>(
  298. GetSlicePartsNPHash64(old_key, ProtectionInfo<T>::kSeedK));
  299. val = val ^ static_cast<T>(
  300. GetSlicePartsNPHash64(new_key, ProtectionInfo<T>::kSeedK));
  301. SetVal(val);
  302. }
  303. template <typename T>
  304. void ProtectionInfoKVO<T>::UpdateV(const Slice& old_value,
  305. const Slice& new_value) {
  306. T val = GetVal();
  307. val = val ^
  308. static_cast<T>(GetSliceNPHash64(old_value, ProtectionInfo<T>::kSeedV));
  309. val = val ^
  310. static_cast<T>(GetSliceNPHash64(new_value, ProtectionInfo<T>::kSeedV));
  311. SetVal(val);
  312. }
  313. template <typename T>
  314. void ProtectionInfoKVO<T>::UpdateV(const SliceParts& old_value,
  315. const SliceParts& new_value) {
  316. T val = GetVal();
  317. val = val ^ static_cast<T>(
  318. GetSlicePartsNPHash64(old_value, ProtectionInfo<T>::kSeedV));
  319. val = val ^ static_cast<T>(
  320. GetSlicePartsNPHash64(new_value, ProtectionInfo<T>::kSeedV));
  321. SetVal(val);
  322. }
  323. template <typename T>
  324. void ProtectionInfoKVO<T>::UpdateO(ValueType old_op_type,
  325. ValueType new_op_type) {
  326. T val = GetVal();
  327. val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&old_op_type),
  328. sizeof(old_op_type),
  329. ProtectionInfo<T>::kSeedO));
  330. val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&new_op_type),
  331. sizeof(new_op_type),
  332. ProtectionInfo<T>::kSeedO));
  333. SetVal(val);
  334. }
  335. template <typename T>
  336. ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const Slice& key,
  337. const Slice& value,
  338. ValueType op_type) const {
  339. T val = GetVal();
  340. val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
  341. val =
  342. val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
  343. val = val ^
  344. static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
  345. sizeof(op_type), ProtectionInfo<T>::kSeedO));
  346. return ProtectionInfo<T>(val);
  347. }
  348. template <typename T>
  349. ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const SliceParts& key,
  350. const SliceParts& value,
  351. ValueType op_type) const {
  352. T val = GetVal();
  353. val = val ^
  354. static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
  355. val = val ^
  356. static_cast<T>(GetSlicePartsNPHash64(value, ProtectionInfo<T>::kSeedV));
  357. val = val ^
  358. static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
  359. sizeof(op_type), ProtectionInfo<T>::kSeedO));
  360. return ProtectionInfo<T>(val);
  361. }
  362. template <typename T>
  363. ProtectionInfoKVOC<T> ProtectionInfoKVO<T>::ProtectC(
  364. ColumnFamilyId column_family_id) const {
  365. T val = GetVal();
  366. val = val ^ static_cast<T>(NPHash64(
  367. reinterpret_cast<char*>(&column_family_id),
  368. sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
  369. return ProtectionInfoKVOC<T>(val);
  370. }
  371. template <typename T>
  372. ProtectionInfoKVO<T> ProtectionInfoKVOC<T>::StripC(
  373. ColumnFamilyId column_family_id) const {
  374. T val = GetVal();
  375. val = val ^ static_cast<T>(NPHash64(
  376. reinterpret_cast<char*>(&column_family_id),
  377. sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
  378. return ProtectionInfoKVO<T>(val);
  379. }
  380. template <typename T>
  381. void ProtectionInfoKVOC<T>::UpdateC(ColumnFamilyId old_column_family_id,
  382. ColumnFamilyId new_column_family_id) {
  383. T val = GetVal();
  384. val = val ^ static_cast<T>(NPHash64(
  385. reinterpret_cast<char*>(&old_column_family_id),
  386. sizeof(old_column_family_id), ProtectionInfo<T>::kSeedC));
  387. val = val ^ static_cast<T>(NPHash64(
  388. reinterpret_cast<char*>(&new_column_family_id),
  389. sizeof(new_column_family_id), ProtectionInfo<T>::kSeedC));
  390. SetVal(val);
  391. }
  392. template <typename T>
  393. ProtectionInfoKVOS<T> ProtectionInfoKVO<T>::ProtectS(
  394. SequenceNumber sequence_number) const {
  395. T val = GetVal();
  396. val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
  397. sizeof(sequence_number),
  398. ProtectionInfo<T>::kSeedS));
  399. return ProtectionInfoKVOS<T>(val);
  400. }
  401. template <typename T>
  402. ProtectionInfoKVO<T> ProtectionInfoKVOS<T>::StripS(
  403. SequenceNumber sequence_number) const {
  404. T val = GetVal();
  405. val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
  406. sizeof(sequence_number),
  407. ProtectionInfo<T>::kSeedS));
  408. return ProtectionInfoKVO<T>(val);
  409. }
  410. template <typename T>
  411. void ProtectionInfoKVOS<T>::UpdateS(SequenceNumber old_sequence_number,
  412. SequenceNumber new_sequence_number) {
  413. T val = GetVal();
  414. val = val ^ static_cast<T>(NPHash64(
  415. reinterpret_cast<char*>(&old_sequence_number),
  416. sizeof(old_sequence_number), ProtectionInfo<T>::kSeedS));
  417. val = val ^ static_cast<T>(NPHash64(
  418. reinterpret_cast<char*>(&new_sequence_number),
  419. sizeof(new_sequence_number), ProtectionInfo<T>::kSeedS));
  420. SetVal(val);
  421. }
  422. } // namespace ROCKSDB_NAMESPACE