Coverage Report

Created: 2024-07-27 06:53

/src/rocksdb/db/kv_checksum.h
Line
Count
Source (jump to first uncovered line)
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
31
#pragma once
32
33
#include <type_traits>
34
35
#include "db/dbformat.h"
36
#include "rocksdb/types.h"
37
#include "util/hash.h"
38
39
namespace ROCKSDB_NAMESPACE {
40
41
template <typename T>
42
class ProtectionInfo;
43
template <typename T>
44
class ProtectionInfoKVO;
45
template <typename T>
46
class ProtectionInfoKVOC;
47
template <typename T>
48
class ProtectionInfoKVOS;
49
template <typename T>
50
class ProtectionInfoKV;
51
52
// Aliases for 64-bit protection infos.
53
using ProtectionInfo64 = ProtectionInfo<uint64_t>;
54
using ProtectionInfoKVO64 = ProtectionInfoKVO<uint64_t>;
55
using ProtectionInfoKVOC64 = ProtectionInfoKVOC<uint64_t>;
56
using ProtectionInfoKVOS64 = ProtectionInfoKVOS<uint64_t>;
57
58
template <typename T>
59
class ProtectionInfo {
60
 public:
61
14.7k
  ProtectionInfo() = default;
62
63
  Status GetStatus() const;
64
  ProtectionInfoKVO<T> ProtectKVO(const Slice& key, const Slice& value,
65
                                  ValueType op_type) const;
66
  ProtectionInfoKVO<T> ProtectKVO(const SliceParts& key,
67
                                  const SliceParts& value,
68
                                  ValueType op_type) const;
69
  ProtectionInfoKV<T> ProtectKV(const Slice& key, const Slice& value) const;
70
71
 private:
72
  friend class ProtectionInfoKVO<T>;
73
  friend class ProtectionInfoKVOS<T>;
74
  friend class ProtectionInfoKVOC<T>;
75
  friend class ProtectionInfoKV<T>;
76
77
  // Each field is hashed with an independent value so we can catch fields being
78
  // swapped. Per the `NPHash64()` docs, using consecutive seeds is a pitfall,
79
  // and we should instead vary our seeds by a large odd number. This value by
80
  // which we increment (0xD28AAD72F49BD50B) was taken from
81
  // `head -c8 /dev/urandom | hexdump`, run repeatedly until it yielded an odd
82
  // number. The values are computed manually since the Windows C++ compiler
83
  // complains about the overflow when adding constants.
84
  static const uint64_t kSeedK = 0;
85
  static const uint64_t kSeedV = 0xD28AAD72F49BD50B;
86
  static const uint64_t kSeedO = 0xA5155AE5E937AA16;
87
  static const uint64_t kSeedS = 0x77A00858DDD37F21;
88
  static const uint64_t kSeedC = 0x4A2AB5CBD26F542C;
89
90
78.4k
  ProtectionInfo(T val) : val_(val) {
91
78.4k
    static_assert(sizeof(ProtectionInfo<T>) == sizeof(T), "");
92
78.4k
  }
93
94
80.7k
  T GetVal() const { return val_; }
95
2.28k
  void SetVal(T val) { val_ = val; }
96
97
0
  void Encode(uint8_t len, char* dst) const {
98
0
    assert(sizeof(val_) >= len);
99
0
    switch (len) {
100
0
      case 1:
101
0
        dst[0] = static_cast<uint8_t>(val_);
102
0
        break;
103
0
      case 2:
104
0
        EncodeFixed16(dst, static_cast<uint16_t>(val_));
105
0
        break;
106
0
      case 4:
107
0
        EncodeFixed32(dst, static_cast<uint32_t>(val_));
108
0
        break;
109
0
      case 8:
110
0
        EncodeFixed64(dst, static_cast<uint64_t>(val_));
111
0
        break;
112
0
      default:
113
0
        assert(false);
114
0
    }
115
0
  }
116
117
0
  bool Verify(uint8_t len, const char* checksum_ptr) const {
118
0
    assert(sizeof(val_) >= len);
119
0
    switch (len) {
120
0
      case 1:
121
0
        return static_cast<uint8_t>(checksum_ptr[0]) ==
122
0
               static_cast<uint8_t>(val_);
123
0
      case 2:
124
0
        return DecodeFixed16(checksum_ptr) == static_cast<uint16_t>(val_);
125
0
      case 4:
126
0
        return DecodeFixed32(checksum_ptr) == static_cast<uint32_t>(val_);
127
0
      case 8:
128
0
        return DecodeFixed64(checksum_ptr) == static_cast<uint64_t>(val_);
129
0
      default:
130
0
        assert(false);
131
0
        return false;
132
0
    }
133
0
  }
134
135
  T val_ = 0;
136
};
137
138
template <typename T>
139
class ProtectionInfoKVO {
140
 public:
141
0
  ProtectionInfoKVO() = default;
142
143
  ProtectionInfo<T> StripKVO(const Slice& key, const Slice& value,
144
                             ValueType op_type) const;
145
  ProtectionInfo<T> StripKVO(const SliceParts& key, const SliceParts& value,
146
                             ValueType op_type) const;
147
148
  ProtectionInfoKVOC<T> ProtectC(ColumnFamilyId column_family_id) const;
149
  ProtectionInfoKVOS<T> ProtectS(SequenceNumber sequence_number) const;
150
151
  void UpdateK(const Slice& old_key, const Slice& new_key);
152
  void UpdateK(const SliceParts& old_key, const SliceParts& new_key);
153
  void UpdateV(const Slice& old_value, const Slice& new_value);
154
  void UpdateV(const SliceParts& old_value, const SliceParts& new_value);
155
  void UpdateO(ValueType old_op_type, ValueType new_op_type);
156
157
  // Encode this protection info into `len` bytes and stores them in `dst`.
158
0
  void Encode(uint8_t len, char* dst) const { info_.Encode(len, dst); }
159
  // Verify this protection info against the protection info encoded by Encode()
160
  // at the first `len` bytes of `checksum_ptr`.
161
  // Returns true iff the verification is successful.
162
0
  bool Verify(uint8_t len, const char* checksum_ptr) const {
163
0
    return info_.Verify(len, checksum_ptr);
164
0
  }
165
166
 private:
167
  friend class ProtectionInfo<T>;
168
  friend class ProtectionInfoKVOS<T>;
169
  friend class ProtectionInfoKVOC<T>;
170
171
68.6k
  explicit ProtectionInfoKVO(T val) : info_(val) {
172
68.6k
    static_assert(sizeof(ProtectionInfoKVO<T>) == sizeof(T), "");
173
68.6k
  }
174
175
66.0k
  T GetVal() const { return info_.GetVal(); }
176
2.28k
  void SetVal(T val) { info_.SetVal(val); }
177
178
  ProtectionInfo<T> info_;
179
};
180
181
template <typename T>
182
class ProtectionInfoKVOC {
183
 public:
184
0
  ProtectionInfoKVOC() = default;
185
186
  ProtectionInfoKVO<T> StripC(ColumnFamilyId column_family_id) const;
187
188
  void UpdateK(const Slice& old_key, const Slice& new_key) {
189
    kvo_.UpdateK(old_key, new_key);
190
  }
191
0
  void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
192
0
    kvo_.UpdateK(old_key, new_key);
193
0
  }
194
  void UpdateV(const Slice& old_value, const Slice& new_value) {
195
    kvo_.UpdateV(old_value, new_value);
196
  }
197
0
  void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
198
0
    kvo_.UpdateV(old_value, new_value);
199
0
  }
