/Users/deen/code/yugabyte-db/ent/src/yb/tserver/backup_service.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 | | #include "yb/tserver/backup_service.h" |
14 | | |
15 | | #include "yb/util/debug/trace_event.h" |
16 | | #include "yb/common/wire_protocol.h" |
17 | | |
18 | | #include "yb/tablet/tablet.h" |
19 | | #include "yb/tablet/tablet_retention_policy.h" |
20 | | #include "yb/tablet/transaction_participant.h" |
21 | | #include "yb/tablet/operations/snapshot_operation.h" |
22 | | |
23 | | #include "yb/tserver/service_util.h" |
24 | | #include "yb/tserver/tablet_server.h" |
25 | | #include "yb/tserver/ts_tablet_manager.h" |
26 | | |
27 | | #include "yb/util/flag_tags.h" |
28 | | #include "yb/util/format.h" |
29 | | #include "yb/util/random_util.h" |
30 | | #include "yb/util/status_format.h" |
31 | | |
32 | | using namespace std::literals; |
33 | | |
34 | | DEFINE_test_flag(int32, tablet_delay_restore_ms, 0, "Delay restore on tablet"); |
35 | | |
36 | | namespace yb { |
37 | | namespace tserver { |
38 | | |
39 | | using rpc::RpcContext; |
40 | | using tablet::SnapshotOperation; |
41 | | using tablet::OperationCompletionCallback; |
42 | | using tablet::Tablet; |
43 | | |
44 | | TabletServiceBackupImpl::TabletServiceBackupImpl(TSTabletManager* tablet_manager, |
45 | | const scoped_refptr<MetricEntity>& metric_entity) |
46 | | : TabletServerBackupServiceIf(metric_entity), |
47 | 5.81k | tablet_manager_(tablet_manager) { |
48 | 5.81k | } |
49 | | |
50 | | void TabletServiceBackupImpl::TabletSnapshotOp(const TabletSnapshotOpRequestPB* req, |
51 | | TabletSnapshotOpResponsePB* resp, |
52 | 4 | RpcContext context) { |
53 | 4 | if (!CheckUuidMatchOrRespond(tablet_manager_, "TabletSnapshotOp", req, resp, &context)) { |
54 | 0 | return; |
55 | 0 | } |
56 | | |
57 | 4 | if (req->tablet_id_size() != 1) { |
58 | 1 | auto status = STATUS_FORMAT( |
59 | 1 | InvalidArgument, "Wrong number of tablets: expected one, but found $0", |
60 | 1 | req->tablet_id_size()); |
61 | 1 | SetupErrorAndRespond(resp->mutable_error(), status, &context); |
62 | 1 | return; |
63 | 1 | } |
64 | | |
65 | 3 | server::UpdateClock(*req, tablet_manager_->server()->Clock()); |
66 | | |
67 | 3 | const auto& tablet_id = req->tablet_id(0); |
68 | | |
69 | 3 | TRACE_EVENT1("tserver", "TabletSnapshotOp", "tablet_id: ", tablet_id); |
70 | | |
71 | 3 | LOG(INFO) << "Processing TabletSnapshotOp for tablet " << tablet_id << " from " |
72 | 3 | << context.requestor_string() << ": " |
73 | 3 | << TabletSnapshotOpRequestPB::Operation_Name(req->operation()); |
74 | 0 | VLOG(1) << "Full request: " << req->DebugString(); |
75 | | |
76 | 3 | auto tablet = LookupLeaderTabletOrRespond(tablet_manager_, tablet_id, resp, &context); |
77 | 3 | if (!tablet) { |
78 | 0 | return; |
79 | 0 | } |
80 | | |
81 | 3 | auto snapshot_hybrid_time = HybridTime::FromPB(req->snapshot_hybrid_time()); |
82 | 3 | tablet::ScopedReadOperation read_operation; |
83 | | // Transaction aware snapshot |
84 | 3 | if (snapshot_hybrid_time && req->operation() == TabletSnapshotOpRequestPB::CREATE_ON_TABLET) { |
85 | | // We need to ensure that the state of the tablet's data at the snapshot hybrid time is not |
86 | | // garbage-collected away only while performing submit. |
87 | | // Since history cutoff is propagated using Raft, it will use the same queue as the |
88 | | // "create snapshot" operation. |
89 | | // So history cutoff could be updated only after the "create snapshot" operation is applied. |
90 | 0 | auto temp_read_operation_result = tablet::ScopedReadOperation::Create( |
91 | 0 | tablet.peer->tablet(), tablet::RequireLease::kTrue, |
92 | 0 | ReadHybridTime::SingleTime(snapshot_hybrid_time)); |
93 | 0 | Status status; |
94 | 0 | if (temp_read_operation_result.ok()) { |
95 | 0 | read_operation = std::move(*temp_read_operation_result); |
96 | 0 | if (tablet.peer->tablet()->transaction_participant()) { |
97 | 0 | status = tablet.peer->tablet()->transaction_participant()->ResolveIntents( |
98 | 0 | snapshot_hybrid_time, context.GetClientDeadline()); |
99 | 0 | } |
100 | 0 | } else { |
101 | 0 | status = temp_read_operation_result.status(); |
102 | 0 | } |
103 | 0 | if (!status.ok()) { |
104 | 0 | return SetupErrorAndRespond(resp->mutable_error(), status, &context); |
105 | 0 | } |
106 | 3 | } |
107 | | |
108 | 3 | auto operation = std::make_unique<SnapshotOperation>(tablet.peer->tablet(), req); |
109 | | |
110 | 3 | auto clock = tablet_manager_->server()->Clock(); |
111 | 3 | operation->set_completion_callback( |
112 | 3 | MakeRpcOperationCompletionCallback(std::move(context), resp, clock)); |
113 | | |
114 | 3 | if (operation->request()->operation() == TabletSnapshotOpRequestPB::RESTORE_ON_TABLET) { |
115 | 1 | AtomicFlagRandomSleepMs(&FLAGS_TEST_tablet_delay_restore_ms); |
116 | 1 | } |
117 | | |
118 | 3 | if (!operation->CheckOperationRequirements()) { |
119 | 0 | return; |
120 | 0 | } |
121 | | |
122 | | // TODO(txn_snapshot) Avoid duplicate snapshots. |
123 | | // Submit the create snapshot op. The RPC will be responded to asynchronously. |
124 | 3 | tablet.peer->Submit(std::move(operation), tablet.leader_term); |
125 | 3 | } |
126 | | |
127 | | } // namespace tserver |
128 | | } // namespace yb |