YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/docdb/value.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#include "yb/docdb/value.h"
15
16
#include <string>
17
18
#include "yb/common/table_properties_constants.h"
19
20
#include "yb/docdb/value_type.h"
21
22
#include "yb/gutil/strings/substitute.h"
23
24
#include "yb/util/fast_varint.h"
25
#include "yb/util/kv_util.h"
26
#include "yb/util/result.h"
27
28
namespace yb {
29
namespace docdb {
30
31
using std::string;
32
using strings::Substitute;
33
34
const MonoDelta Value::kMaxTtl = yb::common::kMaxTtl;
35
const MonoDelta Value::kResetTtl = MonoDelta::FromNanoseconds(0);
36
const int64_t Value::kInvalidUserTimestamp = yb::common::kInvalidUserTimestamp;
37
38
template <typename T>
39
bool DecodeType(ValueType expected_value_type, const T& default_value, Slice* slice,
40
1.00G
                T* val) {
41
1.00G
  if (!slice->TryConsumeByte(static_cast<char>(expected_value_type))) {
42
960M
    *val = default_value;
43
960M
    return false;
44
960M
  }
45
46
43.1M
  return true;
47
43.1M
}
_ZN2yb5docdb10DecodeTypeIyEEbNS0_9ValueTypeERKT_PNS_5SliceEPS3_
Line
Count
Source
40
250M
                T* val) {
41
250M
  if (!slice->TryConsumeByte(static_cast<char>(expected_value_type))) {
42
250M
    *val = default_value;
43
250M
    return false;
44
250M
  }
45
46
18.4E
  return true;
47
18.4E
}
_ZN2yb5docdb10DecodeTypeINS_13DocHybridTimeEEEbNS0_9ValueTypeERKT_PNS_5SliceEPS4_
Line
Count
Source
40
250M
                T* val) {
41
250M
  if (!slice->TryConsumeByte(static_cast<char>(expected_value_type))) {
42
207M
    *val = default_value;
43
207M
    return false;
44
207M
  }
45
46
43.3M
  return true;
47
43.3M
}
_ZN2yb5docdb10DecodeTypeINS_9MonoDeltaEEEbNS0_9ValueTypeERKT_PNS_5SliceEPS4_
Line
Count
Source
40
250M
                T* val) {
41
251M
  if (!slice->TryConsumeByte(static_cast<char>(expected_value_type))) {
42
251M
    *val = default_value;
43
251M
    return false;
44
251M
  }
45
46
18.4E
  return true;
47
18.4E
}
_ZN2yb5docdb10DecodeTypeIxEEbNS0_9ValueTypeERKT_PNS_5SliceEPS3_
Line
Count
Source
40
251M
                T* val) {
41
251M
  if (!slice->TryConsumeByte(static_cast<char>(expected_value_type))) {
42
251M
    *val = default_value;
43
251M
    return false;
44
251M
  }
45
46
18.4E
  return true;
47
18.4E
}
48
49
250M
CHECKED_STATUS Value::DecodeMergeFlags(Slice* slice, uint64_t* merge_flags) {
50
250M
  if (DecodeType(ValueType::kMergeFlags, (uint64_t) 0, slice, merge_flags)) {
51
162
    *merge_flags = VERIFY_RESULT(util::FastDecodeUnsignedVarInt(slice));
52
162
  }
53
250M
  return Status::OK();
54
250M
}
55
56
0
CHECKED_STATUS Value::DecodeMergeFlags(const rocksdb::Slice& slice, uint64_t* merge_flags) {
57
0
  rocksdb::Slice value_copy = slice;
58
0
  return DecodeMergeFlags(&value_copy, merge_flags);
59
0
}
60
61
250M
CHECKED_STATUS DecodeIntentDocHT(Slice* slice, DocHybridTime* doc_ht) {
62
250M
  if (!DecodeType(ValueType::kHybridTime, DocHybridTime::kInvalid, slice, doc_ht)) {
63
207M
    return Status::OK();
64
207M
  }
65
43.0M
  return doc_ht->DecodeFrom(slice);
66
43.0M
}
67
68
250M
Status Value::DecodeTTL(rocksdb::Slice* slice, MonoDelta* ttl) {
69
250M
  if (DecodeType(ValueType::kTtl, kMaxTtl, slice, ttl)) {
70
1.15k
    *ttl = MonoDelta::FromMilliseconds(VERIFY_RESULT(util::FastDecodeSignedVarIntUnsafe(slice)));
71
1.15k
  }
72
250M
  return Status::OK();
73
250M
}
74
75
0
Status Value::DecodeTTL(const rocksdb::Slice& rocksdb_value, MonoDelta* ttl) {
76
0
  rocksdb::Slice value_copy = rocksdb_value;
77
0
  uint64_t merge_flags;
78
0
  RETURN_NOT_OK(DecodeMergeFlags(&value_copy, &merge_flags));
79
0
  return DecodeTTL(&value_copy, ttl);
80
0
}
81
82
Status Value::DecodeUserTimestamp(const rocksdb::Slice& rocksdb_value,
83
0
                                  UserTimeMicros* user_timestamp) {
84
0
  MonoDelta ttl;
85
0
  auto slice_copy = rocksdb_value;
86
0
  RETURN_NOT_OK(DecodeTTL(&slice_copy, &ttl));
87
0
  return DecodeUserTimestamp(&slice_copy, user_timestamp);
88
0
}
89
90
251M
Status Value::DecodeUserTimestamp(rocksdb::Slice* slice, UserTimeMicros* user_timestamp) {
91
251M
  if (DecodeType(ValueType::kUserTimestamp, kInvalidUserTimestamp, slice,
92
315
                 user_timestamp)) {
93
315
    if (slice->size() < kBytesPerInt64) {
94
0
      return STATUS(Corruption, Substitute(
95
0
          "Failed to decode TTL from value, size too small: $1, need $2",
96
0
          slice->size(), kBytesPerInt64));
97
0
    }
98
99
315
    *user_timestamp = BigEndian::Load64(slice->data());
100
315
    slice->remove_prefix(kBytesPerInt64);
101
315
  }
102
251M
  return Status::OK();
103
251M
}
104
105
250M
Status Value::DecodeControlFields(Slice* slice) {
106
250M
  if (slice->empty()) {
107
0
    return STATUS(Corruption, "Cannot decode a value from an empty slice");
108
0
  }
109
110
250M
  Slice original = *slice;
111
250M
  RETURN_NOT_OK_PREPEND(
112
250M
      DecodeMergeFlags(slice, &merge_flags_),
113
250M
      Format("Failed to decode merge flags in $0", original.ToDebugHexString()));
114
250M
  RETURN_NOT_OK_PREPEND(
115
250M
      DecodeIntentDocHT(slice, &intent_doc_ht_),
116
250M
      Format("Failed to decode intent ht in $0", original.ToDebugHexString()));
117
250M
  RETURN_NOT_OK_PREPEND(
118
250M
      DecodeTTL(slice, &ttl_),
119
250M
      Format("Failed to decode TTL in $0", original.ToDebugHexString()));
120
250M
  RETURN_NOT_OK_PREPEND(
121
250M
      DecodeUserTimestamp(slice, &user_timestamp_),
122
250M
      Format("Failed to decode user timestamp in $0", original.ToDebugHexString()));
123
250M
  return Status::OK();
124
250M
}
125
126
250M
Status Value::Decode(const Slice& rocksdb_value) {
127
250M
  Slice slice = rocksdb_value;
128
250M
  RETURN_NOT_OK(DecodeControlFields(&slice));
129
250M
  RETURN_NOT_OK_PREPEND(
130
250M
      primitive_value_.DecodeFromValue(slice),
131
250M
      Format("Failed to decode value in $0", rocksdb_value.ToDebugHexString()));
132
250M
  return Status::OK();
133
250M
}
134
135
180k
std::string Value::ToString() const {
136
180k
  std::string result = primitive_value_.ToString();
137
180k
  if (merge_flags_) {
138
0
    result += Format("; merge flags: $0", merge_flags_);
139
0
  }
140
180k
  if (intent_doc_ht_.is_valid()) {
141
0
    result += Format("; intent doc ht: $0", intent_doc_ht_);
142
0
  }
143
180k
  if (!ttl_.Equals(kMaxTtl)) {
144
0
    result += Format("; ttl: $0", ttl_);
145
0
  }
146
180k
  if (user_timestamp_ != kInvalidUserTimestamp) {
147
0
    result += Format("; user timestamp: $0", user_timestamp_);
148
0
  }
149
180k
  return result;
150
180k
}
151
152
0
std::string Value::DebugSliceToString(const Slice& encoded_value) {
153
0
  Value value;
154
0
  auto status = value.Decode(encoded_value);
155
0
  if (!status.ok()) {
156
0
    return status.ToString();
157
0
  }
158
159
0
  return value.ToString();
160
0
}
161
162
21.3M
std::string Value::Encode(const Slice* external_value) const {
163
21.3M
  std::string result;
164
21.3M
  EncodeAndAppend(&result, external_value);
165
21.3M
  return result;
166
21.3M
}
167
168
21.3M
void Value::EncodeAndAppend(std::string *value_bytes, const Slice* external_value) const {
169
21.3M
  if (merge_flags_) {
170
18
    value_bytes->push_back(ValueTypeAsChar::kMergeFlags);
171
18
    util::FastAppendUnsignedVarIntToStr(merge_flags_, value_bytes);
172
18
  }
173
21.3M
  if (intent_doc_ht_.is_valid()) {
174
0
    value_bytes->push_back(ValueTypeAsChar::kHybridTime);
175
0
    intent_doc_ht_.AppendEncodedInDocDbFormat(value_bytes);
176
0
  }
177
21.3M
  if (!ttl_.Equals(kMaxTtl)) {
178
265
    value_bytes->push_back(ValueTypeAsChar::kTtl);
179
265
    util::FastAppendSignedVarIntToBuffer(ttl_.ToMilliseconds(), value_bytes);
180
265
  }
181
21.3M
  if (user_timestamp_ != kInvalidUserTimestamp) {
182
138
    value_bytes->push_back(ValueTypeAsChar::kUserTimestamp);
183
138
    util::AppendBigEndianUInt64(user_timestamp_, value_bytes);
184
138
  }
185
21.3M
  if (!external_value) {
186
21.3M
    value_bytes->append(primitive_value_.ToValue());
187
18.4E
  } else {
188
18.4E
    value_bytes->append(external_value->cdata(), external_value->size());
189
18.4E
  }
190
21.3M
}
191
192
Status Value::DecodePrimitiveValueType(
193
    const rocksdb::Slice& rocksdb_value,
194
    ValueType* value_type,
195
    uint64_t* merge_flags,
196
    MonoDelta* ttl,
197
170k
    int64_t* user_ts) {
198
170k
  auto slice_copy = rocksdb_value;
199
170k
  uint64_t local_merge_flags;
200
170k
  DocHybridTime local_doc_ht;
201
170k
  MonoDelta local_ttl;
202
170k
  int64_t local_user_ts;
203
170k
  RETURN_NOT_OK(DecodeMergeFlags(&slice_copy, merge_flags ? merge_flags : &local_merge_flags));
204
170k
  RETURN_NOT_OK(DecodeIntentDocHT(&slice_copy, &local_doc_ht));
205
170k
  RETURN_NOT_OK(DecodeTTL(&slice_copy, ttl ? ttl : &local_ttl));
206
170k
  RETURN_NOT_OK(DecodeUserTimestamp(&slice_copy, user_ts ? user_ts : &local_user_ts));
207
170k
  *value_type = DecodeValueType(slice_copy);
208
170k
  return Status::OK();
209
170k
}
210
211
42
const Value& Value::Tombstone() {
212
42
  static const auto kTombstone = Value(PrimitiveValue::kTombstone);
213
42
  return kTombstone;
214
42
}
215
216
0
const string& Value::EncodedTombstone() {
217
0
  static const string kEncodedTombstone = Tombstone().Encode();
218
0
  return kEncodedTombstone;
219
0
}
220
221
0
void Value::ClearIntentDocHt() {
222
0
  intent_doc_ht_ = DocHybridTime::kInvalid;
223
0
}
224
225
0
Result<bool> Value::IsTombstoned(const Slice& slice) {
226
0
  Value doc_value;
227
0
  Slice value = slice;
228
0
  RETURN_NOT_OK(doc_value.DecodeControlFields(&value));
229
0
  return value[0] == ValueTypeAsChar::kTombstone;
230
0
}
231
232
}  // namespace docdb
233
}  // namespace yb