200
  void UpdateO(ValueType old_op_type, ValueType new_op_type) {
201
    kvo_.UpdateO(old_op_type, new_op_type);
202
  }
203
  void UpdateC(ColumnFamilyId old_column_family_id,
204
               ColumnFamilyId new_column_family_id);
205
206
  void Encode(uint8_t len, char* dst) const { kvo_.Encode(len, dst); }
207
  bool Verify(uint8_t len, const char* checksum_ptr) const {
208
    return kvo_.Verify(len, checksum_ptr);
209
  }
210
211
 private:
212
  friend class ProtectionInfoKVO<T>;
213
214
14.7k
  explicit ProtectionInfoKVOC(T val) : kvo_(val) {
215
14.7k
    static_assert(sizeof(ProtectionInfoKVOC<T>) == sizeof(T), "");
216
14.7k
  }
217
218
14.7k
  T GetVal() const { return kvo_.GetVal(); }
219
  void SetVal(T val) { kvo_.SetVal(val); }
220
221
  ProtectionInfoKVO<T> kvo_;
222
};
223
224
template <typename T>
225
class ProtectionInfoKVOS {
226
 public:
227
  ProtectionInfoKVOS() = default;
228
229
  ProtectionInfoKVO<T> StripS(SequenceNumber sequence_number) const;
230
231
  void UpdateK(const Slice& old_key, const Slice& new_key) {
232
    kvo_.UpdateK(old_key, new_key);
233
  }
234
  void UpdateK(const SliceParts& old_key, const SliceParts& new_key) {
235
    kvo_.UpdateK(old_key, new_key);
236
  }
237
0
  void UpdateV(const Slice& old_value, const Slice& new_value) {
238
0
    kvo_.UpdateV(old_value, new_value);
239
0
  }
240
  void UpdateV(const SliceParts& old_value, const SliceParts& new_value) {
241
    kvo_.UpdateV(old_value, new_value);
242
  }
243
2.28k
  void UpdateO(ValueType old_op_type, ValueType new_op_type) {
244
2.28k
    kvo_.UpdateO(old_op_type, new_op_type);
245
2.28k
  }
246
  void UpdateS(SequenceNumber old_sequence_number,
247
               SequenceNumber new_sequence_number);
248
249
0
  void Encode(uint8_t len, char* dst) const { kvo_.Encode(len, dst); }
250
0
  bool Verify(uint8_t len, const char* checksum_ptr) const {
251
0
    return kvo_.Verify(len, checksum_ptr);
252
0
  }
253
254
 private:
255
  friend class ProtectionInfoKVO<T>;
256
257
14.7k
  explicit ProtectionInfoKVOS(T val) : kvo_(val) {
258
14.7k
    static_assert(sizeof(ProtectionInfoKVOS<T>) == sizeof(T), "");
259
14.7k
  }
260
261
9.82k
  T GetVal() const { return kvo_.GetVal(); }
262
0
  void SetVal(T val) { kvo_.SetVal(val); }
263
264
  ProtectionInfoKVO<T> kvo_;
265
};
266
267
template <typename T>
268
class ProtectionInfoKV {
269
 public:
270
  ProtectionInfoKV() = default;
271
272
0
  void Encode(uint8_t len, char* dst) const { info_.Encode(len, dst); }
273
0
  bool Verify(uint8_t len, const char* checksum_ptr) const {
274
0
    return info_.Verify(len, checksum_ptr);
275
0
  }
276
277
 private:
278
  friend class ProtectionInfo<T>;
279
280
0
  explicit ProtectionInfoKV(T val) : info_(val) {
281
0
    static_assert(sizeof(ProtectionInfoKV<T>) == sizeof(T));
282
0
  }
283
284
  ProtectionInfo<T> info_;
285
};
286
287
template <typename T>
288
9.82k
Status ProtectionInfo<T>::GetStatus() const {
289
9.82k
  if (val_ != 0) {
290
0
    return Status::Corruption("ProtectionInfo mismatch");
291
0
  }
292
9.82k
  return Status::OK();
293
9.82k
}
294
295
template <typename T>
296
ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const Slice& key,
297
                                                   const Slice& value,
