YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/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
69
    consensus::ReplicateMsg* replicate) {
44
69
  return replicate->mutable_split_request();
45
69
}
46
47
50
void SplitOperation::AddedAsPending() {
48
50
  tablet()->RegisterOperationFilter(this);
49
50
}
50
51
44
void SplitOperation::RemovedFromPending() {
52
44
  tablet()->UnregisterOperationFilter(this);
53
44
}
54
55
Status SplitOperation::RejectionStatus(
56
    OpId split_op_id, OpId rejected_op_id, consensus::OperationType op_type,
57
12
    const TabletId& child1, const TabletId& child2) {
58
12
  auto status = STATUS_EC_FORMAT(
59
12
      IllegalState, consensus::ConsensusError(consensus::ConsensusErrorPB::TABLET_SPLIT),
60
12
      "Tablet split has been $0, operation $1 $2 should be retried to new tablets",
61
12
      split_op_id.empty() ? "applied" : Format("added to Raft log ($0)", split_op_id),
62
12
      OperationType_Name(op_type), rejected_op_id);
63
12
  return status.CloneAndAddErrorCode(SplitChildTabletIdsData({child1, child2}));
64
12
}
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
16
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
16
  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
12
    case consensus::WRITE_OP: FALLTHROUGH_INTENDED;
85
12
    case consensus::CHANGE_METADATA_OP: FALLTHROUGH_INTENDED;
86
12
    case consensus::HISTORY_CUTOFF_OP: FALLTHROUGH_INTENDED;
87
12
    case consensus::UPDATE_TRANSACTION_OP: FALLTHROUGH_INTENDED;
88
12
    case consensus::TRUNCATE_OP: FALLTHROUGH_INTENDED;
89
12
    case consensus::SPLIT_OP:
90
12
      return false;
91
0
  }
92
0
  FATAL_INVALID_ENUM_VALUE(consensus::OperationType, op_type);
93
0
}
94
95
Status SplitOperation::CheckOperationAllowed(
96
21
    const OpId& id, consensus::OperationType op_type) const {
97
21
  if (id == op_id() || ShouldAllowOpAfterSplitTablet(op_type)) {
98
20
    return Status::OK();
99
20
  }
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
1
  return RejectionStatus(
106
1
      op_id(), id, op_type, request()->new_tablet1_id(), request()->new_tablet2_id());
107
1
}
108
109
50
Status SplitOperation::Prepare() {
110
0
  VLOG_WITH_PREFIX(2) << "Prepare";
111
50
  return Status::OK();
112
50
}
113
114
2
Status SplitOperation::DoAborted(const Status& status) {
115
0
  VLOG_WITH_PREFIX(2) << "DoAborted";
116
2
  return status;
117
2
}
118
119
46
Status SplitOperation::DoReplicated(int64_t leader_term, Status* complete_status) {
120
0
  VLOG_WITH_PREFIX(2) << "Apply";
121
46
  return tablet_splitter().ApplyTabletSplit(this, /* raft_log= */ nullptr);
122
46
}
123
124
}  // namespace tablet
125
}  // namespace yb