Added GRPC_ERROR_IS_ABSEIL_STATUS (#26078)

Added GRPC_ERROR_IS_ABSEIL_STATUS
pull/26115/head
Esun Kim 4 years ago committed by GitHub
parent ff9ece1588
commit f27a41db43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      include/grpc/impl/codegen/port_platform.h
  2. 94
      src/core/lib/gprpp/status_helper.cc
  3. 72
      src/core/lib/gprpp/status_helper.h
  4. 120
      src/core/lib/iomgr/error.cc
  5. 266
      src/core/lib/iomgr/error.h
  6. 4
      src/core/lib/iomgr/error_internal.h
  7. 38
      test/core/gprpp/status_helper_test.cc

@ -34,6 +34,11 @@
#define GPR_ABSEIL_SYNC 1
#endif // GPR_ABSEIL_SYNC
/*
* Defines GRPC_ERROR_IS_ABSEIL_STATUS to use absl::Status for grpc_error_handle
*/
// #define GRPC_ERROR_IS_ABSEIL_STATUS 1
/* Get windows.h included everywhere (we need it) */
#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
#ifndef WIN32_LEAN_AND_MEAN

@ -43,35 +43,35 @@ const absl::string_view kChildrenPropertyUrl = TYPE_URL("children");
const char* GetStatusIntPropertyUrl(StatusIntProperty key) {
switch (key) {
case StatusIntProperty::ERRNO:
case StatusIntProperty::kErrorNo:
return TYPE_URL("errno");
case StatusIntProperty::FILE_LINE:
case StatusIntProperty::kFileLine:
return TYPE_URL("file_line");
case StatusIntProperty::STREAM_ID:
case StatusIntProperty::kStreamId:
return TYPE_URL("stream_id");
case StatusIntProperty::GRPC_STATUS:
case StatusIntProperty::kRpcStatus:
return TYPE_URL("grpc_status");
case StatusIntProperty::OFFSET:
case StatusIntProperty::kOffset:
return TYPE_URL("offset");
case StatusIntProperty::INDEX:
case StatusIntProperty::kIndex:
return TYPE_URL("index");
case StatusIntProperty::SIZE:
case StatusIntProperty::kSize:
return TYPE_URL("size");
case StatusIntProperty::HTTP2_ERROR:
case StatusIntProperty::kHttp2Error:
return TYPE_URL("http2_error");
case StatusIntProperty::TSI_CODE:
case StatusIntProperty::kTsiCode:
return TYPE_URL("tsi_code");
case StatusIntProperty::FD:
return TYPE_URL("fd");
case StatusIntProperty::WSA_ERROR:
case StatusIntProperty::kWsaError:
return TYPE_URL("wsa_error");
case StatusIntProperty::HTTP_STATUS:
case StatusIntProperty::kFd:
return TYPE_URL("fd");
case StatusIntProperty::kHttpStatus:
return TYPE_URL("http_status");
case StatusIntProperty::OCCURRED_DURING_WRITE:
case StatusIntProperty::kOccurredDuringWrite:
return TYPE_URL("occurred_during_write");
case StatusIntProperty::CHANNEL_CONNECTIVITY_STATE:
case StatusIntProperty::ChannelConnectivityState:
return TYPE_URL("channel_connectivity_state");
case StatusIntProperty::LB_POLICY_DROP:
case StatusIntProperty::kLbPolicyDrop:
return TYPE_URL("lb_policy_drop");
}
GPR_UNREACHABLE_CODE(return "unknown");
@ -79,29 +79,29 @@ const char* GetStatusIntPropertyUrl(StatusIntProperty key) {
const char* GetStatusStrPropertyUrl(StatusStrProperty key) {
switch (key) {
case StatusStrProperty::KEY:
return TYPE_URL("key");
case StatusStrProperty::VALUE:
return TYPE_URL("value");
case StatusStrProperty::DESCRIPTION:
case StatusStrProperty::kDescription:
return TYPE_URL("description");
case StatusStrProperty::OS_ERROR:
case StatusStrProperty::kFile:
return TYPE_URL("file");
case StatusStrProperty::kOsError:
return TYPE_URL("os_error");
case StatusStrProperty::TARGET_ADDRESS:
return TYPE_URL("target_address");
case StatusStrProperty::SYSCALL:
case StatusStrProperty::kSyscall:
return TYPE_URL("syscall");
case StatusStrProperty::FILE:
return TYPE_URL("file");
case StatusStrProperty::GRPC_MESSAGE:
case StatusStrProperty::kTargetAddress:
return TYPE_URL("target_address");
case StatusStrProperty::kGrpcMessage:
return TYPE_URL("grpc_message");
case StatusStrProperty::RAW_BYTES:
case StatusStrProperty::kRawBytes:
return TYPE_URL("raw_bytes");
case StatusStrProperty::TSI_ERROR:
case StatusStrProperty::kTsiError:
return TYPE_URL("tsi_error");
case StatusStrProperty::FILENAME:
case StatusStrProperty::kFilename:
return TYPE_URL("filename");
case StatusStrProperty::CREATED_TIME:
case StatusStrProperty::kKey:
return TYPE_URL("key");
case StatusStrProperty::kValue:
return TYPE_URL("value");
case StatusStrProperty::kCreatedTime:
return TYPE_URL("created_time");
}
GPR_UNREACHABLE_CODE(return "unknown");
@ -145,13 +145,13 @@ absl::Status StatusCreate(absl::StatusCode code, absl::string_view msg,
std::initializer_list<absl::Status> children) {
absl::Status s(code, msg);
if (location.file() != nullptr) {
StatusSetStr(&s, StatusStrProperty::FILE, location.file());
StatusSetStr(&s, StatusStrProperty::kFile, location.file());
}
if (location.line() != -1) {
StatusSetInt(&s, StatusIntProperty::FILE_LINE, location.line());
StatusSetInt(&s, StatusIntProperty::kFileLine, location.line());
}
absl::Time now = grpc_core::ToAbslTime(gpr_now(GPR_CLOCK_REALTIME));
StatusSetStr(&s, StatusStrProperty::CREATED_TIME, absl::FormatTime(now));
StatusSetStr(&s, StatusStrProperty::kCreatedTime, absl::FormatTime(now));
for (const absl::Status& child : children) {
if (!child.ok()) {
StatusAddChild(&s, child);
@ -315,6 +315,30 @@ absl::Status StatusFromProto(google_rpc_Status* msg) {
return status;
}
uintptr_t StatusAllocPtr(absl::Status s) {
// This relies the fact that absl::Status has only one member, StatusRep*
// so the sizeof(absl::Status) has the same size of intptr_t and StatusRep*
// can be stolen using placement allocation.
static_assert(sizeof(intptr_t) == sizeof(absl::Status),
"absl::Status should be as big as intptr_t");
// This does two things;
// 1. Copies StatusRep* of absl::Status to ptr
// 2. Increases the counter of StatusRep if it's not inlined
uintptr_t ptr;
new (&ptr) absl::Status(s);
return ptr;
}
void StatusFreePtr(uintptr_t ptr) {
// Decreases the counter of StatusRep if it's not inlined.
reinterpret_cast<absl::Status*>(&ptr)->~Status();
}
absl::Status StatusGetFromPtr(uintptr_t ptr) {
// Constructs Status from ptr having the address of StatusRep.
return *reinterpret_cast<absl::Status*>(&ptr);
}
} // namespace internal
} // namespace grpc_core

@ -32,67 +32,67 @@ namespace grpc_core {
// TODO(veblush): Use camel-case names once migration to absl::Status is done.
enum class StatusIntProperty {
/// 'errno' from the operating system
ERRNO,
kErrorNo,
/// __LINE__ from the call site creating the error
FILE_LINE,
kFileLine,
/// stream identifier: for errors that are associated with an individual
/// wire stream
STREAM_ID,
kStreamId,
/// grpc status code representing this error
// TODO(veblush): Remove this after grpc_error is replaced with absl::Status
GRPC_STATUS,
kRpcStatus,
/// offset into some binary blob (usually represented by
/// RAW_BYTES) where the error occurred
OFFSET,
kOffset,
/// context sensitive index associated with the error
INDEX,
kIndex,
/// context sensitive size associated with the error
SIZE,
kSize,
/// http2 error code associated with the error (see the HTTP2 RFC)
HTTP2_ERROR,
kHttp2Error,
/// TSI status code associated with the error
TSI_CODE,
kTsiCode,
/// WSAGetLastError() reported when this error occurred
WSA_ERROR,
kWsaError,
/// File descriptor associated with this error
FD,
kFd,
/// HTTP status (i.e. 404)
HTTP_STATUS,
kHttpStatus,
/// chttp2: did the error occur while a write was in progress
OCCURRED_DURING_WRITE,
kOccurredDuringWrite,
/// channel connectivity state associated with the error
CHANNEL_CONNECTIVITY_STATE,
ChannelConnectivityState,
/// LB policy drop
LB_POLICY_DROP,
kLbPolicyDrop,
};
/// This enum should have the same value of grpc_error_strs
// TODO(veblush): Use camel-case names once migration to absl::Status is done.
enum class StatusStrProperty {
/// top-level textual description of this error
DESCRIPTION,
kDescription,
/// source file in which this error occurred
FILE,
kFile,
/// operating system description of this error
OS_ERROR,
kOsError,
/// syscall that generated this error
SYSCALL,
kSyscall,
/// peer that we were trying to communicate when this error occurred
TARGET_ADDRESS,
kTargetAddress,
/// grpc status message associated with this error
GRPC_MESSAGE,
kGrpcMessage,
/// hex dump (or similar) with the data that generated this error
RAW_BYTES,
kRawBytes,
/// tsi error string associated with this error
TSI_ERROR,
kTsiError,
/// filename that we were trying to read/write when this error occurred
FILENAME,
kFilename,
/// key associated with the error
KEY,
kKey,
/// value associated with the error
VALUE,
kValue,
/// time string to create the error
CREATED_TIME,
kCreatedTime,
};
/// Creates a status with given additional information
@ -136,10 +136,26 @@ namespace internal {
google_rpc_Status* StatusToProto(absl::Status status,
upb_arena* arena) GRPC_MUST_USE_RESULT;
/// Build a status from a upb message, google_rpc_Status
/// Builds a status from a upb message, google_rpc_Status
/// This is for internal implementation & test only
absl::Status StatusFromProto(google_rpc_Status* msg) GRPC_MUST_USE_RESULT;
/// The same value of grpc_core::internal::StatusAllocPtr(absl::OkStatus())
static constexpr uintptr_t kOkStatusPtr = 0;
/// Returns ptr where the given status is copied into.
/// This ptr can be used to get Status later and should be freed by
/// StatusFreePtr. This shouldn't be used except migration purpose.
uintptr_t StatusAllocPtr(absl::Status s);
/// Frees the allocated status at ptr.
/// This shouldn't be used except migration purpose.
void StatusFreePtr(uintptr_t ptr);
/// Get the status from ptr.
/// This shouldn't be used except migration purpose.
absl::Status StatusGetFromPtr(uintptr_t ptr);
} // namespace internal
} // namespace grpc_core

@ -41,6 +41,114 @@ grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount(false,
"error_refcount");
grpc_core::DebugOnlyTraceFlag grpc_trace_closure(false, "closure");
static gpr_atm g_error_creation_allowed = true;
void grpc_disable_error_creation() {
gpr_atm_no_barrier_store(&g_error_creation_allowed, false);
}
void grpc_enable_error_creation() {
gpr_atm_no_barrier_store(&g_error_creation_allowed, true);
}
#ifdef GRPC_ERROR_IS_ABSEIL_STATUS
absl::Status grpc_status_create(absl::StatusCode code, absl::string_view msg,
const grpc_core::DebugLocation& location,
size_t children_count, absl::Status* children) {
absl::Status s = StatusCreate(code, msg, location, {});
for (size_t i = 0; i < children_count; ++i) {
if (!children[i].ok()) {
StatusAddChild(&s, children[i]);
}
}
return s;
}
std::string grpc_error_std_string(const absl::Status& error) {
return grpc_core::StatusToString(error);
}
absl::Status grpc_os_error(const grpc_core::DebugLocation& location, int err,
const char* call_name) {
absl::Status s =
StatusCreate(absl::StatusCode::kUnknown, "OS Error", location, {});
grpc_core::StatusSetInt(&s, grpc_core::StatusIntProperty::ERRNO, err);
grpc_core::StatusSetStr(&s, grpc_core::StatusStrProperty::OS_ERROR,
strerror(err));
grpc_core::StatusSetStr(&s, grpc_core::StatusStrProperty::SYSCALL, call_name);
return s;
}
#ifdef GPR_WINDOWS
absl::Status grpc_wsa_error(const grpc_core::DebugLocation& location, int err,
const char* call_name) {
char* utf8_message = gpr_format_message(err);
absl::Status s =
StatusCreate(absl::StatusCode::kUnknown, "WSA Error", location, {});
StatusSetInt(&s, StatusIntProperty::WSA_ERROR, err);
StatusSetStr(&s, StatusStrProperty::OS_ERROR, utf8_message);
StatusSetStr(&s, StatusStrProperty::SYSCALL, call_name);
}
#endif
grpc_error_handle grpc_error_set_int(grpc_error_handle src,
grpc_error_ints which, intptr_t value) {
grpc_core::StatusSetInt(
&src, static_cast<grpc_core::StatusIntProperty>(which), value);
return src;
}
bool grpc_error_get_int(grpc_error_handle error, grpc_error_ints which,
intptr_t* p) {
absl::optional<intptr_t> value = grpc_core::StatusGetInt(
error, static_cast<grpc_core::StatusIntProperty>(which));
if (value.has_value()) {
*p = *value;
return true;
} else {
return false;
}
}
grpc_error_handle grpc_error_set_str(grpc_error_handle src,
grpc_error_strs which,
const grpc_slice& str) {
grpc_core::StatusSetStr(
&src, static_cast<grpc_core::StatusStrProperty>(which),
std::string(reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(str)),
GRPC_SLICE_LENGTH(str)));
return src;
}
bool grpc_error_get_str(grpc_error_handle error, grpc_error_strs which,
grpc_slice* s) {
absl::optional<std::string> value = grpc_core::StatusGetStr(
error, static_cast<grpc_core::StatusStrProperty>(which));
if (value.has_value()) {
*s = grpc_slice_from_copied_buffer(value->c_str(), value->size());
return true;
} else {
return false;
}
}
grpc_error_handle grpc_error_add_child(grpc_error_handle src,
grpc_error_handle child) {
grpc_core::StatusAddChild(&src, child);
return src;
}
bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
int line) {
GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what,
grpc_core::StatusToString(error).c_str());
return false;
}
#else // GRPC_ERROR_IS_ABSEIL_STATUS
static const char* error_int_name(grpc_error_ints key) {
switch (key) {
case GRPC_ERROR_INT_ERRNO:
@ -304,16 +412,6 @@ static void internal_add_error(grpc_error_handle* err,
// It is very common to include and extra int and string in an error
#define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
static gpr_atm g_error_creation_allowed = true;
void grpc_disable_error_creation() {
gpr_atm_no_barrier_store(&g_error_creation_allowed, false);
}
void grpc_enable_error_creation() {
gpr_atm_no_barrier_store(&g_error_creation_allowed, true);
}
grpc_error_handle grpc_error_create(const char* file, int line,
const grpc_slice& desc,
grpc_error_handle* referencing,
@ -821,3 +919,5 @@ bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
GRPC_ERROR_UNREF(error);
return false;
}
#endif // GRPC_ERROR_IS_ABSEIL_STATUS

@ -30,49 +30,70 @@
#include <grpc/support/time.h>
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/status_helper.h"
#include "absl/status/status.h"
/// Opaque representation of an error.
/// See https://github.com/grpc/grpc/blob/master/doc/core/grpc-error.md for a
/// full write up of this object.
#ifdef GRPC_ERROR_IS_ABSEIL_STATUS
typedef absl::Status grpc_error_handle;
#else // GRPC_ERROR_IS_ABSEIL_STATUS
typedef struct grpc_error grpc_error;
typedef grpc_error* grpc_error_handle;
extern grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount;
#endif // GRPC_ERROR_IS_ABSEIL_STATUS
typedef enum {
/// 'errno' from the operating system
GRPC_ERROR_INT_ERRNO,
GRPC_ERROR_INT_ERRNO =
static_cast<int>(grpc_core::StatusIntProperty::kErrorNo),
/// __LINE__ from the call site creating the error
GRPC_ERROR_INT_FILE_LINE,
GRPC_ERROR_INT_FILE_LINE =
static_cast<int>(grpc_core::StatusIntProperty::kFileLine),
/// stream identifier: for errors that are associated with an individual
/// wire stream
GRPC_ERROR_INT_STREAM_ID,
GRPC_ERROR_INT_STREAM_ID =
static_cast<int>(grpc_core::StatusIntProperty::kStreamId),
/// grpc status code representing this error
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_ERROR_INT_GRPC_STATUS =
static_cast<int>(grpc_core::StatusIntProperty::kRpcStatus),
/// offset into some binary blob (usually represented by
/// GRPC_ERROR_STR_RAW_BYTES) where the error occurred
GRPC_ERROR_INT_OFFSET,
GRPC_ERROR_INT_OFFSET =
static_cast<int>(grpc_core::StatusIntProperty::kOffset),
/// context sensitive index associated with the error
GRPC_ERROR_INT_INDEX,
GRPC_ERROR_INT_INDEX = static_cast<int>(grpc_core::StatusIntProperty::kIndex),
/// context sensitive size associated with the error
GRPC_ERROR_INT_SIZE,
GRPC_ERROR_INT_SIZE = static_cast<int>(grpc_core::StatusIntProperty::kSize),
/// http2 error code associated with the error (see the HTTP2 RFC)
GRPC_ERROR_INT_HTTP2_ERROR,
GRPC_ERROR_INT_HTTP2_ERROR =
static_cast<int>(grpc_core::StatusIntProperty::kHttp2Error),
/// TSI status code associated with the error
GRPC_ERROR_INT_TSI_CODE,
GRPC_ERROR_INT_TSI_CODE =
static_cast<int>(grpc_core::StatusIntProperty::kTsiCode),
/// WSAGetLastError() reported when this error occurred
GRPC_ERROR_INT_WSA_ERROR,
GRPC_ERROR_INT_WSA_ERROR =
static_cast<int>(grpc_core::StatusIntProperty::kWsaError),
/// File descriptor associated with this error
GRPC_ERROR_INT_FD,
GRPC_ERROR_INT_FD = static_cast<int>(grpc_core::StatusIntProperty::kFd),
/// HTTP status (i.e. 404)
GRPC_ERROR_INT_HTTP_STATUS,
GRPC_ERROR_INT_HTTP_STATUS =
static_cast<int>(grpc_core::StatusIntProperty::kHttpStatus),
/// chttp2: did the error occur while a write was in progress
GRPC_ERROR_INT_OCCURRED_DURING_WRITE,
GRPC_ERROR_INT_OCCURRED_DURING_WRITE =
static_cast<int>(grpc_core::StatusIntProperty::kOccurredDuringWrite),
/// channel connectivity state associated with the error
GRPC_ERROR_INT_CHANNEL_CONNECTIVITY_STATE,
GRPC_ERROR_INT_CHANNEL_CONNECTIVITY_STATE =
static_cast<int>(grpc_core::StatusIntProperty::ChannelConnectivityState),
/// LB policy drop
GRPC_ERROR_INT_LB_POLICY_DROP,
GRPC_ERROR_INT_LB_POLICY_DROP =
static_cast<int>(grpc_core::StatusIntProperty::kLbPolicyDrop),
/// Must always be last
GRPC_ERROR_INT_MAX,
@ -80,27 +101,35 @@ typedef enum {
typedef enum {
/// top-level textual description of this error
GRPC_ERROR_STR_DESCRIPTION,
GRPC_ERROR_STR_DESCRIPTION =
static_cast<int>(grpc_core::StatusStrProperty::kDescription),
/// source file in which this error occurred
GRPC_ERROR_STR_FILE,
GRPC_ERROR_STR_FILE = static_cast<int>(grpc_core::StatusStrProperty::kFile),
/// operating system description of this error
GRPC_ERROR_STR_OS_ERROR,
GRPC_ERROR_STR_OS_ERROR =
static_cast<int>(grpc_core::StatusStrProperty::kOsError),
/// syscall that generated this error
GRPC_ERROR_STR_SYSCALL,
GRPC_ERROR_STR_SYSCALL =
static_cast<int>(grpc_core::StatusStrProperty::kSyscall),
/// peer that we were trying to communicate when this error occurred
GRPC_ERROR_STR_TARGET_ADDRESS,
GRPC_ERROR_STR_TARGET_ADDRESS =
static_cast<int>(grpc_core::StatusStrProperty::kTargetAddress),
/// grpc status message associated with this error
GRPC_ERROR_STR_GRPC_MESSAGE,
GRPC_ERROR_STR_GRPC_MESSAGE =
static_cast<int>(grpc_core::StatusStrProperty::kGrpcMessage),
/// hex dump (or similar) with the data that generated this error
GRPC_ERROR_STR_RAW_BYTES,
GRPC_ERROR_STR_RAW_BYTES =
static_cast<int>(grpc_core::StatusStrProperty::kRawBytes),
/// tsi error string associated with this error
GRPC_ERROR_STR_TSI_ERROR,
GRPC_ERROR_STR_TSI_ERROR =
static_cast<int>(grpc_core::StatusStrProperty::kTsiError),
/// filename that we were trying to read/write when this error occurred
GRPC_ERROR_STR_FILENAME,
GRPC_ERROR_STR_FILENAME =
static_cast<int>(grpc_core::StatusStrProperty::kFilename),
/// key associated with the error
GRPC_ERROR_STR_KEY,
GRPC_ERROR_STR_KEY = static_cast<int>(grpc_core::StatusStrProperty::kKey),
/// value associated with the error
GRPC_ERROR_STR_VALUE,
GRPC_ERROR_STR_VALUE = static_cast<int>(grpc_core::StatusStrProperty::kValue),
/// Must always be last
GRPC_ERROR_STR_MAX,
@ -114,6 +143,84 @@ typedef enum {
GRPC_ERROR_TIME_MAX,
} grpc_error_times;
// DEPRECATED: Use grpc_error_std_string instead
const char* grpc_error_string(grpc_error_handle error);
std::string grpc_error_std_string(grpc_error_handle error);
// debug only toggles that allow for a sanity to check that ensures we will
// never create any errors in the per-RPC hotpath.
void grpc_disable_error_creation();
void grpc_enable_error_creation();
#ifdef GRPC_ERROR_IS_ABSEIL_STATUS
#define GRPC_ERROR_NONE absl::OkStatus()
#define GRPC_ERROR_OOM absl::Status(absl::ResourceExhaustedError)
#define GRPC_ERROR_CANCELLED absl::CancelledError()
#define GRPC_ERROR_REF(err) (err)
#define GRPC_ERROR_UNREF(err)
#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc) \
StatusCreate(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, {})
#define GRPC_ERROR_CREATE_FROM_COPIED_STRING(desc) \
StatusCreate(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, {})
#define GRPC_ERROR_CREATE_FROM_STRING_VIEW(desc) \
StatusCreate(ababsl::StatusCode::kUnknown, desc, DEBUG_LOCATION, {})
absl::Status grpc_status_create(absl::StatusCode code, absl::string_view msg,
const grpc_core::DebugLocation& location,
size_t children_count,
absl::Status* children) GRPC_MUST_USE_RESULT;
// Create an error that references some other errors. This function adds a
// reference to each error in errs - it does not consume an existing reference
#define GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(desc, errs, count) \
grpc_status_create(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, count, \
errs)
#define GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(desc, errs, count) \
grpc_status_create(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION, count, \
errs)
// Consumes all the errors in the vector and forms a referencing error from
// them. If the vector is empty, return GRPC_ERROR_NONE.
template <typename VectorType>
static absl::Status grpc_status_create_from_vector(
const grpc_core::DebugLocation& location, const char* desc,
VectorType* error_list) {
absl::Status error = GRPC_ERROR_NONE;
if (error_list->size() != 0) {
error = grpc_status_create(absl::StatusCode::kUnknown, desc, DEBUG_LOCATION,
error_list->size(), error_list->data());
error_list->clear();
}
return error;
}
#define GRPC_ERROR_CREATE_FROM_VECTOR(desc, error_list) \
grpc_status_create_from_vector(DEBUG_LOCATION, desc, error_list)
absl::Status grpc_os_error(const grpc_core::DebugLocation& location, int err,
const char* call_name) GRPC_MUST_USE_RESULT;
inline absl::Status grpc_assert_never_ok(absl::Status error) {
GPR_ASSERT(error != GRPC_ERROR_NONE);
return error;
}
/// create an error associated with errno!=0 (an 'operating system' error)
#define GRPC_OS_ERROR(err, call_name) \
grpc_assert_never_ok(grpc_os_error(DEBUG_LOCATION, err, call_name))
absl::Status grpc_wsa_error(const grpc_core::DebugLocation& location, int err,
const char* call_name) GRPC_MUST_USE_RESULT;
/// windows only: create an error associated with WSAGetLastError()!=0
#define GRPC_WSA_ERROR(err, call_name) \
grpc_wsa_error(DEBUG_LOCATION, err, call_name)
#else // GRPC_ERROR_IS_ABSEIL_STATUS
/// The following "special" errors can be propagated without allocating memory.
/// They are always even so that other code (particularly combiner locks,
/// polling engines) can safely use the lower bit for themselves.
@ -129,14 +236,36 @@ inline bool grpc_error_is_special(grpc_error_handle err) {
return err <= GRPC_ERROR_SPECIAL_MAX;
}
// debug only toggles that allow for a sanity to check that ensures we will
// never create any errors in the per-RPC hotpath.
void grpc_disable_error_creation();
void grpc_enable_error_creation();
// DEPRECATED: Use grpc_error_std_string instead
const char* grpc_error_string(grpc_error_handle error);
std::string grpc_error_std_string(grpc_error_handle error);
#ifndef NDEBUG
grpc_error_handle grpc_error_do_ref(grpc_error_handle err, const char* file,
int line);
void grpc_error_do_unref(grpc_error_handle err, const char* file, int line);
inline grpc_error_handle grpc_error_ref(grpc_error_handle err, const char* file,
int line) {
if (grpc_error_is_special(err)) return err;
return grpc_error_do_ref(err, file, line);
}
inline void grpc_error_unref(grpc_error_handle err, const char* file,
int line) {
if (grpc_error_is_special(err)) return;
grpc_error_do_unref(err, file, line);
}
#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err, __FILE__, __LINE__)
#else
grpc_error_handle grpc_error_do_ref(grpc_error_handle err);
void grpc_error_do_unref(grpc_error_handle err);
inline grpc_error_handle grpc_error_ref(grpc_error_handle err) {
if (grpc_error_is_special(err)) return err;
return grpc_error_do_ref(err);
}
inline void grpc_error_unref(grpc_error_handle err) {
if (grpc_error_is_special(err)) return;
grpc_error_do_unref(err);
}
#define GRPC_ERROR_REF(err) grpc_error_ref(err)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
#endif
/// Create an error - but use GRPC_ERROR_CREATE instead
grpc_error_handle grpc_error_create(const char* file, int line,
@ -174,37 +303,6 @@ grpc_error_handle grpc_error_create(const char* file, int line,
#define GRPC_ERROR_CREATE_FROM_VECTOR(desc, error_list) \
grpc_error_create_from_vector(__FILE__, __LINE__, desc, error_list)
#ifndef NDEBUG
grpc_error_handle grpc_error_do_ref(grpc_error_handle err, const char* file,
int line);
void grpc_error_do_unref(grpc_error_handle err, const char* file, int line);
inline grpc_error_handle grpc_error_ref(grpc_error_handle err, const char* file,
int line) {
if (grpc_error_is_special(err)) return err;
return grpc_error_do_ref(err, file, line);
}
inline void grpc_error_unref(grpc_error_handle err, const char* file,
int line) {
if (grpc_error_is_special(err)) return;
grpc_error_do_unref(err, file, line);
}
#define GRPC_ERROR_REF(err) grpc_error_ref(err, __FILE__, __LINE__)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err, __FILE__, __LINE__)
#else
grpc_error_handle grpc_error_do_ref(grpc_error_handle err);
void grpc_error_do_unref(grpc_error_handle err);
inline grpc_error_handle grpc_error_ref(grpc_error_handle err) {
if (grpc_error_is_special(err)) return err;
return grpc_error_do_ref(err);
}
inline void grpc_error_unref(grpc_error_handle err) {
if (grpc_error_is_special(err)) return;
grpc_error_do_unref(err);
}
#define GRPC_ERROR_REF(err) grpc_error_ref(err)
#define GRPC_ERROR_UNREF(err) grpc_error_unref(err)
#endif
// Consumes all the errors in the vector and forms a referencing error from
// them. If the vector is empty, return GRPC_ERROR_NONE.
template <typename VectorType>
@ -225,6 +323,25 @@ static grpc_error_handle grpc_error_create_from_vector(const char* file,
return error;
}
grpc_error_handle grpc_os_error(const char* file, int line, int err,
const char* call_name) GRPC_MUST_USE_RESULT;
inline grpc_error_handle grpc_assert_never_ok(grpc_error_handle error) {
GPR_ASSERT(error != GRPC_ERROR_NONE);
return error;
}
/// create an error associated with errno!=0 (an 'operating system' error)
#define GRPC_OS_ERROR(err, call_name) \
grpc_assert_never_ok(grpc_os_error(__FILE__, __LINE__, err, call_name))
grpc_error_handle grpc_wsa_error(const char* file, int line, int err,
const char* call_name) GRPC_MUST_USE_RESULT;
/// windows only: create an error associated with WSAGetLastError()!=0
#define GRPC_WSA_ERROR(err, call_name) \
grpc_wsa_error(__FILE__, __LINE__, err, call_name)
#endif // GRPC_ERROR_IS_ABSEIL_STATUS
grpc_error_handle grpc_error_set_int(grpc_error_handle src,
grpc_error_ints which,
intptr_t value) GRPC_MUST_USE_RESULT;
@ -256,23 +373,6 @@ bool grpc_error_get_str(grpc_error_handle error, grpc_error_strs which,
grpc_error_handle grpc_error_add_child(
grpc_error_handle src, grpc_error_handle child) GRPC_MUST_USE_RESULT;
grpc_error_handle grpc_os_error(const char* file, int line, int err,
const char* call_name) GRPC_MUST_USE_RESULT;
inline grpc_error_handle grpc_assert_never_ok(grpc_error_handle error) {
GPR_ASSERT(error != GRPC_ERROR_NONE);
return error;
}
/// create an error associated with errno!=0 (an 'operating system' error)
#define GRPC_OS_ERROR(err, call_name) \
grpc_assert_never_ok(grpc_os_error(__FILE__, __LINE__, err, call_name))
grpc_error_handle grpc_wsa_error(const char* file, int line, int err,
const char* call_name) GRPC_MUST_USE_RESULT;
/// windows only: create an error associated with WSAGetLastError()!=0
#define GRPC_WSA_ERROR(err, call_name) \
grpc_wsa_error(__FILE__, __LINE__, err, call_name)
bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
int line);
inline bool grpc_log_if_error(const char* what, grpc_error_handle error,

@ -27,6 +27,8 @@
#include <grpc/support/sync.h>
#include "src/core/lib/iomgr/error.h"
#ifndef GRPC_ERROR_IS_ABSEIL_STATUS
typedef struct grpc_linked_error grpc_linked_error;
struct grpc_linked_error {
@ -58,4 +60,6 @@ struct grpc_error {
intptr_t arena[0];
};
#endif // GRPC_ERROR_IS_ABSEIL_STATUS
#endif /* GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H */

@ -33,36 +33,36 @@ TEST(StatusUtilTest, CreateStatus) {
EXPECT_EQ(absl::StatusCode::kUnknown, s.code());
EXPECT_EQ("Test", s.message());
#ifndef NDEBUG
EXPECT_EQ(true, StatusGetStr(s, StatusStrProperty::FILE).has_value());
EXPECT_EQ(true, StatusGetInt(s, StatusIntProperty::FILE_LINE).has_value());
EXPECT_EQ(true, StatusGetStr(s, StatusStrProperty::kFile).has_value());
EXPECT_EQ(true, StatusGetInt(s, StatusIntProperty::kFileLine).has_value());
#endif
EXPECT_EQ(true, StatusGetStr(s, StatusStrProperty::CREATED_TIME).has_value());
EXPECT_EQ(true, StatusGetStr(s, StatusStrProperty::kCreatedTime).has_value());
EXPECT_THAT(StatusGetChildren(s),
::testing::ElementsAre(absl::CancelledError()));
}
TEST(StatusUtilTest, SetAndGetInt) {
absl::Status s = absl::CancelledError();
StatusSetInt(&s, StatusIntProperty::ERRNO, 2021);
EXPECT_EQ(2021, StatusGetInt(s, StatusIntProperty::ERRNO));
StatusSetInt(&s, StatusIntProperty::kErrorNo, 2021);
EXPECT_EQ(2021, StatusGetInt(s, StatusIntProperty::kErrorNo));
}
TEST(StatusUtilTest, GetIntNotExistent) {
absl::Status s = absl::CancelledError();
EXPECT_EQ(absl::optional<intptr_t>(),
StatusGetInt(s, StatusIntProperty::ERRNO));
StatusGetInt(s, StatusIntProperty::kErrorNo));
}
TEST(StatusUtilTest, SetAndGetStr) {
absl::Status s = absl::CancelledError();
StatusSetStr(&s, StatusStrProperty::OS_ERROR, "value");
EXPECT_EQ("value", StatusGetStr(s, StatusStrProperty::OS_ERROR));
StatusSetStr(&s, StatusStrProperty::kOsError, "value");
EXPECT_EQ("value", StatusGetStr(s, StatusStrProperty::kOsError));
}
TEST(StatusUtilTest, GetStrNotExistent) {
absl::Status s = absl::CancelledError();
EXPECT_EQ(absl::optional<std::string>(),
StatusGetStr(s, StatusStrProperty::OS_ERROR));
StatusGetStr(s, StatusStrProperty::kOsError));
}
TEST(StatusUtilTest, AddAndGetChildren) {
@ -76,8 +76,8 @@ TEST(StatusUtilTest, AddAndGetChildren) {
TEST(StatusUtilTest, ToAndFromProto) {
absl::Status s = absl::CancelledError("Message");
StatusSetInt(&s, StatusIntProperty::ERRNO, 2021);
StatusSetStr(&s, StatusStrProperty::OS_ERROR, "value");
StatusSetInt(&s, StatusIntProperty::kErrorNo, 2021);
StatusSetStr(&s, StatusStrProperty::kOsError, "value");
upb::Arena arena;
google_rpc_Status* msg = internal::StatusToProto(s, arena.ptr());
absl::Status s2 = internal::StatusFromProto(msg);
@ -98,18 +98,18 @@ TEST(StatusUtilTest, CancelledErrorToString) {
TEST(StatusUtilTest, ComplexErrorToString) {
absl::Status s = absl::CancelledError("Message");
StatusSetInt(&s, StatusIntProperty::ERRNO, 2021);
StatusSetInt(&s, StatusIntProperty::kErrorNo, 2021);
std::string t = StatusToString(s);
EXPECT_EQ("CANCELLED:Message {errno:\"2021\"}", t);
}
TEST(StatusUtilTest, ComplexErrorWithChildrenToString) {
absl::Status s = absl::CancelledError("Message");
StatusSetInt(&s, StatusIntProperty::ERRNO, 2021);
StatusSetInt(&s, StatusIntProperty::kErrorNo, 2021);
absl::Status s1 = absl::AbortedError("Message1");
StatusAddChild(&s, s1);
absl::Status s2 = absl::AlreadyExistsError("Message2");
StatusSetStr(&s2, StatusStrProperty::OS_ERROR, "value");
StatusSetStr(&s2, StatusStrProperty::kOsError, "value");
StatusAddChild(&s, s2);
std::string t = StatusToString(s);
EXPECT_EQ(
@ -118,6 +118,16 @@ TEST(StatusUtilTest, ComplexErrorWithChildrenToString) {
t);
}
TEST(StatusUtilTest, AllocPtr) {
absl::Status statuses[] = {absl::OkStatus(), absl::CancelledError(),
absl::AbortedError("Message")};
for (const auto& s : statuses) {
uintptr_t p = internal::StatusAllocPtr(s);
EXPECT_EQ(s, internal::StatusGetFromPtr(p));
internal::StatusFreePtr(p);
}
}
} // namespace
} // namespace grpc_core

Loading…
Cancel
Save