This is an automated email from the ASF dual-hosted git repository.

ethanfeng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/celeborn.git


The following commit(s) were added to refs/heads/main by this push:
     new 6a0f763e2 [CELEBORN-1751][CIP-14] Add celebornException utils to 
cppClient
6a0f763e2 is described below

commit 6a0f763e232092a8227b01c3044a77fdd191b976
Author: HolyLow <[email protected]>
AuthorDate: Thu Nov 28 11:10:58 2024 +0800

    [CELEBORN-1751][CIP-14] Add celebornException utils to cppClient
    
    ### What changes were proposed in this pull request?
    This PR adds CelebornException utils code to CppClient.
    
    ### Why are the changes needed?
    To provide CelebornException utils.
    
    ### Does this PR introduce _any_ user-facing change?
    No.
    
    ### How was this patch tested?
    Compilation.
    
    Closes #2958 from 
HolyLow/issue/celeborn-1751-add-celeborn-exception-utils-to-cppClient.
    
    Authored-by: HolyLow <[email protected]>
    Signed-off-by: mingji <[email protected]>
---
 LICENSE                                  |   3 +
 cpp/celeborn/utils/CMakeLists.txt        |   2 +-
 cpp/celeborn/utils/CelebornException.cpp | 281 +++++++++++++++++++++
 cpp/celeborn/utils/CelebornException.h   | 415 +++++++++++++++++++++++++++++++
 cpp/celeborn/utils/flags.cpp             |  49 ++++
 5 files changed, 749 insertions(+), 1 deletion(-)

diff --git a/LICENSE b/LICENSE
index 0e5363511..0147fe37f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -264,6 +264,9 @@ Meta Velox
 ./cpp/celeborn/utils/ProcessBase.cpp
 ./cpp/celeborn/utils/StackTrace.h
 ./cpp/celeborn/utils/StackTrace.cpp
+./cpp/celeborn/utils/CelebornException.h
+./cpp/celeborn/utils/CelebornException.cpp
+./cpp/celeborn/utils/flags.cpp
 
 
 
------------------------------------------------------------------------------------
diff --git a/cpp/celeborn/utils/CMakeLists.txt 
b/cpp/celeborn/utils/CMakeLists.txt
index f473fb5e6..ed5340180 100644
--- a/cpp/celeborn/utils/CMakeLists.txt
+++ b/cpp/celeborn/utils/CMakeLists.txt
@@ -12,7 +12,7 @@
 # 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.