298
14.7k
                                                   ValueType op_type) const {
299
14.7k
  T val = GetVal();
300
14.7k
  val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
301
14.7k
  val =
302
14.7k
      val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
303
14.7k
  val = val ^
304
14.7k
        static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
305
14.7k
                                sizeof(op_type), ProtectionInfo<T>::kSeedO));
306
14.7k
  return ProtectionInfoKVO<T>(val);
307
14.7k
}
308
309
template <typename T>
310
ProtectionInfoKVO<T> ProtectionInfo<T>::ProtectKVO(const SliceParts& key,
311
                                                   const SliceParts& value,
312
0
                                                   ValueType op_type) const {
313
0
  T val = GetVal();
314
0
  val = val ^
315
0
        static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
316
0
  val = val ^
317
0
        static_cast<T>(GetSlicePartsNPHash64(value, ProtectionInfo<T>::kSeedV));
318
0
  val = val ^
319
0
        static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
320
0
                                sizeof(op_type), ProtectionInfo<T>::kSeedO));
321
0
  return ProtectionInfoKVO<T>(val);
322
0
}
323
324
template <typename T>
325
ProtectionInfoKV<T> ProtectionInfo<T>::ProtectKV(const Slice& key,
326
0
                                                 const Slice& value) const {
327
0
  T val = GetVal();
328
0
  val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
329
0
  val =
330
0
      val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
331
0
  return ProtectionInfoKV<T>(val);
332
0
}
333
334
template <typename T>
335
void ProtectionInfoKVO<T>::UpdateK(const Slice& old_key, const Slice& new_key) {
336
  T val = GetVal();
337
  val = val ^
338
        static_cast<T>(GetSliceNPHash64(old_key, ProtectionInfo<T>::kSeedK));
339
  val = val ^
340
        static_cast<T>(GetSliceNPHash64(new_key, ProtectionInfo<T>::kSeedK));
341
  SetVal(val);
342
}
343
344
template <typename T>
345
void ProtectionInfoKVO<T>::UpdateK(const SliceParts& old_key,
346
0
                                   const SliceParts& new_key) {
347
0
  T val = GetVal();
348
0
  val = val ^ static_cast<T>(
349
0
                  GetSlicePartsNPHash64(old_key, ProtectionInfo<T>::kSeedK));
350
0
  val = val ^ static_cast<T>(
351
0
                  GetSlicePartsNPHash64(new_key, ProtectionInfo<T>::kSeedK));
352
0
  SetVal(val);
353
0
}
354
355
template <typename T>
356
void ProtectionInfoKVO<T>::UpdateV(const Slice& old_value,
357
0
                                   const Slice& new_value) {
358
0
  T val = GetVal();
359
0
  val = val ^
360
0
        static_cast<T>(GetSliceNPHash64(old_value, ProtectionInfo<T>::kSeedV));
361
0
  val = val ^
362
0
        static_cast<T>(GetSliceNPHash64(new_value, ProtectionInfo<T>::kSeedV));
363
0
  SetVal(val);
364
0
}
365
366
template <typename T>
367
void ProtectionInfoKVO<T>::UpdateV(const SliceParts& old_value,
368
0
                                   const SliceParts& new_value) {
369
0
  T val = GetVal();
370
0
  val = val ^ static_cast<T>(
371
0
                  GetSlicePartsNPHash64(old_value, ProtectionInfo<T>::kSeedV));
372
0
  val = val ^ static_cast<T>(
373
0
                  GetSlicePartsNPHash64(new_value, ProtectionInfo<T>::kSeedV));
374
0
  SetVal(val);
375
0
}
376
377
template <typename T>
378
void ProtectionInfoKVO<T>::UpdateO(ValueType old_op_type,
379
2.28k
                                   ValueType new_op_type) {
380
2.28k
  T val = GetVal();
381
2.28k
  val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&old_op_type),
