Coverage Report

Created: 2025-07-23 07:17

/src/rocksdb/db/blob/blob_log_format.cc
Line
Count
Source (jump to first uncovered line)
1
//  Copyright (c) 2011-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
7
#include "db/blob/blob_log_format.h"
8
9
#include "util/coding.h"
10
#include "util/crc32c.h"
11
12
namespace ROCKSDB_NAMESPACE {
13
14
0
void BlobLogHeader::EncodeTo(std::string* dst) {
15
0
  assert(dst != nullptr);
16
0
  dst->clear();
17
0
  dst->reserve(BlobLogHeader::kSize);
18
0
  PutFixed32(dst, kMagicNumber);
19
0
  PutFixed32(dst, version);
20
0
  PutFixed32(dst, column_family_id);
21
0
  unsigned char flags = (has_ttl ? 1 : 0);
22
0
  dst->push_back(flags);
23
0
  dst->push_back(compression);
24
0
  PutFixed64(dst, expiration_range.first);
25
0
  PutFixed64(dst, expiration_range.second);
26
0
}
27
28
0
Status BlobLogHeader::DecodeFrom(Slice src) {
29
0
  const char* kErrorMessage = "Error while decoding blob log header";
30
0
  if (src.size() != BlobLogHeader::kSize) {
31
0
    return Status::Corruption(kErrorMessage,
32
0
                              "Unexpected blob file header size");
33
0
  }
34
0
  uint32_t magic_number;
35
0
  unsigned char flags;
36
0
  if (!GetFixed32(&src, &magic_number) || !GetFixed32(&src, &version) ||
37
0
      !GetFixed32(&src, &column_family_id)) {
38
0
    return Status::Corruption(
39
0
        kErrorMessage,
40
0
        "Error decoding magic number, version and column family id");
41
0
  }
42
0
  if (magic_number != kMagicNumber) {
43
0
    return Status::Corruption(kErrorMessage, "Magic number mismatch");
44
0
  }
45
0
  if (version != kVersion1) {
46
0
    return Status::Corruption(kErrorMessage, "Unknown header version");
47
0
  }
48
0
  flags = src.data()[0];
49
0
  compression = static_cast<CompressionType>(src.data()[1]);
50
0
  has_ttl = (flags & 1) == 1;
51
0
  src.remove_prefix(2);
52
0
  if (!GetFixed64(&src, &expiration_range.first) ||
53
0
      !GetFixed64(&src, &expiration_range.second)) {
54
0
    return Status::Corruption(kErrorMessage, "Error decoding expiration range");
55
0
  }
56
0
  return Status::OK();
57
0
}
58
59
0
void BlobLogFooter::EncodeTo(std::string* dst) {
60
0
  assert(dst != nullptr);
61
0
  dst->clear();
62
0
  dst->reserve(BlobLogFooter::kSize);
63
0
  PutFixed32(dst, kMagicNumber);
64
0
  PutFixed64(dst, blob_count);
65
0
  PutFixed64(dst, expiration_range.first);
66
0
  PutFixed64(dst, expiration_range.second);
67
0
  crc = crc32c::Value(dst->c_str(), dst->size());
68
0
  crc = crc32c::Mask(crc);
69
0
  PutFixed32(dst, crc);
70
0
}
71
72
0
Status BlobLogFooter::DecodeFrom(Slice src) {
73
0
  const char* kErrorMessage = "Error while decoding blob log footer";
74
0
  if (src.size() != BlobLogFooter::kSize) {
75
0
    return Status::Corruption(kErrorMessage,
76
0
                              "Unexpected blob file footer size");
77
0
  }
78
0
  uint32_t src_crc = 0;
79
0
  src_crc = crc32c::Value(src.data(), BlobLogFooter::kSize - sizeof(uint32_t));
80
0
  src_crc = crc32c::Mask(src_crc);
81
0
  uint32_t magic_number = 0;
82
0
  if (!GetFixed32(&src, &magic_number) || !GetFixed64(&src, &blob_count) ||
83
0
      !GetFixed64(&src, &expiration_range.first) ||
84
0
      !GetFixed64(&src, &expiration_range.second) || !GetFixed32(&src, &crc)) {
85
0
    return Status::Corruption(kErrorMessage, "Error decoding content");
86
0
  }
87
0
  if (magic_number != kMagicNumber) {
88
0
    return Status::Corruption(kErrorMessage, "Magic number mismatch");
89
0
  }
90
0
  if (src_crc != crc) {
91
0
    return Status::Corruption(kErrorMessage, "CRC mismatch");
92
0
  }
93
0
  return Status::OK();
94
0
}
95
96
0
void BlobLogRecord::EncodeHeaderTo(std::string* dst) {
97
0
  assert(dst != nullptr);
98
0
  dst->clear();
99
0
  dst->reserve(BlobLogRecord::kHeaderSize + key.size() + value.size());
100
0
  PutFixed64(dst, key.size());
101
0
  PutFixed64(dst, value.size());
102
0
  PutFixed64(dst, expiration);
103
0
  header_crc = crc32c::Value(dst->c_str(), dst->size());
104
0
  header_crc = crc32c::Mask(header_crc);
105
0
  PutFixed32(dst, header_crc);
106
0
  blob_crc = crc32c::Value(key.data(), key.size());
107
0
  blob_crc = crc32c::Extend(blob_crc, value.data(), value.size());
108
0
  blob_crc = crc32c::Mask(blob_crc);
109
0
  PutFixed32(dst, blob_crc);
110
0
}
111
112
0
Status BlobLogRecord::DecodeHeaderFrom(Slice src) {
113
0
  const char* kErrorMessage = "Error while decoding blob record";
114
0
  if (src.size() != BlobLogRecord::kHeaderSize) {
115
0
    return Status::Corruption(kErrorMessage,
116
0
                              "Unexpected blob record header size");
117
0
  }
118
0
  uint32_t src_crc = 0;
119
0
  src_crc = crc32c::Value(src.data(), BlobLogRecord::kHeaderSize - 8);
120
0
  src_crc = crc32c::Mask(src_crc);
121
0
  if (!GetFixed64(&src, &key_size) || !GetFixed64(&src, &value_size) ||
122
0
      !GetFixed64(&src, &expiration) || !GetFixed32(&src, &header_crc) ||
123
0
      !GetFixed32(&src, &blob_crc)) {
124
0
    return Status::Corruption(kErrorMessage, "Error decoding content");
125
0
  }
126
0
  if (src_crc != header_crc) {
127
0
    return Status::Corruption(kErrorMessage, "Header CRC mismatch");
128
0
  }
129
0
  return Status::OK();
130
0
}
131
132
0
Status BlobLogRecord::CheckBlobCRC() const {
133
0
  uint32_t expected_crc = 0;
134
0
  expected_crc = crc32c::Value(key.data(), key.size());
135
0
  expected_crc = crc32c::Extend(expected_crc, value.data(), value.size());
136
0
  expected_crc = crc32c::Mask(expected_crc);
137
0
  if (expected_crc != blob_crc) {
138
0
    return Status::Corruption("Blob CRC mismatch");
139
0
  }
140
0
  return Status::OK();
141
0
}
142
143
}  // namespace ROCKSDB_NAMESPACE