Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc(common): documentation improvements #11376

Merged
merged 2 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions google/cloud/doc/common-main.dox
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,28 @@ Client Libraries. Including:
values are stored asynchronously). They satisfy the API for `std::future` and
`std::promise`, and add support for callbacks and cancellation.

@warning The symbols in the `google::cloud::internal` namespace are
implementation details and subject to change and/or removal without notice.
@warning
@parblock
Some namespaces are reserved for implementation details and are subject to
change without notice. Do not use any symbols in these namespaces as your
application may break when trying to use future versions of the library.

@warning The symbols in the `google::cloud::testing_util` namespace are
implementation details and subject to change and/or removal without notice.
These namespaces include:

- Any namespace with `internal` in its name, including `google::cloud::internal`
and `google::cloud::rest_internal`.
- Any namespace with `testing` in its name, including
`google::cloud::testing_util`.
@endparblock

## More information

- @ref common-error-handling for more details about how the libraries report
run-time errors and how you can handle them.
- @ref options for information about configuring the client libraries at
runtime.
- @ref guac for more details about how to configure authentication in the client
libraries.
- @ref logging for information about enabling logging to the console in the
client libraries.
*/
224 changes: 221 additions & 3 deletions google/cloud/status.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,161 @@ enum class StatusCode {
/// Not an error; returned on success.
kOk = 0,

/// `kCancelled` (gRPC code `CANCELLED`) indicates the operation was
/// cancelled, typically by the caller.
kCancelled = 1,

/// `kUnknown` (gRPC code `UNKNOWN`) indicates an unknown error occurred.
///
/// In general, more specific errors should be raised, if possible. Errors
/// raised by APIs that do not return enough error information may be
/// converted to this error.
kUnknown = 2,

/// `kInvalidArgument` (gRPC code `INVALID_ARGUMENT`) indicates the caller
/// specified an invalid argument, such as a malformed filename.
///
/// Note that use of such errors should be narrowly limited to indicate the
/// invalid nature of the arguments themselves. Errors with validly formed
/// arguments that may cause errors with the state of the receiving system
/// should be denoted with `kFailedPrecondition` instead.
kInvalidArgument = 3,

/// `kDeadlineExceeded` (gRPC code `DEADLINE_EXCEEDED`) indicates a deadline
/// expired before the operation could complete.
///
/// For operations that may change state within a system, this error may be
/// returned even if the operation has completed successfully. For example, a
/// successful response from a server could have been delayed long enough for
/// the deadline to expire.
kDeadlineExceeded = 4,

/// `kNotFound` (gRPC code `NOT_FOUND`) indicates some requested entity (such
/// as a file or directory) was not found.
///
/// `kNotFound` is useful if a request should be denied for an entire class of
/// users, such as during a gradual feature rollout or undocumented allow
/// list.
/// If a request should be denied for specific sets of users, such as through
/// user-based access control, use `kPermissionDenied` instead.
kNotFound = 5,

/// `kAlreadyExists (gRPC code `ALREADY_EXISTS`) indicates that the entity a
/// caller attempted to create (such as a file or directory) is already
/// present.
kAlreadyExists = 6,

/// `kPermissionDenied` (gRPC code `PERMISSION_DENIED`) indicates that the
/// caller does not have permission to execute the specified operation.
///
/// Note that this error is different than an error due to an
/// *un*authenticated caller. This error code does not imply the request is
/// valid or the requested entity exists or satisfies any other
/// pre-conditions.
///
/// `kPermissionDenied` must not be used for rejections caused by exhausting
/// some resource. Instead, use `kResourceExhausted` for those errors.
/// `kPermissionDenied` must not be used if the caller cannot be identified.
/// Instead, use `kUnauthenticated` for those errors.
kPermissionDenied = 7,
kUnauthenticated = 16,

/// `kResourceExhausted` (gRPC code `RESOURCE_EXHAUSTED`) indicates some
/// resource has been exhausted.
///
/// Examples include a per-user quota, or the entire file system being out of
/// space.
kResourceExhausted = 8,

/// `kFailedPrecondition` (gRPC code `FAILED_PRECONDITION`) indicates that the
/// operation was rejected because the system is not in a state required for
/// the operation's execution.
///
/// For example, a directory to be deleted may be non-empty, a "rmdir"
/// operation is applied to a non-directory, etc.
///
/// Some guidelines that may help a service implementer in deciding between
/// `kFailedPrecondition`, `kAborted`, and `kUnavailable`:
///
/// 1. Use `kUnavailable` if the client can retry just the failing call.
/// 2. Use `kAborted` if the client should retry at a higher transaction
/// level (such as when a client-specified test-and-set fails, indicating
/// the client should restart a read-modify-write sequence).
/// 3. Use `kFailedPrecondition` if the client should not retry until the
/// system state has been explicitly fixed. For example, if a "rmdir" fails
/// because the directory is non-empty, `kFailedPrecondition` should be
/// returned since the client should not retry unless the files are deleted
/// from the directory.
kFailedPrecondition = 9,

/// `kAborted` (gRPC code `ABORTED`) indicates the operation was aborted.
///
/// This is typically due to a concurrency issue such as a sequencer check
/// failure or a failed transaction.
///
/// See the guidelines above for deciding between `kFailedPrecondition`,
/// `kAborted`, and `kUnavailable`.
kAborted = 10,

/// `kOutOfRange` (gRPC code `OUT_OF_RANGE`) indicates the operation was
/// attempted past the valid range, such as seeking or reading past an
/// end-of-file.
Comment on lines +135 to +136
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Those examples may not be best. The matching syscalls, for example, don't do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack. I am trying to follow the documentation from Abseil and gRPC. Getting creative (even if it improves correctness) seems risky.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack.

///
/// Unlike `kInvalidArgument`, this error indicates a problem that may
/// be fixed if the system state changes. For example, a 32-bit file
/// system will generate `kInvalidArgument` if asked to read at an
/// offset that is not in the range [0,2^32-1], but it will generate
/// `kOutOfRange` if asked to read from an offset past the current
/// file size.
///
/// There is a fair bit of overlap between `kFailedPrecondition` and
/// `kOutOfRange`. We recommend using `kOutOfRange` (the more specific
/// error) when it applies so that callers who are iterating through
/// a space can easily look for an `kOutOfRange` error to detect when
/// they are done.
kOutOfRange = 11,

/// `kUnimplemented` (gRPC code `UNIMPLEMENTED`) indicates the operation is
/// not implemented or supported in this service.
///
/// In this case, the operation should not be re-attempted.
kUnimplemented = 12,

/// `kInternal` (gRPC code `INTERNAL`) indicates an internal error has
/// occurred and some invariants expected by the underlying system have not
/// been satisfied.
///
/// While this error code is reserved for serious errors, some services return
/// this error under overload conditions.
kInternal = 13,

/// `kUnavailable` (gRPC code `UNAVAILABLE`) indicates the service is
/// currently unavailable and that this is most likely a transient condition.
///
/// An error such as this can be corrected by retrying with a backoff scheme.
/// Note that it is not always safe to retry non-idempotent operations.
///
/// See the guidelines above for deciding between `kFailedPrecondition`,
/// `kAborted`, and `kUnavailable`.
kUnavailable = 14,

/// `kDataLoss` (gRPC code `DATA_LOSS`) indicates that unrecoverable data loss
/// or corruption has occurred.
///
/// As this error is serious, proper alerting should be attached to errors
/// such as this.
kDataLoss = 15,

/// `kUnauthenticated` (gRPC code `UNAUTHENTICATED`) indicates that the
/// request does not have valid authentication credentials for the operation.
///
/// Correct the authentication and try again.
kUnauthenticated = 16,
};

