summaryrefslogtreecommitdiffstats
path: root/src/rocksdb/db/kv_checksum.h
blob: bce507fcf9830065fd2932649cc291ef8f92706e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
//  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;

// 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;

  T GetVal() const { return val_; }

 private:
  friend class ProtectionInfoKVO<T>;
  friend class ProtectionInfoKVOS<T>;
  friend class ProtectionInfoKVOC<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), "");
  }

  void SetVal(T val) { val_ = val; }

  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);

  T GetVal() const { return info_.GetVal(); }

 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), "");
  }

  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);

  T GetVal() const { return kvo_.GetVal(); }

 private:
  friend class ProtectionInfoKVO<T>;

  explicit ProtectionInfoKVOC(T val) : kvo_(val) {
    static_assert(sizeof(ProtectionInfoKVOC<T>) == sizeof(T), "");
  }

  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);

  T GetVal() const { return kvo_.GetVal(); }

 private:
  friend class ProtectionInfoKVO<T>;

  explicit ProtectionInfoKVOS(T val) : kvo_(val) {
    static_assert(sizeof(ProtectionInfoKVOS<T>) == sizeof(T), "");
  }

  void SetVal(T val) { kvo_.SetVal(val); }

  ProtectionInfoKVO<T> kvo_;
};

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>
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