YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/client/table_creator.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/client/table_creator.h"
15
16
#include "yb/client/client-internal.h"
17
#include "yb/client/client.h"
18
#include "yb/client/table_info.h"
19
20
#include "yb/common/schema.h"
21
#include "yb/common/transaction.h"
22
#include "yb/common/wire_protocol.h"
23
24
#include "yb/master/master_ddl.pb.h"
25
26
#include "yb/util/result.h"
27
#include "yb/util/status_format.h"
28
29
#include "yb/yql/redis/redisserver/redis_constants.h"
30
31
DECLARE_bool(client_suppress_created_logs);
32
33
namespace yb {
34
namespace client {
35
36
YBTableCreator::YBTableCreator(YBClient* client)
37
3.20k
  : client_(client), partition_schema_(new PartitionSchemaPB), index_info_(new IndexInfoPB) {
38
3.20k
}
39
40
3.19k
YBTableCreator::~YBTableCreator() {
41
3.19k
}
42
43
3.20k
YBTableCreator& YBTableCreator::table_name(const YBTableName& name) {
44
3.20k
  table_name_ = name;
45
3.20k
  return *this;
46
3.20k
}
47
48
3.12k
YBTableCreator& YBTableCreator::table_type(YBTableType table_type) {
49
3.12k
  table_type_ = ClientToPBTableType(table_type);
50
3.12k
  return *this;
51
3.12k
}
52
53
1.59k
YBTableCreator& YBTableCreator::creator_role_name(const RoleName& creator_role_name) {
54
1.59k
  creator_role_name_ = creator_role_name;
55
1.59k
  return *this;
56
1.59k
}
57
58
1.44k
YBTableCreator& YBTableCreator::table_id(const std::string& table_id) {
59
1.44k
  table_id_ = table_id;
60
1.44k
  return *this;
61
1.44k
}
62
63
0
YBTableCreator& YBTableCreator::is_pg_catalog_table() {
64
0
  is_pg_catalog_table_ = true;
65
0
  return *this;
66
0
}
67
68
0
YBTableCreator& YBTableCreator::is_pg_shared_table() {
69
0
  is_pg_shared_table_ = true;
70
0
  return *this;
71
0
}
72
73
1.36k
YBTableCreator& YBTableCreator::hash_schema(YBHashSchema hash_schema) {
74
1.36k
  switch (hash_schema) {
75
30
    case YBHashSchema::kMultiColumnHash:
76
30
      partition_schema_->set_hash_schema(PartitionSchemaPB::MULTI_COLUMN_HASH_SCHEMA);
77
30
      break;
78
0
    case YBHashSchema::kRedisHash:
79
0
      partition_schema_->set_hash_schema(PartitionSchemaPB::REDIS_HASH_SCHEMA);
80
0
      break;
81
1.33k
    case YBHashSchema::kPgsqlHash:
82
1.33k
      partition_schema_->set_hash_schema(PartitionSchemaPB::PGSQL_HASH_SCHEMA);
83
1.33k
      break;
84
1.36k
  }
85
1.36k
  return *this;
86
1.36k
}
87
88
132
YBTableCreator& YBTableCreator::num_tablets(int32_t count) {
89
132
  num_tablets_ = count;
90
132
  return *this;
91
132
}
92
93
1.42k
YBTableCreator& YBTableCreator::colocated(const bool colocated) {
94
1.42k
  colocated_ = colocated;
95
1.42k
  return *this;
96
1.42k
}
97
98
7
YBTableCreator& YBTableCreator::tablegroup_id(const std::string& tablegroup_id) {
99
7
  tablegroup_id_ = tablegroup_id;
100
7
  return *this;
101
7
}
102
103
0
YBTableCreator& YBTableCreator::tablespace_id(const std::string& tablespace_id) {
104
0
  tablespace_id_ = tablespace_id;
105
0
  return *this;
106
0
}
107
108
0
YBTableCreator& YBTableCreator::matview_pg_table_id(const std::string& matview_pg_table_id) {
109
0
  matview_pg_table_id_ = matview_pg_table_id;
110
0
  return *this;
111
0
}
112
113
3.20k
YBTableCreator& YBTableCreator::schema(const YBSchema* schema) {
114
3.20k
  schema_ = schema;
115
3.20k
  return *this;
116
3.20k
}
117
118
1.41k
YBTableCreator& YBTableCreator::part_of_transaction(const TransactionMetadata* txn) {
119
1.41k
  txn_ = txn;
120
1.41k
  return *this;
121
1.41k
}
122
123
2
YBTableCreator &YBTableCreator::add_partition(const Partition& partition) {
124
2
    partitions_.push_back(partition);
125
2
    return *this;
126
2
}
127
128
YBTableCreator& YBTableCreator::add_hash_partitions(const std::vector<std::string>& columns,
129
0
                                                        int32_t num_buckets) {
130
0
  return add_hash_partitions(columns, num_buckets, 0);
131
0
}
132
133
YBTableCreator& YBTableCreator::add_hash_partitions(const std::vector<std::string>& columns,
134
0
                                                        int32_t num_buckets, int32_t seed) {
135
0
  PartitionSchemaPB::HashBucketSchemaPB* bucket_schema =
136
0
    partition_schema_->add_hash_bucket_schemas();
137
0
  for (const string& col_name : columns) {
138
0
    bucket_schema->add_columns()->set_name(col_name);
139
0
  }
140
0
  bucket_schema->set_num_buckets(num_buckets);
141
0
  bucket_schema->set_seed(seed);
142
0
  return *this;
143
0
}
144
145
YBTableCreator& YBTableCreator::set_range_partition_columns(
146
    const std::vector<std::string>& columns,
147
103
    const std::vector<std::string>& split_rows) {
148
103
  PartitionSchemaPB::RangeSchemaPB* range_schema =
149
103
    partition_schema_->mutable_range_schema();
150
103
  range_schema->Clear();
151
152
  for (const string& col_name : columns) {
152
152
    range_schema->add_columns()->set_name(col_name);
153
152
  }
154
155
15
  for (const auto& row : split_rows) {
156
15
    range_schema->add_splits()->set_column_bounds(row);
157
15
  }
158
103
  return *this;
159
103
}
160
161
1
YBTableCreator& YBTableCreator::replication_info(const master::ReplicationInfoPB& ri) {
162
1
  replication_info_ = std::make_unique<master::ReplicationInfoPB>(ri);
163
1
  return *this;
164
1
}
165
166
609
YBTableCreator& YBTableCreator::indexed_table_id(const std::string& id) {
167
609
  index_info_->set_indexed_table_id(id);
168
609
  return *this;
169
609
}
170
171
440
YBTableCreator& YBTableCreator::is_local_index(bool is_local_index) {
172
440
  index_info_->set_is_local(is_local_index);
173
440
  return *this;
174
440
}
175
176
492
YBTableCreator& YBTableCreator::is_unique_index(bool is_unique_index) {
177
492
  index_info_->set_is_unique(is_unique_index);
178
492
  return *this;
179
492
}
180
181
440
YBTableCreator& YBTableCreator::is_backfill_deferred(bool is_backfill_deferred) {
182
440
  index_info_->set_is_backfill_deferred(is_backfill_deferred);
183
440
  return *this;
184
440
}
185
186
61
YBTableCreator& YBTableCreator::skip_index_backfill(const bool skip_index_backfill) {
187
61
  skip_index_backfill_ = skip_index_backfill;
188
61
  return *this;
189
61
}
190
191
0
YBTableCreator& YBTableCreator::use_mangled_column_name(bool value) {
192
0
  index_info_->set_use_mangled_column_name(value);
193
0
  return *this;
194
0
}
195
196
1.48k
YBTableCreator& YBTableCreator::timeout(const MonoDelta& timeout) {
197
1.48k
  timeout_ = timeout;
198
1.48k
  return *this;
199
1.48k
}
200
201
40
YBTableCreator& YBTableCreator::wait(bool wait) {
202
40
  wait_ = wait;
203
40
  return *this;
204
40
}
205
206
18
YBTableCreator& YBTableCreator::TEST_use_old_style_create_request() {
207
18
  TEST_use_old_style_create_request_ = true;
208
18
  return *this;
209
18
}
210
211
2.93k
Status YBTableCreator::Create() {
212
2.38k
  const char *object_type = index_info_->has_indexed_table_id() ? "index" : "table";
213
2.93k
  if (table_name_.table_name().empty()) {
214
0
    return STATUS_SUBSTITUTE(InvalidArgument, "Missing $0 name", object_type);
215
0
  }
216
  // For a redis table, no external schema is passed to TableCreator, we make a unique schema
217
  // and manage its memory withing here.
218
2.93k
  std::unique_ptr<YBSchema> redis_schema;
219
  // We create dummy schema for transaction status table, redis schema is quite lightweight for
220
  // this purpose.
221
2.93k
  if (table_type_ == TableType::REDIS_TABLE_TYPE ||
222
2.93k
      table_type_ == TableType::TRANSACTION_STATUS_TABLE_TYPE) {
223
0
    CHECK(!schema_) << "Schema should not be set for redis table creation";
224
0
    redis_schema.reset(new YBSchema());
225
0
    YBSchemaBuilder b;
226
0
    b.AddColumn(kRedisKeyColumnName)->Type(BINARY)->NotNull()->HashPrimaryKey();
227
0
    RETURN_NOT_OK(b.Build(redis_schema.get()));
228
0
    schema(redis_schema.get());
229
0
  }
230
2.93k
  if (!schema_) {
231
0
    return STATUS(InvalidArgument, "Missing schema");
232
0
  }
233
234
  // Build request.
235
2.93k
  master::CreateTableRequestPB req;
236
2.93k
  req.set_name(table_name_.table_name());
237
2.93k
  table_name_.SetIntoNamespaceIdentifierPB(req.mutable_namespace_());
238
2.93k
  req.set_table_type(table_type_);
239
2.93k
  req.set_colocated(colocated_);
240
241
2.93k
  if (!creator_role_name_.empty()) {
242
242
    req.set_creator_role_name(creator_role_name_);
243
242
  }
244
245
2.93k
  if (!table_id_.empty()) {
246
1.43k
    req.set_table_id(table_id_);
247
1.43k
  }
248
2.93k
  if (is_pg_catalog_table_) {
249
0
    req.set_is_pg_catalog_table(*is_pg_catalog_table_);
250
0
  }
251
2.93k
  if (is_pg_shared_table_) {
252
0
    req.set_is_pg_shared_table(*is_pg_shared_table_);
253
0
  }
254
255
2.93k
  if (!tablegroup_id_.empty()) {
256
7
    req.set_tablegroup_id(tablegroup_id_);
257
7
  }
258
259
2.93k
  if (!tablespace_id_.empty()) {
260
0
    req.set_tablespace_id(tablespace_id_);
261
0
  }
262
263
2.93k
  if (!matview_pg_table_id_.empty()) {
264
0
    req.set_matview_pg_table_id(matview_pg_table_id_);
265
0
  }
266
267
  // Note that the check that the sum of min_num_replicas for each placement block being less or
268
  // equal than the overall placement info num_replicas is done on the master side and an error is
269
  // naturally returned if you try to create a table and the numbers mismatch. As such, it is the
270
  // responsibility of the client to ensure that does not happen.
271
2.93k
  if (replication_info_) {
272
0
    req.mutable_replication_info()->CopyFrom(*replication_info_);
273
0
  }
274
275
2.93k
  SchemaToPB(internal::GetSchema(*schema_), req.mutable_schema());
276
277
2.93k
  if (txn_) {
278
1.41k
    txn_->ToPB(req.mutable_transaction());
279
1.41k
  }
280
281
  // Setup the number splits (i.e. number of splits).
282
2.93k
  if (num_tablets_ > 0) {
283
0
    VLOG(1) << "num_tablets: number of tablets explicitly specified: " << num_tablets_;
284
2.93k
  } else if (schema_->table_properties().num_tablets() > 0) {
285
0
    VLOG(1) << "num_tablets: number of tablets specified by user: "
286
0
            << schema_->table_properties().num_tablets();
287
178
    num_tablets_ = schema_->table_properties().num_tablets();
288
2.75k
  } else {
289
2.75k
    if (table_name_.is_system()) {
290
0
      num_tablets_ = 1;
291
0
      VLOG(1) << "num_tablets=1: using one tablet for a system table";
292
2.75k
    } else {
293
2.75k
      num_tablets_ = VERIFY_RESULT(client_->NumTabletsForUserTable(table_type_));
294
2.75k
    }
295
2.75k
  }
296
2.93k
  req.set_num_tablets(num_tablets_);
297
298
2.93k
  req.mutable_partition_schema()->CopyFrom(*partition_schema_);
299
300
2.93k
  if (!partitions_.empty()) {
301
0
    for (const auto& p : partitions_) {
302
0
      auto * np = req.add_partitions();
303
0
      p.ToPB(np);
304
0
    }
305
0
  }
306
307
  // Index mapping with data-table being indexed.
308
2.93k
  if (index_info_->has_indexed_table_id()) {
309
548
    if (!TEST_use_old_style_create_request_) {
310
548
      req.mutable_index_info()->CopyFrom(*index_info_);
311
548
    }
312
313
    // For compatibility reasons, set the old fields just in case we have new clients talking to
314
    // old master server during rolling upgrade.
315
548
    req.set_indexed_table_id(index_info_->indexed_table_id());
316
548
    req.set_is_local_index(index_info_->is_local());
317
548
    req.set_is_unique_index(index_info_->is_unique());
318
548
    req.set_skip_index_backfill(skip_index_backfill_);
319
548
    req.set_is_backfill_deferred(index_info_->is_backfill_deferred());
320
548
  }
321
322
2.93k
  auto deadline = CoarseMonoClock::Now() +
323
1.49k
                  (timeout_.Initialized() ? timeout_ : client_->default_admin_operation_timeout());
324
325
2.93k
  auto s = client_->data_->CreateTable(
326
2.93k
      client_, req, *schema_, deadline, &table_id_);
327
328
2.93k
  if (!s.ok() && !s.IsAlreadyPresent()) {
329
8
      RETURN_NOT_OK_PREPEND(s, strings::Substitute("Error creating $0 $1 on the master",
330
0
                                                   object_type, table_name_.ToString()));
331
0
  }
332
333
  // We are here because the create request succeeded or we received an IsAlreadyPresent error.
334
  // Although the table is already in the catalog manager, it doesn't mean that the table is
335
  // ready to receive requests. So we will call WaitForCreateTableToFinish to ensure that once
336
  // this request returns, the client can send operations without receiving a "Table Not Found"
337
  // error.
338
339
  // Spin until the table is fully created, if requested.
340
2.92k
  if (wait_) {
341
2.92k
    RETURN_NOT_OK(client_->data_->WaitForCreateTableToFinish(
342
2.92k
        client_, YBTableName(), table_id_, deadline));
343
2.92k
  }
344
345
2.92k
  if (s.ok() && !FLAGS_client_suppress_created_logs) {
346
2.92k
    LOG(INFO) << "Created " << object_type << " " << table_name_.ToString()
347
2.92k
              << " of type " << TableType_Name(table_type_);
348
2.92k
  }
349
350
2.92k
  return s;
351
2.92k
}
352
353
} // namespace client
354
} // namespace yb