/// Convert @p code to a human readable string.
std::string StatusCodeToString(StatusCode code);

/// Integration with `std::iostreams`.
std::ostream& operator<<(std::ostream& os, StatusCode code);

class Status;
Expand All @@ -70,15 +206,63 @@ absl::optional<std::string> GetPayload(Status const&, std::string const& key);
*/
class ErrorInfo {
public:
/**
* Default constructor.
*
* Post-condition: the `reason()`, `domain()`, and `metadata()` fields are
* empty.
*/
ErrorInfo() = default;

/**
* Constructor.
*
* @param reason initializes the `reason()` value.
* @param domain initializes the `domain()` value.
* @param metadata initializes the `metadata()` value.
*/
explicit ErrorInfo(std::string reason, std::string domain,
std::unordered_map<std::string, std::string> metadata)
: reason_(std::move(reason)),
domain_(std::move(domain)),
metadata_(std::move(metadata)) {}

/**
* The reason of the error.
*
* This is a constant value that identifies the proximate cause of the error.
* Error reasons are unique within a particular domain of errors. This should
* be at most 63 characters and match a regular expression of
* `[A-Z][A-Z0-9_]+[A-Z0-9]`, which represents UPPER_SNAKE_CASE.
*/
std::string const& reason() const { return reason_; }

/**
* The logical grouping to which the "reason" belongs.
*
* The error domain is typically the registered service name of the tool or
* product that generates the error. Example: "pubsub.googleapis.com". If the
* error is generated by some common infrastructure, the error domain must be
* a globally unique value that identifies the infrastructure. For Google API
* infrastructure, the error domain is "googleapis.com".
*
* For errors generated by the C++ client libraries the domain is
* `gcloud-cpp`.
*/
std::string const& domain() const { return domain_; }

/**
* Additional structured details about this error.
*
* Keys should match the regular expression `[a-zA-Z0-9-_]` and be limited
* to 64 characters in length.
*
* When identifying the current value of an exceeded limit, the units should
* be contained in the key, not the value. For example, if the client exceeds
* the number of instances that can be created in a single (batch) request
* return `{"instanceLimitPerRequest": "100"}` rather than
* `{"instanceLimit": "100/request"}`.
*/
std::unordered_map<std::string, std::string> const& metadata() const {
return metadata_;
}
Expand Down Expand Up @@ -110,23 +294,55 @@ class ErrorInfo {
*/
class Status {
public:
/// Default constructor, initializes to `StatusCode::kOk`.
Status();
/// Destructor.
~Status();
///@{
/**
* @name Copy construction and assignment.
*/
Status(Status const&);
Status& operator=(Status const&);
///@}
///@{
/**
* @name Move construction and assignment.
*/
Status(Status&&) noexcept;
Status& operator=(Status&&) noexcept;
///@}

/**
* Constructs a Status with the given @p code and @p message.
* Construct from a status code, message and (optional) error info.
*
* Ignores @p message if @p code is `StatusCode::kOk`.
* @param code the status code for the new `Status`.
* @param message the message for the new `Status`, ignored if @p code is
* `StatusCode::kOk`.
* @param info the `ErrorInfo` for the new `Status`, ignored if @p code is
* `SStatusCode::kOk`.
*/
explicit Status(StatusCode code, std::string message, ErrorInfo info = {});

/// Returns true if the status code is `StatusCode::kOk`.
bool ok() const { return !impl_; }

/// Returns the status code.
StatusCode code() const;

/**
* Returns the message associated with the status.
*
* This is always empty if `code()` is `StatusCode::kOk`.
*/
std::string const& message() const;

/**
* Returns the additional error info associated with the status.
*
* This is always a default-constructed error info if `code()` is
* `StatusCode::kOk`.
*/
ErrorInfo const& error_info() const;

friend inline bool operator==(Status const& a, Status const& b) {
Expand Down Expand Up @@ -160,8 +376,10 @@ std::ostream& operator<<(std::ostream& os, Status const& s);
*/
class RuntimeStatusError : public std::runtime_error {
public:
/// Constructor from a `Status`.
explicit RuntimeStatusError(Status status);

/// Returns the original status.
Status const& status() const { return status_; }

private:
Expand Down
7 changes: 5 additions & 2 deletions google/cloud/status_or.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
* Alternatively, you may call the `StatusOr::value()` member function,
* which is defined to: (1) throw an exception if there is no `T` value, or (2)
* crash the program if exceptions are disabled. It is never UB to call
* `.value()`.
* `value()`.
*
* @code
* StatusOr<Foo> foo = FetchFoo();
Expand Down Expand Up @@ -99,7 +99,7 @@ class StatusOr final {
using value_type = T;

/**
* Initializes with an error status (UNKNOWN).
* Initializes with an error status (`StatusCode::kUnknown`).
*/
StatusOr() : StatusOr(MakeDefaultStatus()) {}

Expand Down Expand Up @@ -178,7 +178,10 @@ class StatusOr final {
// NOLINTNEXTLINE(google-explicit-constructor)
StatusOr(T const& rhs) : value_(rhs) {}

/// Returns `true` when `this` holds a value.
bool ok() const { return status_.ok(); }

/// Returns `true` when `this` holds a value.
explicit operator bool() const { return status_.ok(); }

///@{
Expand Down