YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/client/snapshot_test_util.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/snapshot_test_util.h"
15
16
#include "yb/client/client_fwd.h"
17
#include "yb/client/table.h"
18
19
#include "yb/common/common_fwd.h"
20
#include "yb/common/wire_protocol.h"
21
22
#include "yb/rpc/rpc_controller.h"
23
24
#include "yb/util/format.h"
25
#include "yb/util/status_format.h"
26
27
using namespace std::literals;
28
29
namespace yb {
30
namespace client {
31
32
Result<master::SysSnapshotEntryPB::State> SnapshotTestUtil::SnapshotState(
33
0
    const TxnSnapshotId& snapshot_id) {
34
0
  auto snapshots = VERIFY_RESULT(ListSnapshots(snapshot_id));
35
0
  if (snapshots.size() != 1) {
36
0
    return STATUS_FORMAT(RuntimeError, "Wrong number of snapshots, one expected but $0 found",
37
0
                         snapshots.size());
38
0
  }
39
0
  LOG(INFO) << "Snapshot state: " << snapshots[0].ShortDebugString();
40
0
  return snapshots[0].entry().state();
41
0
}
42
43
0
Result<bool> SnapshotTestUtil::IsSnapshotDone(const TxnSnapshotId& snapshot_id) {
44
0
  return VERIFY_RESULT(SnapshotState(snapshot_id)) == master::SysSnapshotEntryPB::COMPLETE;
45
0
}
46
47
Result<Snapshots> SnapshotTestUtil::ListSnapshots(
48
    const TxnSnapshotId& snapshot_id, ListDeleted list_deleted,
49
0
    PrepareForBackup prepare_for_backup) {
50
0
  master::ListSnapshotsRequestPB req;
51
0
  master::ListSnapshotsResponsePB resp;
52
53
0
  req.set_list_deleted_snapshots(list_deleted);
54
0
  req.set_prepare_for_backup(prepare_for_backup);
55
0
  if (!snapshot_id.IsNil()) {
56
0
    req.set_snapshot_id(snapshot_id.data(), snapshot_id.size());
57
0
  }
58
59
0
  rpc::RpcController controller;
60
0
  controller.set_timeout(60s);
61
0
  RETURN_NOT_OK(VERIFY_RESULT(MakeBackupServiceProxy()).ListSnapshots(req, &resp, &controller));
62
0
  if (resp.has_error()) {
63
0
    return StatusFromPB(resp.error().status());
64
0
  }
65
0
  LOG(INFO) << "Snapshots: " << resp.ShortDebugString();
66
0
  return std::move(resp.snapshots());
67
0
}
68
69
CHECKED_STATUS SnapshotTestUtil::VerifySnapshot(
70
    const TxnSnapshotId& snapshot_id, master::SysSnapshotEntryPB::State state,
71
0
    size_t expected_num_tablets, size_t expected_num_namespaces, size_t expected_num_tables) {
72
0
  auto snapshots = VERIFY_RESULT(ListSnapshots());
73
0
  SCHECK_EQ(snapshots.size(), 1, IllegalState, "Wrong number of snapshots");
74
0
  const auto& snapshot = snapshots[0];
75
0
  auto listed_snapshot_id = VERIFY_RESULT(FullyDecodeTxnSnapshotId(snapshot.id()));
76
0
  if (listed_snapshot_id != snapshot_id) {
77
0
    return STATUS_FORMAT(
78
0
        IllegalState, "Wrong snapshot id returned $0, expected $1", listed_snapshot_id,
79
0
        snapshot_id);
80
0
  }
81
0
  if (snapshot.entry().state() != state) {
82
0
    return STATUS_FORMAT(
83
0
        IllegalState, "Wrong snapshot state: $0 vs $1",
84
0
        master::SysSnapshotEntryPB::State_Name(snapshot.entry().state()),
85
0
        master::SysSnapshotEntryPB::State_Name(state));
86
0
  }
87
0
  size_t num_namespaces = 0, num_tables = 0, num_tablets = 0;
88
0
  for (const auto& entry : snapshot.entry().entries()) {
89
0
    switch (entry.type()) {
90
0
      case master::SysRowEntryType::TABLET:
91
0
        ++num_tablets;
92
0
        break;
93
0
      case master::SysRowEntryType::TABLE:
94
0
        ++num_tables;
95
0
        break;
96
0
      case master::SysRowEntryType::NAMESPACE:
97
0
        ++num_namespaces;
98
0
        break;
99
0
      default:
100
0
        return STATUS_FORMAT(
101
0
            IllegalState, "Unexpected entry type: $0",
102
0
            master::SysRowEntryType_Name(entry.type()));
103
0
    }
104
0
  }
105
0
  SCHECK_EQ(num_namespaces, expected_num_namespaces, IllegalState,
106
0
            "Wrong number of namespaces");
107
0
  SCHECK_EQ(num_tables, expected_num_tables, IllegalState, "Wrong number of tables");
108
0
  SCHECK_EQ(num_tablets, expected_num_tablets, IllegalState,
109
0
            "Wrong number of tablets");
110
111
0
  return Status::OK();
112
0
}
113
114
CHECKED_STATUS SnapshotTestUtil::WaitSnapshotInState(
115
    const TxnSnapshotId& snapshot_id, master::SysSnapshotEntryPB::State state,
116
0
    MonoDelta duration) {
117
0
  auto state_name = master::SysSnapshotEntryPB::State_Name(state);
118
0
  master::SysSnapshotEntryPB::State last_state = master::SysSnapshotEntryPB::UNKNOWN;
119
0
  auto status = WaitFor([this, &snapshot_id, state, &last_state]() -> Result<bool> {
120
0
    last_state = VERIFY_RESULT(SnapshotState(snapshot_id));
121
0
    return last_state == state;
122
0
  }, duration * kTimeMultiplier, "Snapshot in state " + state_name);
123
124
0
  if (!status.ok() && status.IsTimedOut()) {
125
0
    return STATUS_FORMAT(
126
0
      IllegalState, "Wrong snapshot state: $0, while $1 expected",
127
0
      master::SysSnapshotEntryPB::State_Name(last_state), state_name);
128
0
  }
129
0
  return status;
130
0
}
131
132
CHECKED_STATUS SnapshotTestUtil::WaitSnapshotDone(
133
0
    const TxnSnapshotId& snapshot_id, MonoDelta duration) {
134
0
  return WaitSnapshotInState(snapshot_id, master::SysSnapshotEntryPB::COMPLETE, duration);
135
0
}
136
137
Result<TxnSnapshotRestorationId> SnapshotTestUtil::StartRestoration(
138
0
    const TxnSnapshotId& snapshot_id, HybridTime restore_at) {
139
0
  master::RestoreSnapshotRequestPB req;
140
0
  master::RestoreSnapshotResponsePB resp;
141
142
0
  rpc::RpcController controller;
143
0
  controller.set_timeout(60s);
144
0
  req.set_snapshot_id(snapshot_id.data(), snapshot_id.size());
145
0
  if (restore_at) {
146
0
    req.set_restore_ht(restore_at.ToUint64());
147
0
  }
148
0
  RETURN_NOT_OK(VERIFY_RESULT(MakeBackupServiceProxy()).RestoreSnapshot(req, &resp, &controller));
149
0
  return FullyDecodeTxnSnapshotRestorationId(resp.restoration_id());
150
0
}
151
152
0
Result<bool> SnapshotTestUtil::IsRestorationDone(const TxnSnapshotRestorationId& restoration_id) {
153
0
  master::ListSnapshotRestorationsRequestPB req;
154
0
  master::ListSnapshotRestorationsResponsePB resp;
155
0
  req.set_restoration_id(restoration_id.data(), restoration_id.size());
156
157
0
  auto deadline = CoarseMonoClock::now() + 60s;
158
0
  for (;;) {
159
0
    rpc::RpcController controller;
160
0
    controller.set_deadline(deadline);
161
0
    RETURN_NOT_OK(
162
0
        VERIFY_RESULT(MakeBackupServiceProxy()).ListSnapshotRestorations(req, &resp, &controller));
163
0
    LOG(INFO) << "Restoration: " << resp.ShortDebugString();
164
0
    if (!resp.has_status()) {
165
0
      break;
166
0
    }
167
0
    auto status = StatusFromPB(resp.status());
168
0
    if (!status.IsServiceUnavailable()) {
169
0
      return status;
170
0
    }
171
0
  }
172
0
  if (resp.restorations().size() != 1) {
173
0
    return STATUS_FORMAT(RuntimeError, "Wrong number of restorations, one expected but $0 found",
174
0
                         resp.restorations().size());
175
0
  }
176
0
  return resp.restorations(0).entry().state() == master::SysSnapshotEntryPB::RESTORED;
177
0
}
178
179
Status SnapshotTestUtil::RestoreSnapshot(
180
0
    const TxnSnapshotId& snapshot_id, HybridTime restore_at) {
181
0
  auto restoration_id = VERIFY_RESULT(StartRestoration(snapshot_id, restore_at));
182
183
0
  return WaitFor([this, &restoration_id] {
184
0
    return IsRestorationDone(restoration_id);
185
0
  }, kWaitTimeout * kTimeMultiplier, Format("Restoration $0 done", restoration_id));
186
0
}
187
188
0
Result<TxnSnapshotId> SnapshotTestUtil::StartSnapshot(const TableHandle& table) {
189
0
  rpc::RpcController controller;
190
0
  controller.set_timeout(60s);
191
0
  master::CreateSnapshotRequestPB req;
192
0
  req.set_transaction_aware(true);
193
0
  auto id = req.add_tables();
194
0
  id->set_table_id(table.table()->id());
195
0
  master::CreateSnapshotResponsePB resp;
196
0
  RETURN_NOT_OK(VERIFY_RESULT(MakeBackupServiceProxy()).CreateSnapshot(req, &resp, &controller));
197
0
  return FullyDecodeTxnSnapshotId(resp.snapshot_id());
198
0
}
199
200
0
Result<TxnSnapshotId> SnapshotTestUtil::CreateSnapshot(const TableHandle& table) {
201
0
  TxnSnapshotId snapshot_id = VERIFY_RESULT(StartSnapshot(table));
202
0
  RETURN_NOT_OK(WaitSnapshotDone(snapshot_id));
203
0
  return snapshot_id;
204
0
}
205
206
0
CHECKED_STATUS SnapshotTestUtil::DeleteSnapshot(const TxnSnapshotId& snapshot_id) {
207
0
  master::DeleteSnapshotRequestPB req;
208
0
  master::DeleteSnapshotResponsePB resp;
209
210
0
  rpc::RpcController controller;
211
0
  controller.set_timeout(60s);
212
0
  req.set_snapshot_id(snapshot_id.data(), snapshot_id.size());
213
0
  RETURN_NOT_OK(VERIFY_RESULT(MakeBackupServiceProxy()).DeleteSnapshot(req, &resp, &controller));
214
0
  if (resp.has_error()) {
215
0
    return StatusFromPB(resp.error().status());
216
0
  }
217
0
  return Status::OK();
218
0
}
219
220
0
CHECKED_STATUS SnapshotTestUtil::WaitAllSnapshotsDeleted() {
221
0
  RETURN_NOT_OK(WaitFor([this]() -> Result<bool> {
222
0
    auto snapshots = VERIFY_RESULT(ListSnapshots());
223
0
    SCHECK_EQ(snapshots.size(), 1, IllegalState, "Wrong number of snapshots");
224
0
    if (snapshots[0].entry().state(), master::SysSnapshotEntryPB::DELETED) {
225
0
      return true;
226
0
    }
227
0
    SCHECK_EQ(snapshots[0].entry().state(), master::SysSnapshotEntryPB::DELETING, IllegalState,
228
0
              "Wrong snapshot state");
229
0
    return false;
230
0
  }, kWaitTimeout * kTimeMultiplier, "Complete delete snapshot"));
231
0
  return Status::OK();
232
0
}
233
234
0
CHECKED_STATUS SnapshotTestUtil::WaitAllSnapshotsCleaned() {
235
0
  return WaitFor([this]() -> Result<bool> {
236
0
    return VERIFY_RESULT(ListSnapshots()).empty();
237
0
  }, kWaitTimeout * kTimeMultiplier, "Snapshot cleanup");
238
0
}
239
240
Result<ImportedSnapshotData> SnapshotTestUtil::StartImportSnapshot(
241
0
    const master::SnapshotInfoPB& snapshot) {
242
0
  master::ImportSnapshotMetaRequestPB req;
243
0
  master::ImportSnapshotMetaResponsePB resp;
244
0
  rpc::RpcController controller;
245
0
  controller.set_timeout(60s);
246
247
0
  *req.mutable_snapshot() = snapshot;
248
249
0
  RETURN_NOT_OK(
250
0
      VERIFY_RESULT(MakeBackupServiceProxy()).ImportSnapshotMeta(req, &resp, &controller));
251
0
  if (resp.has_error()) {
252
0
    return StatusFromPB(resp.error().status());
253
0
  }
254
255
0
  LOG(INFO) << "Imported snapshot metadata: " << resp.DebugString();
256
257
0
  return resp.tables_meta();
258
0
}
259
260
Result<SnapshotScheduleId> SnapshotTestUtil::CreateSchedule(
261
0
    const TableHandle& table, MonoDelta interval, MonoDelta retention) {
262
0
  return CreateSchedule(table, WaitSnapshot::kFalse, interval, retention);
263
0
}
264
265
Result<SnapshotScheduleId> SnapshotTestUtil::CreateSchedule(
266
    const TableHandle& table, WaitSnapshot wait_snapshot,
267
0
    MonoDelta interval, MonoDelta retention) {
268
0
  rpc::RpcController controller;
269
0
  controller.set_timeout(60s);
270
0
  master::CreateSnapshotScheduleRequestPB req;
271
0
  auto& options = *req.mutable_options();
272
0
  options.set_interval_sec(interval.ToSeconds());
273
0
  options.set_retention_duration_sec(retention.ToSeconds());
274
0
  auto& tables = *options.mutable_filter()->mutable_tables()->mutable_tables();
275
0
  tables.Add()->set_table_id(table.table()->id());
276
0
  master::CreateSnapshotScheduleResponsePB resp;
277
0
  RETURN_NOT_OK(
278
0
      VERIFY_RESULT(MakeBackupServiceProxy()).CreateSnapshotSchedule(req, &resp, &controller));
279
0
  auto id = VERIFY_RESULT(FullyDecodeSnapshotScheduleId(resp.snapshot_schedule_id()));
280
0
  if (wait_snapshot) {
281
0
    RETURN_NOT_OK(WaitScheduleSnapshot(id));
282
0
  }
283
0
  return id;
284
0
}
285
286
0
Result<Schedules> SnapshotTestUtil::ListSchedules(const SnapshotScheduleId& id) {
287
0
  master::ListSnapshotSchedulesRequestPB req;
288
0
  master::ListSnapshotSchedulesResponsePB resp;
289
290
0
  if (!id.IsNil()) {
291
0
    req.set_snapshot_schedule_id(id.data(), id.size());
292
0
  }
293
294
0
  rpc::RpcController controller;
295
0
  controller.set_timeout(60s);
296
0
  RETURN_NOT_OK(
297
0
      VERIFY_RESULT(MakeBackupServiceProxy()).ListSnapshotSchedules(req, &resp, &controller));
298
0
  if (resp.has_error()) {
299
0
    return StatusFromPB(resp.error().status());
300
0
  }
301
0
  LOG(INFO) << "Schedules: " << resp.ShortDebugString();
302
0
  return std::move(resp.schedules());
303
0
}
304
305
Result<TxnSnapshotId> SnapshotTestUtil::PickSuitableSnapshot(
306
0
      const SnapshotScheduleId& schedule_id, HybridTime hybrid_time) {
307
0
  auto schedules = VERIFY_RESULT(ListSchedules(schedule_id));
308
0
  SCHECK_EQ(schedules.size(), 1, IllegalState,
309
0
            Format("Expected exactly one schedule with id $0", schedule_id));
310
0
  const auto& schedule = schedules[0];
311
0
  for (const auto& snapshot : schedule.snapshots()) {
312
0
    auto prev_ht = HybridTime::FromPB(snapshot.entry().previous_snapshot_hybrid_time());
313
0
    auto cur_ht = HybridTime::FromPB(snapshot.entry().snapshot_hybrid_time());
314
0
    auto id = VERIFY_RESULT(FullyDecodeTxnSnapshotId(snapshot.id()));
315
0
    if (hybrid_time > prev_ht && hybrid_time <= cur_ht) {
316
0
      return id;
317
0
    }
318
0
    LOG(INFO) << __func__ << " rejected " << id << " (" << prev_ht << "-" << cur_ht << "] for "
319
0
              << hybrid_time;
320
0
  }
321
0
  return STATUS_FORMAT(NotFound, "Not found suitable snapshot for $0", hybrid_time);
322
0
}
323
324
CHECKED_STATUS SnapshotTestUtil::WaitScheduleSnapshot(
325
0
    const SnapshotScheduleId& schedule_id, HybridTime min_hybrid_time) {
326
0
  return WaitScheduleSnapshot(schedule_id, std::numeric_limits<int>::max(), min_hybrid_time);
327
0
}
328
329
CHECKED_STATUS SnapshotTestUtil::WaitScheduleSnapshot(
330
    const SnapshotScheduleId& schedule_id, int max_snapshots,
331
0
    HybridTime min_hybrid_time) {
332
0
  return WaitFor([this, schedule_id, max_snapshots, min_hybrid_time]() -> Result<bool> {
333
0
    auto snapshots = VERIFY_RESULT(ListSnapshots());
334
0
    EXPECT_LE(snapshots.size(), max_snapshots);
335
0
    LOG(INFO) << "Snapshots: " << AsString(snapshots);
336
0
    for (const auto& snapshot : snapshots) {
337
0
      EXPECT_EQ(TryFullyDecodeSnapshotScheduleId(snapshot.entry().schedule_id()), schedule_id);
338
0
      if (snapshot.entry().state() == master::SysSnapshotEntryPB::COMPLETE
339
0
          && HybridTime::FromPB(snapshot.entry().snapshot_hybrid_time()) >= min_hybrid_time) {
340
0
        return true;
341
0
      }
342
0
    }
343
0
      return false;
344
0
    },
345
0
    ((max_snapshots == 1) ? 0s : kSnapshotInterval) + kSnapshotInterval / 2,
346
0
    "Schedule snapshot");
347
0
}
348
349
} // namespace client
350
} // namespace yb