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