YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/master/state_with_tablets.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/master/state_with_tablets.h"
15
16
#include "yb/util/enums.h"
17
#include "yb/util/flag_tags.h"
18
#include "yb/util/logging.h"
19
#include "yb/util/result.h"
20
#include "yb/util/status_format.h"
21
22
DEFINE_test_flag(bool, mark_snasphot_as_failed, false,
23
                 "Whether we should skip sending RESTORE_FINISHED to tablets.");
24
25
namespace yb {
26
namespace master {
27
28
namespace {
29
30
const std::initializer_list<std::pair<SysSnapshotEntryPB::State, SysSnapshotEntryPB::State>>
31
    kStateTransitions = {
32
  { SysSnapshotEntryPB::CREATING, SysSnapshotEntryPB::COMPLETE },
33
  { SysSnapshotEntryPB::DELETING, SysSnapshotEntryPB::DELETED },
34
  { SysSnapshotEntryPB::RESTORING, SysSnapshotEntryPB::RESTORED },
35
};
36
37
53
SysSnapshotEntryPB::State InitialStateToTerminalState(SysSnapshotEntryPB::State state) {
38
73
  for (const auto& initial_and_terminal_states : kStateTransitions) {
39
73
    if (state == initial_and_terminal_states.first) {
40
53
      if (PREDICT_FALSE(FLAGS_TEST_mark_snasphot_as_failed)
41
53
          && 
state == SysSnapshotEntryPB::RESTORING0
) {
42
0
        LOG(INFO) << "TEST: Mark COMPETE snapshot as FAILED";
43
0
        return SysSnapshotEntryPB::FAILED;
44
0
      }
45
53
      return initial_and_terminal_states.second;
46
53
    }
47
73
  }
48
49
0
  FATAL_INVALID_PB_ENUM_VALUE(SysSnapshotEntryPB::State, state);
50
0
}
51
52
} // namespace
53
54
StateWithTablets::StateWithTablets(
55
    SnapshotCoordinatorContext* context, SysSnapshotEntryPB::State initial_state,
56
    std::string log_prefix)
57
148
    : context_(*context), initial_state_(initial_state), log_prefix_(std::move(log_prefix)) {
58
148
}
59
60
void StateWithTablets::InitTablets(
61
94
    const google::protobuf::RepeatedPtrField<SysSnapshotEntryPB::TabletSnapshotPB>& tablets) {
62
122
  for (const auto& tablet : tablets) {
63
122
    tablets_.emplace(tablet.id(), tablet.state());
64
122
    if (tablet.state() == initial_state_) {
65
61
      ++num_tablets_in_initial_state_;
66
61
    }
67
122
  }
68
94
  CheckCompleteness();
69
94
}
70
71
52
Result<SysSnapshotEntryPB::State> StateWithTablets::AggregatedState() const {
72
52
  if (tablets_.empty()) {
73
18
    return InitialStateToTerminalState(initial_state_);
74
18
  }
75
34
  SysSnapshotEntryPB::State result = initial_state_;
76
34
  bool has_initial = false;
77
92
  for (const auto& tablet : tablets_) {
78
92
    if (tablet.state == SysSnapshotEntryPB::FAILED) {
79
0
      return SysSnapshotEntryPB::FAILED;
80
92
    } else if (tablet.state == initial_state_) {
81
17
      has_initial = true;
82
75
    } else if (result == initial_state_) {
83
29
      result = tablet.state;
84
46
    } else if (tablet.state != result) {
85
      // Should not happen.
86
0
      return STATUS_FORMAT(IllegalState, "Tablets in different terminal states: $0 and $1",
87
0
                           SysSnapshotEntryPB::State_Name(result),
88
0
                           SysSnapshotEntryPB::State_Name(tablet.state));
89
0
    }
90
92
  }
91
34
  return has_initial ? 
initial_state_7
:
result27
;
92
34
}
93
94
6
Result<bool> StateWithTablets::Complete() const {
95
6
  return VERIFY_RESULT(AggregatedState()) != initial_state_;
96
6
}
97
98
0
Status StateWithTablets::AnyFailure() const {
99
0
  for (const auto& tablet : tablets_) {
100
0
    if (tablet.state == SysSnapshotEntryPB::FAILED) {
101
0
      return tablet.last_error;
102
0
    }
103
0
  }
104
0
  return Status::OK();
105
0
}
106
107
43
bool StateWithTablets::AllTabletsDone() const {
108
43
  return num_tablets_in_initial_state_ == 0;
109
43
}
110
111
0
bool StateWithTablets::PassedSinceCompletion(const MonoDelta& duration) const {
112
0
  if (!AllTabletsDone()) {
113
0
    return false;
114
0
  }
115
116
0
  if (complete_at_ == CoarseTimePoint()) {
117
0
    YB_LOG_EVERY_N_SECS(DFATAL, 30)
118
0
        << LogPrefix() << "All tablets done but complete done was not set";
119
0
    return false;
120
0
  }
121
122
0
  return CoarseMonoClock::Now() > complete_at_ + duration;
123
0
}
124
125
3
std::vector<TabletId> StateWithTablets::TabletIdsInState(SysSnapshotEntryPB::State state) {
126
3
  std::vector<TabletId> result;
127
3
  result.reserve(tablets_.size());
128
7
  for (const auto& tablet : tablets_) {
129
7
    if (tablet.state == state) {
130
7
      result.push_back(tablet.id);
131
7
    }
132
7
  }
133
3
  return result;
134
3
}
135
136
35
void StateWithTablets::Done(const TabletId& tablet_id, Status status) {
137
35
  
VLOG_WITH_PREFIX_AND_FUNC0
(4) << tablet_id << ", " << status0
;
138
139
35
  auto it = tablets_.find(tablet_id);
140
35
  if (it == tablets_.end()) {
141
0
    LOG_WITH_PREFIX(DFATAL)
142
0
        << "Finished " << InitialStateName() <<  " at unknown tablet "
143
0
        << tablet_id << ": " << status;
144
0
    return;
145
0
  }
146
35
  if (!it->running) {
147
0
    LOG_WITH_PREFIX(DFATAL)
148
0
        << "Finished " << InitialStateName() <<  " at " << tablet_id
149
0
        << " that is not running and in state " << SysSnapshotEntryPB::State_Name(it->state)
150
0
        << ": " << status;
151
0
    return;
152
0
  }
153
35
  tablets_.modify(it, [](TabletData& data) { data.running = false; });
154
35
  const auto& state = it->state;
155
35
  if (state == initial_state_) {
156
35
    status = CheckDoneStatus(status);
157
35
    if (status.ok()) {
158
35
      tablets_.modify(
159
35
          it, [terminal_state = InitialStateToTerminalState(initial_state_)](TabletData& data) {
160
35
        data.state = terminal_state;
161
35
      });
162
35
      LOG_WITH_PREFIX(INFO) << "Finished " << InitialStateName() << " at " << tablet_id << ", "
163
35
                            << num_tablets_in_initial_state_ << " was running";
164
35
    } else {
165
0
      auto full_status = status.CloneAndPrepend(
166
0
          Format("Failed to $0 snapshot at $1", InitialStateName(), tablet_id));
167
0
      bool terminal = IsTerminalFailure(status);
168
0
      tablets_.modify(it, [&full_status, terminal](TabletData& data) {
169
0
        if (terminal) {
170
0
          data.state = SysSnapshotEntryPB::FAILED;
171
0
        }
172
0
        data.last_error = full_status;
173
0
      });
174
0
      LOG_WITH_PREFIX(WARNING)
175
0
          << full_status << ", terminal: " << terminal << ", " << num_tablets_in_initial_state_
176
0
          << " was running";
177
0
      if (!terminal) {
178
0
        return;
179
0
      }
180
0
    }
181
35
    --num_tablets_in_initial_state_;
182
35
    CheckCompleteness();
183
35
  } else {
184
0
    LOG_WITH_PREFIX(DFATAL)
185
0
        << "Finished " << InitialStateName() << " at tablet " << tablet_id << " in a wrong state "
186
0
        << state << ": " << status;
187
0
  }
188
35
}
189
190
0
bool StateWithTablets::AllInState(SysSnapshotEntryPB::State state) {
191
0
  for (const auto& tablet : tablets_) {
192
0
    if (tablet.state != state) {
193
0
      return false;
194
0
    }
195
0
  }
196
197
0
  return true;
198
0
}
199
200
0
bool StateWithTablets::HasInState(SysSnapshotEntryPB::State state) {
201
0
  for (const auto& tablet : tablets_) {
202
0
    if (tablet.state == state) {
203
0
      return true;
204
0
    }
205
0
  }
206
207
0
  return false;
208
0
}
209
210
0
void StateWithTablets::SetInitialTabletsState(SysSnapshotEntryPB::State state) {
211
0
  initial_state_ = state;
212
0
  for (auto it = tablets_.begin(); it != tablets_.end(); ++it) {
213
0
    tablets_.modify(it, [state](TabletData& data) {
214
0
      data.state = state;
215
0
    });
216
0
  }
217
0
  num_tablets_in_initial_state_ = tablets_.size();
218
0
}
219
220
44
const std::string& StateWithTablets::InitialStateName() const {
221
44
  return SysSnapshotEntryPB::State_Name(initial_state_);
222
44
}
223
224
186
void StateWithTablets::CheckCompleteness() {
225
186
  if (num_tablets_in_initial_state_ == 0) {
226
110
    complete_at_ = CoarseMonoClock::Now();
227
110
  }
228
186
}
229
230
0
void StateWithTablets::RemoveTablets(const std::vector<std::string>& tablet_ids) {
231
0
  for (const auto& id : tablet_ids) {
232
0
    tablets_.erase(id);
233
0
  }
234
0
}
235
236
35
const std::string& StateWithTablets::LogPrefix() const {
237
35
  return log_prefix_;
238
35
}
239
240
} // namespace master
241
} // namespace yb