YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/tablet/operations/split_operation.cc
Line
Count
Source (jump to first uncovered line)
1
//
2
// Copyright (c) YugaByte, Inc.
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5
// in compliance with the License.  You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software distributed under the License
10
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
// or implied.  See the License for the specific language governing permissions and limitations
12
// under the License.
13
//
14
//
15
16
#include "yb/tablet/operations/split_operation.h"
17
18
#include "yb/common/wire_protocol.h"
19
20
#include "yb/consensus/consensus.pb.h"
21
#include "yb/consensus/consensus_error.h"
22
#include "yb/consensus/consensus_round.h"
23
24
#include "yb/tablet/tablet.h"
25
#include "yb/tablet/tablet_splitter.h"
26
27
#include "yb/util/logging.h"
28
#include "yb/util/status_format.h"
29
30
using namespace std::literals;
31
32
namespace yb {
33
namespace tablet {
34
35
template <>
36
void RequestTraits<tablet::SplitTabletRequestPB>::SetAllocatedRequest(
37
0
    consensus::ReplicateMsg* replicate, SplitTabletRequestPB* request) {
38
0
  replicate->set_allocated_split_request(request);
39
0
}
40
41
template <>
42
SplitTabletRequestPB* RequestTraits<SplitTabletRequestPB>::MutableRequest(
43
116
    consensus::ReplicateMsg* replicate) {
44
116
  return replicate->mutable_split_request();
45
116
}
46
47
71
void SplitOperation::AddedAsPending() {
48
71
  tablet()->RegisterOperationFilter(this);
49
71
}
50
51
67
void SplitOperation::RemovedFromPending() {
52
67
  tablet()->UnregisterOperationFilter(this);
53
67
}
54
55
Status SplitOperation::RejectionStatus(
56
    OpId split_op_id, OpId rejected_op_id, consensus::OperationType op_type,
57
23
    const TabletId& child1, const TabletId& child2) {
58
23
  auto status = STATUS_EC_FORMAT(
59
23
      IllegalState, consensus::ConsensusError(consensus::ConsensusErrorPB::TABLET_SPLIT),
60
23
      "Tablet split has been $0, operation $1 $2 should be retried to new tablets",
61
23
      split_op_id.empty() ? "applied" : Format("added to Raft log ($0)", split_op_id),
62
23
      OperationType_Name(op_type), rejected_op_id);
63
23
  return status.CloneAndAddErrorCode(SplitChildTabletIdsData({child1, child2}));
64
23
}
65
66
// Returns whether Raft operation of op_type is allowed to be added to Raft log of the tablet
67
// for which split tablet Raft operation has been already added to Raft log.
68
27
bool SplitOperation::ShouldAllowOpAfterSplitTablet(const consensus::OperationType op_type) {
69
  // Old tablet remains running for remote bootstrap purposes for some time and could receive
70
  // Raft operations.
71
72
  // If new OperationType is added, make an explicit deliberate decision whether new op type
73
  // should be allowed to be added into Raft log for old (pre-split) tablet.
74
27
  switch (op_type) {
75
      // We allow NO_OP, so old tablet can have leader changes in case of re-elections.
76
1
    case consensus::NO_OP: FALLTHROUGH_INTENDED;
77
      // We allow SNAPSHOT_OP, so old tablet can be restored.
78
1
    case consensus::SNAPSHOT_OP: FALLTHROUGH_INTENDED;
79
      // Allow CHANGE_CONFIG_OP, so the old tablet replicas can be moved between tservers while we
80
      // keep the tablet available.
81
4
    case consensus::CHANGE_CONFIG_OP:
82
4
      return true;
83
0
    case consensus::UNKNOWN_OP: FALLTHROUGH_INTENDED;
84
23
    case consensus::WRITE_OP: FALLTHROUGH_INTENDED;
85
23
    case consensus::CHANGE_METADATA_OP: FALLTHROUGH_INTENDED;
86
23
    case consensus::HISTORY_CUTOFF_OP: FALLTHROUGH_INTENDED;
87
23
    case consensus::UPDATE_TRANSACTION_OP: FALLTHROUGH_INTENDED;
88
23
    case consensus::TRUNCATE_OP: FALLTHROUGH_INTENDED;
89
23
    case consensus::SPLIT_OP:
90
23
      return false;
91
27
  }
92
0
  FATAL_INVALID_ENUM_VALUE(consensus::OperationType, op_type);
93
0
}
94
95
Status SplitOperation::CheckOperationAllowed(
96
47
    const OpId& id, consensus::OperationType op_type) const {
97
47
  if (id == op_id() || 
ShouldAllowOpAfterSplitTablet(op_type)2
) {
98
45
    return Status::OK();
99
45
  }
100
101
  // TODO(tsplit): for optimization - include new tablet IDs into response, so client knows
102
  // earlier where to retry.
103
  // TODO(tsplit): test - check that split_op_id_ is correctly aborted.
104
  // TODO(tsplit): test - check that split_op_id_ is correctly restored during bootstrap.
105
2
  return RejectionStatus(
106
2
      op_id(), id, op_type, request()->new_tablet1_id(), request()->new_tablet2_id());
107
47
}
108
109
71
Status SplitOperation::Prepare() {
110
71
  
VLOG_WITH_PREFIX0
(2) << "Prepare"0
;
111
71
  return Status::OK();
112
71
}
113
114
0
Status SplitOperation::DoAborted(const Status& status) {
115
0
  VLOG_WITH_PREFIX(2) << "DoAborted";
116
0
  return status;
117
0
}
118
119
70
Status SplitOperation::DoReplicated(int64_t leader_term, Status* complete_status) {
120
70
  
VLOG_WITH_PREFIX0
(2) << "Apply"0
;
121
70
  return tablet_splitter().ApplyTabletSplit(this, /* raft_log= */ nullptr);
122
70
}
123
124
}  // namespace tablet
125
}  // namespace yb