YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/tablet/tablet-test-base.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
#ifndef YB_TABLET_TABLET_TEST_BASE_H
33
#define YB_TABLET_TABLET_TEST_BASE_H
34
35
#include <algorithm>
36
#include <limits>
37
#include <string>
38
#include <unordered_set>
39
#include <vector>
40
41
#include <boost/thread/thread.hpp>
42
#include <glog/logging.h>
43
#include <gtest/gtest.h>
44
45
#include "yb/common/partial_row.h"
46
#include "yb/common/ql_expr.h"
47
#include "yb/common/ql_protocol_util.h"
48
#include "yb/common/ql_value.h"
49
50
#include "yb/docdb/ql_rowwise_iterator_interface.h"
51
52
#include "yb/gutil/strings/substitute.h"
53
#include "yb/gutil/strings/util.h"
54
#include "yb/gutil/walltime.h"
55
#include "yb/util/env.h"
56
#include "yb/util/memory/arena.h"
57
#include "yb/util/status_log.h"
58
#include "yb/util/stopwatch.h"
59
#include "yb/util/test_graph.h"
60
#include "yb/util/test_macros.h"
61
#include "yb/util/test_util.h"
62
#include "yb/tablet/local_tablet_writer.h"
63
#include "yb/tablet/tablet-test-util.h"
64
#include "yb/tablet/tablet.h"
65
#include "yb/gutil/strings/numbers.h"
66
67
namespace yb {
68
namespace tablet {
69
70
// The base class takes as a template argument a "setup" class
71
// which can customize the schema for the tests. This way we can
72
// get coverage on various schemas without duplicating test code.
73
struct StringKeyTestSetup {
74
  static Schema CreateSchema();
75
76
  void BuildRowKey(QLWriteRequestPB *req, int64_t key_idx);
77
78
  void BuildRow(QLWriteRequestPB *req, int32_t key_idx, int32_t val = 0);
79
80
  static void FormatKey(char *buf, size_t buf_size, int64_t key_idx);
81
82
  string FormatDebugRow(int64_t key_idx, int32_t val, bool updated);
83
84
  // Slices can be arbitrarily large
85
  // but in practice tests won't overflow a uint64_t
86
  static uint32_t GetMaxRows();
87
};
88
89
// Setup for testing composite keys
90
struct CompositeKeyTestSetup {
91
  static Schema CreateSchema();
92
93
  static void FormatKey(char *buf, size_t buf_size, int64_t key_idx);
94
95
  string FormatDebugRow(int64_t key_idx, int32_t val, bool updated);
96
97
  // Slices can be arbitrarily large
98
  // but in practice tests won't overflow a uint64_t
99
  static uint32_t GetMaxRows();
100
};
101
102
// Setup for testing integer keys
103
template<DataType Type>
104
struct IntKeyTestSetup {
105
  static Schema CreateSchema() {
106
    return Schema({ ColumnSchema("key", Type, false, true),
107
                    ColumnSchema("key_idx", INT32),
108
                    ColumnSchema("val", INT32) }, 1);
109
  }
110
111
  void BuildRowKey(QLWriteRequestPB *req, int64_t i) {
112
    CHECK(false) << "Unsupported type";
113
  }
114
115
  // builds a row key from an existing row for updates
116
  template<class RowType>
117
  void BuildRowKeyFromExistingRow(YBPartialRow *dst_row, const RowType& row) {
118
    CHECK(false) << "Unsupported type";
119
  }
120
121
  void BuildRow(QLWriteRequestPB* req, int32_t key_idx, int32_t val = 0) {
122
    BuildRowKey(req, key_idx);
123
    QLAddInt32ColumnValue(req, kFirstColumnId + 1, key_idx);
124
    QLAddInt32ColumnValue(req, kFirstColumnId + 2, val);
125
  }
126
127
  string FormatDebugRow(int64_t key_idx, int32_t val, bool updated) {
128
    CHECK(false) << "Unsupported type";
129
    return "";
130
  }
131
132
  static uint32_t GetMaxRows() {
133
    using CppType = typename DataTypeTraits<Type>::cpp_type;
134
    uint64_t max = std::numeric_limits<CppType>::max();
135
    if (max > std::numeric_limits<uint32_t>::max()) {
136
      max = static_cast<CppType>(std::numeric_limits<uint32_t>::max());
137
    }
138
    return static_cast<uint32_t>(max - 1);
139
  }
140
};
141
142
template<>
143
2.32k
void IntKeyTestSetup<INT8>::BuildRowKey(QLWriteRequestPB *req, int64_t i) {
144
2.32k
  QLAddInt8HashValue(req, i * (i % 2 == 0 ? 
-11.13k
:
11.19k
));
145
2.32k
}
146
147
template<>
148
4.51k
void IntKeyTestSetup<INT16>::BuildRowKey(QLWriteRequestPB *req, int64_t i) {
149
4.51k
  QLAddInt16HashValue(req, i * (i % 2 == 0 ? 
-12.00k
:
12.50k
));
150
4.51k
}
151
152
template<>
153
4.51k
void IntKeyTestSetup<INT32>::BuildRowKey(QLWriteRequestPB *req, int64_t i) {
154
4.51k
  QLAddInt32HashValue(req, narrow_cast<int32_t>(i * (i % 2 == 0 ? 
-12.00k
:
12.50k
)));
155
4.51k
}
156
157
template<>
158
4.51k
void IntKeyTestSetup<INT64>::BuildRowKey(QLWriteRequestPB *req, int64_t i) {
159
4.51k
  QLAddInt64HashValue(req, i * (i % 2 == 0 ? 
-12.00k
:
12.50k
));
160
4.51k
}
161
162
template<> template<class RowType>
163
void IntKeyTestSetup<INT8>::BuildRowKeyFromExistingRow(YBPartialRow *row,
164
                                                       const RowType& src_row) {
165
  CHECK_OK(row->SetInt8(0, *reinterpret_cast<const int8_t*>(src_row.cell_ptr(0))));
166
}
167
168
template<> template<class RowType>
169
void IntKeyTestSetup<INT16>::BuildRowKeyFromExistingRow(YBPartialRow *row,
170
                                                        const RowType& src_row) {
171
  CHECK_OK(row->SetInt16(0, *reinterpret_cast<const int16_t*>(src_row.cell_ptr(0))));
172
}
173
template<> template<class RowType>
174
void IntKeyTestSetup<INT32>::BuildRowKeyFromExistingRow(YBPartialRow *row,
175
                                                        const RowType& src_row) {
176
  CHECK_OK(row->SetInt32(0, *reinterpret_cast<const int32_t*>(src_row.cell_ptr(0))));
177
}
178
179
template<> template<class RowType>
180
void IntKeyTestSetup<INT64>::BuildRowKeyFromExistingRow(YBPartialRow *row,
181
                                                        const RowType& src_row) {
182
  CHECK_OK(row->SetInt64(0, *reinterpret_cast<const int64_t*>(src_row.cell_ptr(0))));
183
}
184
185
template<>
186
2
string IntKeyTestSetup<INT8>::FormatDebugRow(int64_t key_idx, int32_t val, bool updated) {
187
2
  return strings::Substitute(
188
2
    "{ int8_value: $0 int32_value: $1 int32_value: $2 }",
189
2
    (key_idx % 2 == 0) ? 
-key_idx1
:
key_idx1
, key_idx, val);
190
2
}
191
192
template<>
193
2
string IntKeyTestSetup<INT16>::FormatDebugRow(int64_t key_idx, int32_t val, bool updated) {
194
2
  return strings::Substitute(
195
2
    "{ int16_value: $0 int32_value: $1 int32_value: $2 }",
196
2
    (key_idx % 2 == 0) ? 
-key_idx1
:
key_idx1
, key_idx, val);
197
2
}
198
199
template<>
200
2
string IntKeyTestSetup<INT32>::FormatDebugRow(int64_t key_idx, int32_t val, bool updated) {
201
2
  return strings::Substitute(
202
2
    "{ int32_value: $0 int32_value: $1 int32_value: $2 }",
203
2
    (key_idx % 2 == 0) ? 
-key_idx1
:
key_idx1
, key_idx, val);
204
2
}
205
206
template<>
207
2
string IntKeyTestSetup<INT64>::FormatDebugRow(int64_t key_idx, int32_t val, bool updated) {
208
2
  return strings::Substitute(
209
2
    "{ int64_value: $0 int32_value: $1 int32_value: $2 }",
210
2
    (key_idx % 2 == 0) ? 
-key_idx1
:
key_idx1
, key_idx, val);
211
2
}
212
213
// Setup for testing nullable columns
214
struct NullableValueTestSetup {
215
  static Schema CreateSchema() {
216
    return Schema({ ColumnSchema("key", INT32, false, true),
217
                    ColumnSchema("key_idx", INT32),
218
                    ColumnSchema("val", INT32, true) }, 1);
219
  }
220
221
  void BuildRowKey(QLWriteRequestPB *req, int32_t i) {
222
    QLAddInt32HashValue(req, i);
223
  }
224
225
  // builds a row key from an existing row for updates
226
  template<class RowType>
227
  void BuildRowKeyFromExistingRow(YBPartialRow *row, const RowType& src_row) {
228
    CHECK_OK(row->SetInt32(0, *reinterpret_cast<const int32_t*>(src_row.cell_ptr(0))));
229
  }
230
231
  void BuildRow(QLWriteRequestPB *req, int32_t key_idx, int32_t val = 0) {
232
    BuildRowKey(req, key_idx);
233
    QLAddInt32ColumnValue(req, kFirstColumnId + 1, key_idx);
234
235
    if (!ShouldInsertAsNull(key_idx)) {
236
      QLAddInt32ColumnValue(req, kFirstColumnId + 2, val);
237
    }
238
  }
239
240
  string FormatDebugRow(int64_t key_idx, int64_t val, bool updated) {
241
    if (!updated && ShouldInsertAsNull(key_idx)) {
242
      return strings::Substitute(
243
      "(int32 key=$0, int32 key_idx=$1, int32 val=NULL)",
244
        (int32_t)key_idx, key_idx);
245
    }
246
247
    return strings::Substitute(
248
      "{ int32_value: $0 int32_value: $1 int32_value: $2 }",
249
      (int32_t)key_idx, key_idx, val);
250
  }
251
252
  static bool ShouldInsertAsNull(int64_t key_idx) {
253
    return (key_idx & 2) != 0;
254
  }
255
256
  static uint32_t GetMaxRows() {
257
    return std::numeric_limits<uint32_t>::max() - 1;
258
  }
259
};
260
261
// Use this with TYPED_TEST_CASE from gtest
262
typedef ::testing::Types<
263
                         StringKeyTestSetup,
264
                         IntKeyTestSetup<INT8>,
265
                         IntKeyTestSetup<INT16>,
266
                         IntKeyTestSetup<INT32>,
267
                         IntKeyTestSetup<INT64>,
268
                         NullableValueTestSetup
269
                         > TabletTestHelperTypes;
270
271
class TabletTestPreBase : public YBTabletTest {
272
 public:
273
  TabletTestPreBase(const Schema& schema, uint32_t max_rows)
274
      : YBTabletTest(schema), max_rows_(max_rows), arena_(1_KB, 4_MB) {
275
  }
276
277
  // Inserts "count" rows.
278
  void InsertTestRows(int32_t first_row,
279
                      int32_t count,
280
                      int32_t val,
281
                      TimeSeries *ts = nullptr);
282
283
  // Inserts a single test row within a transaction.
284
  CHECKED_STATUS InsertTestRow(LocalTabletWriter* writer, int32_t key_idx, int32_t val);
285
286
  CHECKED_STATUS UpdateTestRow(LocalTabletWriter* writer, int32_t key_idx, int32_t new_val);
287
288
  CHECKED_STATUS UpdateTestRowToNull(LocalTabletWriter* writer, int32_t key_idx);
289
290
  CHECKED_STATUS DeleteTestRow(LocalTabletWriter* writer, int32_t key_idx);
291
292
  void VerifyTestRows(int32_t first_row, int32_t expected_count);
293
294
  // Iterate through the full table, stringifying the resulting rows
295
  // into the given vector. This is only useful in tests which insert
296
  // a very small number of rows.
297
  CHECKED_STATUS IterateToStringList(vector<string> *out);
298
299
  // Because some types are small we need to
300
  // make sure that we don't overflow the type on inserts
301
  // or else we get errors because the key already exists
302
  uint32_t ClampRowCount(uint32_t proposal) const;
303
304
  virtual void BuildRow(QLWriteRequestPB* row, int32_t key_idx, int32_t value) = 0;
305
  virtual void BuildRowKey(QLWriteRequestPB* row, int32_t key_idx) = 0;
306
307
 private:
308
  const uint32_t max_rows_;
309
  Arena arena_;
310
};
311
312
template<class TestSetup>
313
class TabletTestBase : public TabletTestPreBase {
314
 public:
315
  TabletTestBase() :
316
    TabletTestPreBase(TestSetup::CreateSchema(), TestSetup::GetMaxRows()) {
317
  }
318
319
  template <class RowType>
320
  void VerifyRow(const RowType& row, int64_t key_idx, int32_t val) {
321
    ASSERT_EQ(setup_.FormatDebugRow(key_idx, val, false), schema_.DebugRow(row));
322
  }
323
324
  void BuildRow(QLWriteRequestPB* row, int32_t key_idx, int32_t value) override {
325
    setup_.BuildRow(row, key_idx, value);
326
  }
327
328
  void BuildRowKey(QLWriteRequestPB* row, int32_t key_idx) override {
329
    setup_.BuildRowKey(row, key_idx);
330
  }
331
332
  TestSetup setup_;
333
};
334
335
} // namespace tablet
336
} // namespace yb
337
338
#endif  // YB_TABLET_TABLET_TEST_BASE_H"