Coverage Report

Created: 2024-09-08 07:17

/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