/src/rocksdb/db/wide/wide_column_serialization.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) Meta Platforms, Inc. and affiliates. |
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 | | #include "db/wide/wide_column_serialization.h" |
7 | | |
8 | | #include <algorithm> |
9 | | #include <cassert> |
10 | | #include <limits> |
11 | | |
12 | | #include "db/wide/wide_columns_helper.h" |
13 | | #include "rocksdb/slice.h" |
14 | | #include "util/autovector.h" |
15 | | #include "util/coding.h" |
16 | | |
17 | | namespace ROCKSDB_NAMESPACE { |
18 | | |
19 | | Status WideColumnSerialization::Serialize(const WideColumns& columns, |
20 | 0 | std::string& output) { |
21 | 0 | const size_t num_columns = columns.size(); |
22 | |
|
23 | 0 | if (num_columns > static_cast<size_t>(std::numeric_limits<uint32_t>::max())) { |
24 | 0 | return Status::InvalidArgument("Too many wide columns"); |
25 | 0 | } |
26 | | |
27 | 0 | PutVarint32(&output, kCurrentVersion); |
28 | |
|
29 | 0 | PutVarint32(&output, static_cast<uint32_t>(num_columns)); |
30 | |
|
31 | 0 | const Slice* prev_name = nullptr; |
32 | |
|
33 | 0 | for (size_t i = 0; i < columns.size(); ++i) { |
34 | 0 | const WideColumn& column = columns[i]; |
35 | |
|
36 | 0 | const Slice& name = column.name(); |
37 | 0 | if (name.size() > |
38 | 0 | static_cast<size_t>(std::numeric_limits<uint32_t>::max())) { |
39 | 0 | return Status::InvalidArgument("Wide column name too long"); |
40 | 0 | } |
41 | | |
42 | 0 | if (prev_name && prev_name->compare(name) >= 0) { |
43 | 0 | return Status::Corruption("Wide columns out of order"); |
44 | 0 | } |
45 | | |
46 | 0 | const Slice& value = column.value(); |
47 | 0 | if (value.size() > |
48 | 0 | static_cast<size_t>(std::numeric_limits<uint32_t>::max())) { |
49 | 0 | return Status::InvalidArgument("Wide column value too long"); |
50 | 0 | } |
51 | | |
52 | 0 | PutLengthPrefixedSlice(&output, name); |
53 | 0 | PutVarint32(&output, static_cast<uint32_t>(value.size())); |
54 | |
|
55 | 0 | prev_name = &name; |
56 | 0 | } |
57 | | |
58 | 0 | for (const auto& column : columns) { |
59 | 0 | const Slice& value = column.value(); |
60 | |
|
61 | 0 | output.append(value.data(), value.size()); |
62 | 0 | } |
63 | |
|
64 | 0 | return Status::OK(); |
65 | 0 | } |
66 | | |
67 | | Status WideColumnSerialization::Deserialize(Slice& input, |
68 | 0 | WideColumns& columns) { |
69 | 0 | assert(columns.empty()); |
70 | |
|
71 | 0 | uint32_t version = 0; |
72 | 0 | if (!GetVarint32(&input, &version)) { |
73 | 0 | return Status::Corruption("Error decoding wide column version"); |
74 | 0 | } |
75 | | |
76 | 0 | if (version > kCurrentVersion) { |
77 | 0 | return Status::NotSupported("Unsupported wide column version"); |
78 | 0 | } |
79 | | |
80 | 0 | uint32_t num_columns = 0; |
81 | 0 | if (!GetVarint32(&input, &num_columns)) { |
82 | 0 | return Status::Corruption("Error decoding number of wide columns"); |
83 | 0 | } |
84 | | |
85 | 0 | if (!num_columns) { |
86 | 0 | return Status::OK(); |
87 | 0 | } |
88 | | |
89 | 0 | columns.reserve(num_columns); |
90 | |
|
91 | 0 | autovector<uint32_t, 16> column_value_sizes; |
92 | 0 | column_value_sizes.reserve(num_columns); |
93 | |
|
94 | 0 | for (uint32_t i = 0; i < num_columns; ++i) { |
95 | 0 | Slice name; |
96 | 0 | if (!GetLengthPrefixedSlice(&input, &name)) { |
97 | 0 | return Status::Corruption("Error decoding wide column name"); |
98 | 0 | } |
99 | | |
100 | 0 | if (!columns.empty() && columns.back().name().compare(name) >= 0) { |
101 | 0 | return Status::Corruption("Wide columns out of order"); |
102 | 0 | } |
103 | | |
104 | 0 | columns.emplace_back(name, Slice()); |
105 | |
|
106 | 0 | uint32_t value_size = 0; |
107 | 0 | if (!GetVarint32(&input, &value_size)) { |
108 | 0 | return Status::Corruption("Error decoding wide column value size"); |
109 | 0 | } |
110 | | |
111 | 0 | column_value_sizes.emplace_back(value_size); |
112 | 0 | } |
113 | | |
114 | 0 | const Slice data(input); |
115 | 0 | size_t pos = 0; |
116 | |
|
117 | 0 | for (uint32_t i = 0; i < num_columns; ++i) { |
118 | 0 | const uint32_t value_size = column_value_sizes[i]; |
119 | |
|
120 | 0 | if (pos + value_size > data.size()) { |
121 | 0 | return Status::Corruption("Error decoding wide column value payload"); |
122 | 0 | } |
123 | | |
124 | 0 | columns[i].value() = Slice(data.data() + pos, value_size); |
125 | |
|
126 | 0 | pos += value_size; |
127 | 0 | } |
128 | | |
129 | 0 | return Status::OK(); |
130 | 0 | } |
131 | | |
132 | | WideColumns::const_iterator WideColumnSerialization::Find( |
133 | 0 | const WideColumns& columns, const Slice& column_name) { |
134 | 0 | const auto it = |
135 | 0 | std::lower_bound(columns.cbegin(), columns.cend(), column_name, |
136 | 0 | [](const WideColumn& lhs, const Slice& rhs) { |
137 | 0 | return lhs.name().compare(rhs) < 0; |
138 | 0 | }); |
139 | |
|
140 | 0 | if (it == columns.cend() || it->name() != column_name) { |
141 | 0 | return columns.cend(); |
142 | 0 | } |
143 | | |
144 | 0 | return it; |
145 | 0 | } |
146 | | |
147 | | Status WideColumnSerialization::GetValueOfDefaultColumn(Slice& input, |
148 | 0 | Slice& value) { |
149 | 0 | WideColumns columns; |
150 | |
|
151 | 0 | const Status s = Deserialize(input, columns); |
152 | 0 | if (!s.ok()) { |
153 | 0 | return s; |
154 | 0 | } |
155 | | |
156 | 0 | if (!WideColumnsHelper::HasDefaultColumn(columns)) { |
157 | 0 | value.clear(); |
158 | 0 | return Status::OK(); |
159 | 0 | } |
160 | | |
161 | 0 | value = WideColumnsHelper::GetDefaultColumn(columns); |
162 | |
|
163 | 0 | return Status::OK(); |
164 | 0 | } |
165 | | |
166 | | } // namespace ROCKSDB_NAMESPACE |