YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/client/ql-list-test.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 <thread>
15
16
#include "yb/client/ql-dml-test-base.h"
17
#include "yb/client/schema.h"
18
#include "yb/client/session.h"
19
#include "yb/client/table_handle.h"
20
#include "yb/client/yb_op.h"
21
22
#include "yb/common/ql_type.h"
23
#include "yb/common/ql_value.h"
24
25
#include "yb/util/random_util.h"
26
27
#include "yb/yql/cql/ql/util/statement_result.h"
28
29
using namespace std::literals;
30
31
namespace yb {
32
namespace client {
33
34
namespace {
35
36
constexpr int kCollectionSize = 10;
37
38
0
std::string To8LengthHex(uint32_t value) {
39
0
  char buffer[16];
40
0
  snprintf(buffer, sizeof(buffer), "%08x", value);
41
0
  return buffer;
42
0
}
43
44
template <class RequestPB>
45
0
void AddHash(int32_t hash_seed, RequestPB* req) {
46
0
  QLAddInt32HashValue(req, hash_seed);
47
0
  QLAddInt32HashValue(req, ~hash_seed);
48
0
  auto s1 = To8LengthHex(hash_seed);
49
0
  auto s2 = To8LengthHex(~hash_seed);
50
  // Need 40 chars long string.
51
0
  QLAddStringHashValue(req, s1 + s2 + s1 + s2 + s1);
52
0
}
Unexecuted instantiation: ql-list-test.cc:_ZN2yb6client12_GLOBAL__N_17AddHashINS_16QLWriteRequestPBEEEviPT_
Unexecuted instantiation: ql-list-test.cc:_ZN2yb6client12_GLOBAL__N_17AddHashINS_15QLReadRequestPBEEEviPT_
53
54
// Returns seed for appropriate row. Seed is used to generate all row values.
55
0
int32_t RowSeed(int32_t hash_seed, int32_t range) {
56
0
  return (hash_seed << 16) + range;
57
0
}
58
59
0
int32_t ListEntry(int32_t hash_seed, int32_t range, int32_t i) {
60
0
  return RowSeed(hash_seed, range) * i;
61
0
}
62
63
} // namespace
64
65
class QLListTest : public QLDmlTestBase<MiniCluster> {
66
 public:
67
2
  QLListTest() {
68
2
  }
69
70
2
  void SetUp() override {
71
2
    QLDmlTestBase::SetUp();
72
73
2
    YBSchemaBuilder b;
74
2
    b.AddColumn("h1")->Type(INT32)->HashPrimaryKey()->NotNull();
75
2
    b.AddColumn("h2")->Type(INT32)->HashPrimaryKey()->NotNull();
76
2
    b.AddColumn("h3")->Type(STRING)->HashPrimaryKey()->NotNull();
77
2
    b.AddColumn("r1")->Type(INT32)->PrimaryKey()->NotNull();
78
2
    b.AddColumn("l1")->Type(QLType::CreateTypeList(DataType::INT32));
79
2
    b.AddColumn("s1")->Type(QLType::CreateTypeSet(DataType::STRING));
80
2
    b.AddColumn("s2")->Type(QLType::CreateTypeSet(DataType::STRING));
81
82
2
    ASSERT_OK(table_.Create(kTableName, CalcNumTablets(3), client_.get(), &b));
83
2
  }
84
85
0
  void InsertRows(YBSession* session, int32_t hash_seed, int32_t ranges) {
86
0
    std::vector<YBOperationPtr> ops;
87
0
    for (int32_t range = 0; range != ranges; ++range) {
88
0
      auto op = table_.NewWriteOp(QLWriteRequestPB::QL_STMT_INSERT);
89
0
      auto* const req = op->mutable_request();
90
0
      AddHash(hash_seed, req);
91
0
      QLAddInt32RangeValue(req, range);
92
0
      auto l1 = table_.PrepareColumn(req, "l1")->mutable_list_value();
93
0
      auto s1 = table_.PrepareColumn(req, "s1")->mutable_set_value();
94
0
      auto s2 = table_.PrepareColumn(req, "s2")->mutable_set_value();
95
0
      int32_t seed = RowSeed(hash_seed, range);
96
0
      for (int i = 1; i <= kCollectionSize; ++i) {
97
0
        l1->add_elems()->set_int32_value(ListEntry(hash_seed, range, i));
98
0
        s1->add_elems()->set_string_value(To8LengthHex(seed * i));
99
0
        s2->add_elems()->set_string_value(To8LengthHex((~seed) * i));
100
0
      }
101
0
      ops.push_back(std::move(op));
102
0
    }
103
0
    ASSERT_OK(session->ApplyAndFlush(ops));
104
0
  }
105
106
0
  std::unique_ptr<QLRowBlock> ReadRows(YBSession* session, int32_t hash_seed) {
107
0
    auto op = table_.NewReadOp();
108
0
    auto* const req = op->mutable_request();
109
0
    AddHash(hash_seed, req);
110
0
    table_.AddColumns(table_.AllColumnNames(), req);
111
0
    EXPECT_OK(session->ApplyAndFlush(op));
112
0
    EXPECT_EQ(op->response().status(), QLResponsePB::YQL_STATUS_OK);
113
114
0
    return ql::RowsResult(op.get()).GetRowBlock();
115
0
  }
116
117
  TableHandle table_;
118
};
119
120
0
TEST_F(QLListTest, Simple) {
121
0
  auto session = NewSession();
122
0
  constexpr int kKeys = 2;
123
0
  constexpr int kRanges = 10;
124
0
  for (int i = 1; i <= kKeys; ++i) {
125
0
    InsertRows(session.get(), i, kRanges);
126
0
  }
127
128
0
  for (int k = 1; k <= kKeys; ++k) {
129
0
    auto rowblock = ReadRows(session.get(), k);
130
0
    ASSERT_EQ(kRanges, rowblock->row_count());
131
0
    for (int r = 0; r != kRanges; ++r) {
132
0
      const auto& row = rowblock->row(r);
133
0
      ASSERT_EQ(r, row.column(3).int32_value());
134
0
      const auto& l1 = row.column(4).list_value();
135
0
      ASSERT_EQ(kCollectionSize, l1.elems_size());
136
0
      for (int i = 1; i <= kCollectionSize; ++i) {
137
0
        SCOPED_TRACE(Format("k: $0, r: $1, i: $2", k, r, i));
138
0
        ASSERT_EQ(ListEntry(k, r, i), l1.elems(i - 1).int32_value());
139
0
      }
140
      // TODO add string set verification
141
0
    }
142
0
  }
143
0
}
144
145
0
TEST_F(QLListTest, Performance) {
146
0
  DontVerifyClusterBeforeNextTearDown(); // To remove checksum from perf report
147
148
0
  std::atomic<bool> stop(false);
149
0
  std::atomic<int> inserted(0);
150
0
  std::atomic<int> total_reads(0);
151
0
  constexpr int kRanges = 10;
152
0
  constexpr int kReaders = 4;
153
0
  constexpr int kWarmupInserts = 100;
154
0
  const auto kRunTime = 15s;
155
156
0
  std::thread writer([this, &stop, &inserted] {
157
0
    auto session = NewSession();
158
0
    while (!stop.load()) {
159
0
      auto index = ++inserted;
160
0
      InsertRows(session.get(), index, kRanges);
161
0
      if (index >= kWarmupInserts) {
162
0
        std::this_thread::sleep_for(10ms);
163
0
      }
164
0
    }
165
0
  });
166
167
0
  while (inserted.load() < kWarmupInserts) {
168
0
    std::this_thread::sleep_for(10ms);
169
0
  }
170
171
0
  std::vector<std::thread> readers;
172
0
  for (int i = 0; i != kReaders; ++i) {
173
0
    readers.emplace_back([this, &stop, &inserted, &total_reads, kRanges] {
174
0
      auto session = NewSession();
175
0
      while (!stop.load()) {
176
0
        auto hash_seed = RandomUniformInt(1, inserted.load() - 1);
177
0
        auto rowblock = ReadRows(session.get(), hash_seed);
178
0
        ASSERT_EQ(kRanges, rowblock->row_count()) << "Seed: " << hash_seed;
179
0
        ++total_reads;
180
0
      }
181
0
    });
182
0
  }
183
184
0
  std::this_thread::sleep_for(kRunTime);
185
186
0
  stop = true;
187
0
  LOG(INFO) << "Total writes: " << inserted.load() << ", total reads: " << total_reads.load();
188
189
0
  writer.join();
190
0
  for (auto& t : readers) {
191
0
    t.join();
192
0
  }
193
0
}
194
195
}  // namespace client
196
}  // namespace yb