-add_library(utils ProcessBase.cpp StackTrace.cpp)
+add_library(utils ProcessBase.cpp StackTrace.cpp CelebornException.cpp 
flags.cpp)
 
 target_link_libraries(
         utils
diff --git a/cpp/celeborn/utils/CelebornException.cpp 
b/cpp/celeborn/utils/CelebornException.cpp
new file mode 100644
index 000000000..aa9c63e92
--- /dev/null
+++ b/cpp/celeborn/utils/CelebornException.cpp
@@ -0,0 +1,281 @@
+/*
+ * Based on VeloxException.cpp from Facebook Velox
+ *
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * Licensed 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.
+ */
+
+#include "celeborn/utils/CelebornException.h"
+
+#include <folly/synchronization/AtomicStruct.h>
+#include <google/protobuf/message.h>
+
+#include <exception>
+
+namespace celeborn {
+
+std::exception_ptr toCelebornException(const std::exception_ptr& exceptionPtr) 
{
+  try {
+    std::rethrow_exception(exceptionPtr);
+  } catch (const CelebornException&) {
+    return exceptionPtr;
+  } catch (const std::exception& e) {
+    return std::make_exception_ptr(
+        CelebornUserError(std::current_exception(), e.what(), false));
+  }
+}
+
+int64_t& threadNumCelebornThrow() {
+  thread_local int64_t numThrow;
+  return numThrow;
+}
+
+ExceptionContext& getExceptionContext() {
+  thread_local ExceptionContext context;
+  return context;
+}
+
+// Retrieves the message of the top-level ancestor of the current exception
+// context. If the top-level context message is not empty and is the same as 
the
+// current one, returns a string indicating they are the same.
+std::string getTopLevelExceptionContextString(
+    CelebornException::Type exceptionType,
+    const std::string& currentMessage) {
+  auto* context = &getExceptionContext();
+  if (context->parent && context->parent->parent) {
+    while (context->parent && context->parent->parent) {
+      context = context->parent;
+    }
+    auto topLevelMessage = context->message(exceptionType);
+    if (!topLevelMessage.empty() && topLevelMessage == currentMessage) {
+      return "Same as context.";
+    } else {
+      return topLevelMessage;
+    }
+  }
+
+  if (!currentMessage.empty()) {
+    return "Same as context.";
+  }
+  return "";
+}
+
+CelebornException::CelebornException(
+    const char* file,
+    size_t line,
+    const char* function,
+    std::string_view failingExpression,
+    std::string_view message,
+    std::string_view errorSource,
+    std::string_view errorCode,
+    bool isRetriable,
+    Type exceptionType,
+    std::string_view exceptionName)
+    : CelebornException(State::make(exceptionType, [&](auto& state) {
+        state.exceptionType = exceptionType;
+        state.exceptionName = exceptionName;
+        state.file = file;
+        state.line = line;
+        state.function = function;
+        state.failingExpression = failingExpression;
+        state.message = message;
+        state.errorSource = errorSource;
+        state.errorCode = errorCode;
+        state.context = getExceptionContext().message(exceptionType);
+        state.topLevelContext =
+            getTopLevelExceptionContextString(exceptionType, state.context);
+        state.isRetriable = isRetriable;
+      })) {}
+
+CelebornException::CelebornException(
+    const std::exception_ptr& e,
+    std::string_view message,
+    std::string_view errorSource,
+    std::string_view errorCode,
+    bool isRetriable,
+    Type exceptionType,
+    std::string_view exceptionName)
+    : CelebornException(State::make([&](auto& state) {
+        state.exceptionType = exceptionType;
+        state.exceptionName = exceptionName;
+        state.file = "UNKNOWN";
+        state.line = 0;
+        state.function = "";
+        state.failingExpression = "";
+        state.message = message;
+        state.errorSource = errorSource;
+        state.errorCode = errorCode;
+        state.context = getExceptionContext().message(exceptionType);
+        state.topLevelContext =
+            getTopLevelExceptionContextString(exceptionType, state.context);
+        state.isRetriable = isRetriable;
+        state.wrappedException = e;
+      })) {}
+
+namespace {
+
+/// returns whether CelebornException stacktraces are enabled and whether, if
+/// they are rate-limited, whether the rate-limit check passes
+bool isStackTraceEnabled(CelebornException::Type type) {
+  using namespace std::literals::chrono_literals;
+  const bool isSysException = type == CelebornException::Type::kSystem;
+  if ((isSysException && !FLAGS_celeborn_exception_system_stacktrace_enabled) 
||
+      (!isSysException && !FLAGS_celeborn_exception_user_stacktrace_enabled)) {
+    // CelebornException stacktraces are disabled.
+    return false;
+  }
+
+  const int32_t rateLimitMs = isSysException
+      ? FLAGS_celeborn_exception_system_stacktrace_rate_limit_ms
+      : FLAGS_celeborn_exception_user_stacktrace_rate_limit_ms;
+  // not static so the gflag can be manipulated at runtime
+  if (0 == rateLimitMs) {
+    // CelebornException stacktraces are not rate-limited
+    return true;
+  }
+  static folly::AtomicStruct<std::chrono::steady_clock::time_point> systemLast;
+  static folly::AtomicStruct<std::chrono::steady_clock::time_point> userLast;
+  auto* last = isSysException ? &systemLast : &userLast;
+
+  auto const now = std::chrono::steady_clock::now();
+  auto latest = last->load(std::memory_order_relaxed);
+  if (now < latest + std::chrono::milliseconds(rateLimitMs)) {
+    // CelebornException stacktraces are rate-limited and the rate-limit check
+    // failed
+    return false;
+  }
+
+  // CelebornException stacktraces are rate-limited and the rate-limit check
+  // passed
+  //
+  // the cas happens only here, so the rate-limit check in effect gates not
+  // only computation of the stacktrace but also contention on this atomic
+  // variable
+  return last->compare_exchange_strong(latest, now, std::memory_order_relaxed);
+}
+
+} // namespace
+
+template <typename F>
+std::shared_ptr<const CelebornException::State> CelebornException::State::make(
+    CelebornException::Type exceptionType,
+    F f) {
+  auto state = std::make_shared<CelebornException::State>();
+  if (isStackTraceEnabled(exceptionType)) {
+    // new v.s. make_unique to avoid any extra frames from make_unique
+    state->stackTrace.reset(new utils::StackTrace());
+  }
+  f(*state);
+  return state;
+}
+
+/*
+Not much to say. Constructs the elaborate message from the available
+pieces of information.
+ */
+void CelebornException::State::finalize() const {
+  assert(elaborateMessage.empty());
+
+  // Fill elaborateMessage_
+  if (!exceptionName.empty()) {
+    elaborateMessage += "Exception: ";
+    elaborateMessage += exceptionName;
+    elaborateMessage += '\n';
+  }
+
+  if (!errorSource.empty()) {
+    elaborateMessage += "Error Source: ";
+    elaborateMessage += errorSource;
+    elaborateMessage += '\n';
+  }
+
+  if (!errorCode.empty()) {
+    elaborateMessage += "Error Code: ";
+    elaborateMessage += errorCode;
+    elaborateMessage += '\n';
+  }
+
+  if (!message.empty()) {
+    elaborateMessage += "Reason: ";
+    elaborateMessage += message;
+    elaborateMessage += '\n';
+  }
+
+  elaborateMessage += "Retriable: ";
+  elaborateMessage += isRetriable ? "True" : "False";
+  elaborateMessage += '\n';
+
+  if (!failingExpression.empty()) {
+    elaborateMessage += "Expression: ";
+    elaborateMessage += failingExpression;
+    elaborateMessage += '\n';
+  }
+
+  if (!context.empty()) {
+    elaborateMessage += "Context: " + context + "\n";
+  }
+
+  if (!topLevelContext.empty()) {
+    elaborateMessage += "Top-Level Context: " + topLevelContext + "\n";
+  }
+
+  if (function) {
+    elaborateMessage += "Function: ";
+    elaborateMessage += function;
+    elaborateMessage += '\n';
+  }
+
+  if (file) {
+    elaborateMessage += "File: ";
+    elaborateMessage += file;
+    elaborateMessage += '\n';
+  }
+
+  if (line) {
+    elaborateMessage += "Line: ";
+    auto len = elaborateMessage.size();
+    size_t t = line;
+    do {
+      elaborateMessage += static_cast<char>('0' + t % 10);
+      t /= 10;
+    } while (t);
+    reverse(elaborateMessage.begin() + len, elaborateMessage.end());
+    elaborateMessage += '\n';
+  }
+
+  elaborateMessage += "Stack trace:\n";
+  if (stackTrace) {
+    elaborateMessage += stackTrace->toString();
+  } else {
+    elaborateMessage += "Stack trace has been disabled.";
+    if (exceptionType == CelebornException::Type::kSystem) {
+      elaborateMessage +=
+          " Use --celeborn_exception_system_stacktrace_enabled=true to enable 
it.\n";
+    } else {
+      elaborateMessage +=
+          " Use --celeborn_exception_user_stacktrace_enabled=true to enable 
it.\n";
+    }
+  }
+}
+
+const char* CelebornException::State::what() const noexcept {
+  try {
+    folly::call_once(once, [&] { finalize(); });
+    return elaborateMessage.c_str();
+  } catch (...) {
+    return "<unknown failure in CelebornException::what>";
+  }
+}
+
+} // namespace celeborn
diff --git a/cpp/celeborn/utils/CelebornException.h 
b/cpp/celeborn/utils/CelebornException.h
new file mode 100644
index 000000000..a711ca78e
--- /dev/null
+++ b/cpp/celeborn/utils/CelebornException.h
@@ -0,0 +1,415 @@
+/*
+ * Based on VeloxException.h from Facebook Velox
+ *
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * Licensed 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 <exception>
+#include <string>
+
+#include <folly/Exception.h>
+#include <folly/FixedString.h>
+#include <folly/String.h>
+#include <folly/synchronization/CallOnce.h>
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+
+#include "celeborn/utils/StackTrace.h"
+
+DECLARE_bool(celeborn_exception_user_stacktrace_enabled);
+DECLARE_bool(celeborn_exception_system_stacktrace_enabled);
+
+DECLARE_int32(celeborn_exception_user_stacktrace_rate_limit_ms);
+DECLARE_int32(celeborn_exception_system_stacktrace_rate_limit_ms);
+
+namespace celeborn {
+
+namespace error_source {
+using namespace folly::string_literals;
+
+// Errors where the root cause of the problem is either because of bad input
+// or an unsupported pattern of use are classified with source USER. Examples
+// of errors in this category include syntax errors, unavailable names or
+// objects.
+inline constexpr auto kErrorSourceUser = "USER"_fs;
+
+// Errors where the root cause of the problem is an unexpected internal state 
in
+// the system.
+inline constexpr auto kErrorSourceRuntime = "RUNTIME"_fs;
+
+// Errors where the root cause of the problem is some unreliable aspect of the
+// system are classified with source SYSTEM.
+inline constexpr auto kErrorSourceSystem = "SYSTEM"_fs;
+} // namespace error_source
+
+namespace error_code {
+using namespace folly::string_literals;
+
+//====================== User Error Codes ======================:
+
+// A generic user error code
+inline constexpr auto kGenericUserError = "GENERIC_USER_ERROR"_fs;
+
+// An error raised when an argument verification fails
+inline constexpr auto kInvalidArgument = "INVALID_ARGUMENT"_fs;
+
+// An error raised when a requested operation is not supported.
+inline constexpr auto kUnsupported = "UNSUPPORTED"_fs;
+
+// Arithmetic errors - underflow, overflow, divide by zero etc.
+inline constexpr auto kArithmeticError = "ARITHMETIC_ERROR"_fs;
+
+// Arithmetic errors - underflow, overflow, divide by zero etc.
+inline constexpr auto kSchemaMismatch = "SCHEMA_MISMATCH"_fs;
+
+//====================== Runtime Error Codes ======================:
+
+// An error raised when the current state of a component is invalid.
+inline constexpr auto kInvalidState = "INVALID_STATE"_fs;
+
+// An error raised when unreachable code point was executed.
+inline constexpr auto kUnreachableCode = "UNREACHABLE_CODE"_fs;
+
+// An error raised when a requested operation is not yet supported.
+inline constexpr auto kNotImplemented = "NOT_IMPLEMENTED"_fs;
+
+// An error raised when memory pool exceeds limits.
+inline constexpr auto kMemCapExceeded = "MEM_CAP_EXCEEDED"_fs;
+
+// An error raised when memory pool is aborted.
+inline constexpr auto kMemAborted = "MEM_ABORTED"_fs;
+
+// Error caused by memory allocation failure (inclusive of allocator memory cap
+// exceeded).
+inline constexpr auto kMemAllocError = "MEM_ALLOC_ERROR"_fs;
+
+// Error caused by failing to allocate cache buffer space for IO.
+inline constexpr auto kNoCacheSpace = "NO_CACHE_SPACE"_fs;
+
+// An error raised when spill bytes exceeds limits.
+inline constexpr auto kSpillLimitExceeded = "SPILL_LIMIT_EXCEEDED"_fs;
+
+// Errors indicating file read corruptions.
+inline constexpr auto kFileCorruption = "FILE_CORRUPTION"_fs;
+
+// Errors indicating file not found.
+inline constexpr auto kFileNotFound = "FILE_NOT_FOUND"_fs;
+
+// We do not know how to classify it yet.
+inline constexpr auto kUnknown = "UNKNOWN"_fs;
+} // namespace error_code
+
+class CelebornException : public std::exception {
+ public:
+  enum class Type { kUser = 0, kSystem = 1 };
+
+  CelebornException(
+      const char* file,
+      size_t line,
+      const char* function,
+      std::string_view expression,
+      std::string_view message,
+      std::string_view errorSource,
+      std::string_view errorCode,
+      bool isRetriable,
+      Type exceptionType = Type::kSystem,
+      std::string_view exceptionName = "CelebornException");
+
+  /// Wrap an std::exception.
+  CelebornException(
+      const std::exception_ptr& e,
+      std::string_view message,
+      std::string_view errorSource,
+      std::string_view errorCode,
+      bool isRetriable,
+      Type exceptionType = Type::kSystem,
+      std::string_view exceptionName = "CelebornException");
+
+  CelebornException(
+      const std::exception_ptr& e,
+      std::string_view message,
+      std::string_view errorSource,
+      bool isRetriable,
+      Type exceptionType = Type::kSystem,
+      std::string_view exceptionName = "CelebornException")
+      : CelebornException(
+            e,
+            message,
+            errorSource,
+            "",
+            isRetriable,
+            exceptionType,
+            exceptionName) {}
+
+  // Inherited
+  const char* what() const noexcept override {
+    return state_->what();
+  }
+
+  // Introduced nonvirtuals
+  const utils::StackTrace* stackTrace() const {
+    return state_->stackTrace.get();
+  }
+  const char* file() const {
+    return state_->file;
+  }
+  size_t line() const {
+    return state_->line;
+  }
+  const char* function() const {
+    return state_->function;
+  }
+  const std::string& failingExpression() const {
+    return state_->failingExpression;
+  }
+  const std::string& message() const {
+    return state_->message;
+  }
+
+  const std::string& errorCode() const {
+    return state_->errorCode;
+  }
+
+  const std::string& errorSource() const {
+    return state_->errorSource;
+  }
+
+  Type exceptionType() const {
+    return state_->exceptionType;
+  }
+
+  const std::string& exceptionName() const {
+    return state_->exceptionName;
+  }
+
+  bool isRetriable() const {
+    return state_->isRetriable;
+  }
+
+  bool isUserError() const {
+    return state_->errorSource == error_source::kErrorSourceUser;
+  }
+
+  const std::string& context() const {
+    return state_->context;
+  }
+
+  const std::string& topLevelContext() const {
+    return state_->topLevelContext;
+  }
+
+  const std::exception_ptr& wrappedException() const {
+    return state_->wrappedException;
+  }
+
+ private:
+  struct State {
+    std::unique_ptr<utils::StackTrace> stackTrace;
+    Type exceptionType = Type::kSystem;
+    std::string exceptionName;
+    const char* file = nullptr;
+    size_t line = 0;
+    const char* function = nullptr;
+    std::string failingExpression;
+    std::string message;
+    std::string errorSource;
+    std::string errorCode;
+    // The current exception context.
+    std::string context;
+    // The top-level ancestor of the current exception context.
+    std::string topLevelContext;
+    bool isRetriable;
+    // The original std::exception.
+    std::exception_ptr wrappedException;
+
+    mutable folly::once_flag once;
+    mutable std::string elaborateMessage;
+
+    template <typename F>
+    static std::shared_ptr<const State> make(Type exceptionType, F);
+
+    template <typename F>
+    static std::shared_ptr<const State> make(F f) {
+      auto state = std::make_shared<CelebornException::State>();
+      f(*state);
+      return state;
+    }
+
+    void finalize() const;
+
+    const char* what() const noexcept;
+  };
+
+  explicit CelebornException(std::shared_ptr<State const> state) noexcept
+      : state_(std::move(state)) {}
+
+  const std::shared_ptr<const State> state_;
+};
+
+class CelebornUserError : public CelebornException {
+ public:
+  CelebornUserError(
+      const char* file,
+      size_t line,
+      const char* function,
+      std::string_view expression,
+      std::string_view message,
+      std::string_view /* errorSource */,
+      std::string_view errorCode,
+      bool isRetriable,
+      std::string_view exceptionName = "CelebornUserError")
+      : CelebornException(
+            file,
+            line,
+            function,
+            expression,
+            message,
+            error_source::kErrorSourceUser,
+            errorCode,
+            isRetriable,
+            Type::kUser,
+            exceptionName) {}
+
+  /// Wrap an std::exception.
+  CelebornUserError(
+      const std::exception_ptr& e,
+      std::string_view message,
+      bool isRetriable,
+      std::string_view exceptionName = "CelebornUserError")
+      : CelebornException(
+            e,
+            message,
+            error_source::kErrorSourceUser,
+            error_code::kInvalidArgument,
+            isRetriable,
+            Type::kUser,
+            exceptionName) {}
+};
+
+class CelebornRuntimeError final : public CelebornException {
+ public:
+  CelebornRuntimeError(
+      const char* file,
+      size_t line,
+      const char* function,
+      std::string_view expression,
+      std::string_view message,
+      std::string_view /* errorSource */,
+      std::string_view errorCode,
+      bool isRetriable,
+      std::string_view exceptionName = "CelebornRuntimeError")
+      : CelebornException(
+            file,
+            line,
+            function,
+            expression,
+            message,
+            error_source::kErrorSourceRuntime,
+            errorCode,
+            isRetriable,
+            Type::kSystem,
+            exceptionName) {}
+
+  /// Wrap an std::exception.
+  CelebornRuntimeError(
+      const std::exception_ptr& e,
+      std::string_view message,
+      bool isRetriable,
+      std::string_view exceptionName = "CelebornRuntimeError")
+      : CelebornException(
+            e,
+            message,
+            error_source::kErrorSourceRuntime,
+            isRetriable,
+            Type::kSystem,
+            exceptionName) {}
+};
+
+/// Returns a reference to a thread level counter of Celeborn error throws.
+int64_t& threadNumCelebornThrow();
+
+/// Holds a pointer to a function that provides addition context to be
+/// added to the detailed error message in case of an exception.
+struct ExceptionContext {
+  using MessageFunction =
+      std::string (*)(CelebornException::Type exceptionType, void* arg);
+
+  /// Function to call in case of an exception to get additional context.
+  MessageFunction messageFunc{nullptr};
+
+  /// Value to pass to `messageFunc`. Can be null.
+  void* arg{nullptr};
+
+  /// Pointer to the parent context when there are hierarchical exception
+  /// contexts.
+  ExceptionContext* parent{nullptr};
+
+  /// Calls `messageFunc(arg)` and returns the result. Returns empty string if
+  /// `messageFunc` is null.
+  std::string message(CelebornException::Type exceptionType) {
+    if (!messageFunc || suspended) {
+      return "";
+    }
+
+    std::string theMessage;
+
+    try {
+      // Make sure not to call messageFunc again in case it throws.
+      suspended = true;
+      theMessage = messageFunc(exceptionType, arg);
+      suspended = false;
+    } catch (...) {
+      return "Failed to produce additional context.";
+    }
+
+    return theMessage;
+  }
+
+  bool suspended{false};
+};
+
+/// If exceptionPtr represents an std::exception, convert it to
+/// CelebornUserError to add useful context for debugging.
+std::exception_ptr toCelebornException(const std::exception_ptr& exceptionPtr);
+
+/// Returns a reference to thread_local variable that holds a function that can
+/// be used to get addition context to be added to the detailed error message 
in
+/// case an exception occurs. This is to used in cases when stack trace would
+/// not provide enough information, e.g. in case of hierarchical processing 
like
+/// expression evaluation.
+ExceptionContext& getExceptionContext();
+
+/// RAII class to set and restore context for exceptions. Links the new
+/// exception context with the previous context held by the thread_local
+/// variable to allow retrieving the top-level context when there is an
+/// exception context hierarchy.
+class ExceptionContextSetter {
+ public:
+  explicit ExceptionContextSetter(ExceptionContext value)
+      : prev_{getExceptionContext()} {
+    value.parent = &prev_;
+    getExceptionContext() = std::move(value);
+  }
+
+  ~ExceptionContextSetter() {
+    getExceptionContext() = std::move(prev_);
+  }
+
+ private:
+  ExceptionContext prev_;
+};
+} // namespace celeborn
diff --git a/cpp/celeborn/utils/flags.cpp b/cpp/celeborn/utils/flags.cpp
new file mode 100644
index 000000000..ab4b9ab9e
--- /dev/null
+++ b/cpp/celeborn/utils/flags.cpp
@@ -0,0 +1,49 @@
+/*
+ * Based on flags.cpp from Facebook Velox
+ *
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * Licensed 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.
+ */
+
+#include <gflags/gflags.h>
+
+/* Used in utils/CelebornException.cpp */
+
+DEFINE_bool(
+    celeborn_exception_user_stacktrace_enabled,
+    false,
+    "Enable the stacktrace for user type of CelebornException");
+
+DEFINE_bool(
+    celeborn_exception_system_stacktrace_enabled,
+    true,
+    "Enable the stacktrace for system type of CelebornException");
+
+DEFINE_int32(
+    celeborn_exception_user_stacktrace_rate_limit_ms,
+    0, // effectively turns off rate-limiting
+    "Min time interval in milliseconds between stack traces captured in"
+    " user type of CelebornException; off when set to 0 (the default)");
+
+DEFINE_int32(
+    celeborn_exception_system_stacktrace_rate_limit_ms,
+    0, // effectively turns off rate-limiting
+    "Min time interval in milliseconds between stack traces captured in"
+    " system type of CelebornException; off when set to 0 (the default)");
+
+/* Used in utils/ProcessBase.cpp */
+
+DEFINE_bool(celeborn_avx2, true, "Enables use of AVX2 when available");
+
+DEFINE_bool(celeborn_bmi2, true, "Enables use of BMI2 when available");

Reply via email to