382
2.28k
                                      sizeof(old_op_type),
383
2.28k
                                      ProtectionInfo<T>::kSeedO));
384
2.28k
  val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&new_op_type),
385
2.28k
                                      sizeof(new_op_type),
386
2.28k
                                      ProtectionInfo<T>::kSeedO));
387
2.28k
  SetVal(val);
388
2.28k
}
389
390
template <typename T>
391
ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const Slice& key,
392
                                                 const Slice& value,
393
9.82k
                                                 ValueType op_type) const {
394
9.82k
  T val = GetVal();
395
9.82k
  val = val ^ static_cast<T>(GetSliceNPHash64(key, ProtectionInfo<T>::kSeedK));
396
9.82k
  val =
397
9.82k
      val ^ static_cast<T>(GetSliceNPHash64(value, ProtectionInfo<T>::kSeedV));
398
9.82k
  val = val ^
399
9.82k
        static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
400
9.82k
                                sizeof(op_type), ProtectionInfo<T>::kSeedO));
401
9.82k
  return ProtectionInfo<T>(val);
402
9.82k
}
403
404
template <typename T>
405
ProtectionInfo<T> ProtectionInfoKVO<T>::StripKVO(const SliceParts& key,
406
                                                 const SliceParts& value,
407
                                                 ValueType op_type) const {
408
  T val = GetVal();
409
  val = val ^
410
        static_cast<T>(GetSlicePartsNPHash64(key, ProtectionInfo<T>::kSeedK));
411
  val = val ^
412
        static_cast<T>(GetSlicePartsNPHash64(value, ProtectionInfo<T>::kSeedV));
413
  val = val ^
414
        static_cast<T>(NPHash64(reinterpret_cast<char*>(&op_type),
415
                                sizeof(op_type), ProtectionInfo<T>::kSeedO));
416
  return ProtectionInfo<T>(val);
417
}
418
419
template <typename T>
420
ProtectionInfoKVOC<T> ProtectionInfoKVO<T>::ProtectC(
421
14.7k
    ColumnFamilyId column_family_id) const {
422
14.7k
  T val = GetVal();
423
14.7k
  val = val ^ static_cast<T>(NPHash64(
424
14.7k
                  reinterpret_cast<char*>(&column_family_id),
425
14.7k
                  sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
426
14.7k
  return ProtectionInfoKVOC<T>(val);
427
14.7k
}
428
429
template <typename T>
430
ProtectionInfoKVO<T> ProtectionInfoKVOC<T>::StripC(
431
14.7k
    ColumnFamilyId column_family_id) const {
432
14.7k
  T val = GetVal();
433
14.7k
  val = val ^ static_cast<T>(NPHash64(
434
14.7k
                  reinterpret_cast<char*>(&column_family_id),
435
14.7k
                  sizeof(column_family_id), ProtectionInfo<T>::kSeedC));
436
14.7k
  return ProtectionInfoKVO<T>(val);
437
14.7k
}
438
439
template <typename T>
440
void ProtectionInfoKVOC<T>::UpdateC(ColumnFamilyId old_column_family_id,
441
                                    ColumnFamilyId new_column_family_id) {
442
  T val = GetVal();
443
  val = val ^ static_cast<T>(NPHash64(
444
                  reinterpret_cast<char*>(&old_column_family_id),
445
                  sizeof(old_column_family_id), ProtectionInfo<T>::kSeedC));
446
  val = val ^ static_cast<T>(NPHash64(
447
                  reinterpret_cast<char*>(&new_column_family_id),
448
                  sizeof(new_column_family_id), ProtectionInfo<T>::kSeedC));
449
  SetVal(val);
450
}
451
452
template <typename T>
453
ProtectionInfoKVOS<T> ProtectionInfoKVO<T>::ProtectS(
454
14.7k
    SequenceNumber sequence_number) const {
455
14.7k
  T val = GetVal();
456
14.7k
  val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
457
14.7k
                                      sizeof(sequence_number),
458
14.7k
                                      ProtectionInfo<T>::kSeedS));
459
14.7k
  return ProtectionInfoKVOS<T>(val);
460
14.7k
}
461
462
template <typename T>
463
ProtectionInfoKVO<T> ProtectionInfoKVOS<T>::StripS(
464
9.82k
    SequenceNumber sequence_number) const {
465
9.82k
  T val = GetVal();
466
9.82k
  val = val ^ static_cast<T>(NPHash64(reinterpret_cast<char*>(&sequence_number),
467
9.82k
                                      sizeof(sequence_number),
468
9.82k
                                      ProtectionInfo<T>::kSeedS));
469
9.82k
  return ProtectionInfoKVO<T>(val);
470
9.82k
}
471
472
template <typename T>
473
void ProtectionInfoKVOS<T>::UpdateS(SequenceNumber old_sequence_number,
474
0
                                    SequenceNumber new_sequence_number) {
475
0
  T val = GetVal();
476
0
  val = val ^ static_cast<T>(NPHash64(
477
0
                  reinterpret_cast<char*>(&old_sequence_number),
478
0
                  sizeof(old_sequence_number), ProtectionInfo<T>::kSeedS));
479
0
  val = val ^ static_cast<T>(NPHash64(
480
0
                  reinterpret_cast<char*>(&new_sequence_number),
481
0
                  sizeof(new_sequence_number), ProtectionInfo<T>::kSeedS));
482
0
  SetVal(val);
483
0
}
484
}  // namespace ROCKSDB_NAMESPACE