| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| #pragma once |
| |
| #include <cstdint> |
| |
| #include "kudu/gutil/macros.h" |
| #include "kudu/gutil/port.h" |
| #include "kudu/util/status.h" |
| |
| // Macros for injecting various kinds of faults with varying probability. If |
| // configured with 0 probability, each of these macros is evaluated inline and |
| // is fast enough to run even in hot code paths. |
| |
| // With some probability, crash at the current point in the code |
| // by issuing LOG(FATAL). |
| // |
| // The probability is determined by the 'fraction_flag' argument. |
| // |
| // Typical usage: |
| // |
| // DEFINE_double(fault_crash_before_foo, 0.0, |
| // "Fraction of the time when we will crash before doing foo"); |
| // TAG_FLAG(fault_crash_before_foo, unsafe); |
| #define MAYBE_FAULT(fraction_flag) \ |
| kudu::fault_injection::MaybeFault(AS_STRING(fraction_flag), fraction_flag) |
| |
| // Inject a uniformly random amount of latency between 0 and the configured |
| // number of milliseconds. |
| #define MAYBE_INJECT_RANDOM_LATENCY(max_ms_flag) \ |
| kudu::fault_injection::MaybeInjectRandomLatency(max_ms_flag) |
| |
| // Inject a specific amount of latency. |
| #define MAYBE_INJECT_FIXED_LATENCY(ms_flag) \ |
| kudu::fault_injection::MaybeInjectFixedLatency(ms_flag) |
| |
| // With some probability, return the status described by 'status_expr'. |
| // This will not evaluate 'status_expr' if 'fraction_flag' is zero. |
| #define MAYBE_RETURN_FAILURE(fraction_flag, status_expr) \ |
| do { \ |
| if (kudu::fault_injection::MaybeTrue(fraction_flag)) { \ |
| RETURN_NOT_OK((status_expr)); \ |
| } \ |
| } while (false) |
| |
| // Implementation details below. |
| // Use the MAYBE_FAULT macro instead. |
| namespace kudu { |
| namespace fault_injection { |
| |
| // The exit status returned from a process exiting due to a fault. |
| // The choice of value here is arbitrary: just needs to be something |
| // wouldn't normally be returned by a non-fault-injection code path. |
| constexpr int kExitStatus = 85; |
| |
| // Out-of-line implementation. |
| void DoMaybeFault(const char* fault_str, double fraction); |
| void DoInjectRandomLatency(double max_latency_ms); |
| void DoInjectFixedLatency(int32_t latency_ms); |
| bool DoMaybeTrue(double fraction); |
| |
| inline bool MaybeTrue(double fraction) { |
| if (PREDICT_TRUE(fraction <= 0)) return false; |
| return DoMaybeTrue(fraction); |
| } |
| |
| inline void MaybeFault(const char* fault_str, double fraction) { |
| if (PREDICT_TRUE(fraction <= 0)) return; |
| DoMaybeFault(fault_str, fraction); |
| } |
| |
| inline void MaybeInjectRandomLatency(double max_latency) { |
| if (PREDICT_TRUE(max_latency <= 0)) return; |
| DoInjectRandomLatency(max_latency); |
| } |
| |
| inline void MaybeInjectFixedLatency(int32_t latency) { |
| if (PREDICT_TRUE(latency <= 0)) return; |
| DoInjectFixedLatency(latency); |
| } |
| |
| } // namespace fault_injection |
| } // namespace kudu |