1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <iosfwd> 34 #include <string> 35 36 #include "mongo/base/error_codes.h" 37 #include "mongo/platform/atomic_word.h" 38 #include "mongo/platform/compiler.h" 39 40 namespace mongoutils { 41 namespace str { 42 class stream; 43 } // namespace str 44 } // namespace mongoutils 45 46 namespace mongo { 47 48 /** 49 * Status represents an error state or the absence thereof. 50 * 51 * A Status uses the standardized error codes -- from file 'error_codes.h' -- to 52 * determine an error's cause. It further clarifies the error with a textual 53 * description. 54 * 55 * Example usage: 56 * 57 * Status sumAB(int a, int b, int* c) { 58 * if (overflowIfSum(a,b)) { 59 * return Status(ErrorCodes::ERROR_OVERFLOW, "overflow in sumAB", 16494); 60 * } 61 * 62 * *c = a+b; 63 * return Status::OK(); 64 * } 65 */ 66 class MONGO_WARN_UNUSED_RESULT_CLASS Status { 67 public: 68 // Short-hand for returning an OK status. 69 static inline Status OK(); 70 71 /** 72 * Builds an error status given the error code and a textual description of what 73 * caused the error. 74 * 75 * For OK Statuses prefer using Status::OK(). If code is OK, the remaining arguments are 76 * ignored. 77 * 78 * For adding context to the reason string, use withContext/addContext rather than making a new 79 * Status manually. 80 */ 81 MONGO_COMPILER_COLD_FUNCTION Status(ErrorCodes::Error code, std::string reason); 82 MONGO_COMPILER_COLD_FUNCTION Status(ErrorCodes::Error code, const char* reason); 83 MONGO_COMPILER_COLD_FUNCTION Status(ErrorCodes::Error code, StringData reason); 84 MONGO_COMPILER_COLD_FUNCTION Status(ErrorCodes::Error code, 85 const mongoutils::str::stream& reason); 86 87 inline Status(const Status& other); 88 inline Status& operator=(const Status& other); 89 90 inline Status(Status&& other) noexcept; 91 inline Status& operator=(Status&& other) noexcept; 92 93 inline ~Status(); 94 95 /** 96 * Returns a new Status with the same data as this, but with the reason string prefixed with 97 * reasonPrefix and our standard " :: caused by :: " separator. The new reason is not visible to 98 * any other Statuses that share the same ErrorInfo object. 99 * 100 * No-op when called on an OK status. 101 */ 102 Status withContext(StringData reasonPrefix) const; addContext(StringData reasonPrefix)103 void addContext(StringData reasonPrefix) { 104 *this = this->withContext(reasonPrefix); 105 } 106 107 /** 108 * Only compares codes. Ignores reason strings. 109 */ 110 bool operator==(const Status& other) const { 111 return code() == other.code(); 112 } 113 bool operator!=(const Status& other) const { 114 return !(*this == other); 115 } 116 117 /** 118 * Compares this Status's code with an error code. 119 */ 120 bool operator==(const ErrorCodes::Error other) const { 121 return code() == other; 122 } 123 bool operator!=(const ErrorCodes::Error other) const { 124 return !(*this == other); 125 } 126 127 // 128 // accessors 129 // 130 131 inline bool isOK() const; 132 133 inline ErrorCodes::Error code() const; 134 135 inline std::string codeString() const; 136 137 138 /** 139 * Returns the reason string or the empty string if isOK(). 140 */ reason()141 const std::string& reason() const { 142 if (_error) 143 return _error->reason; 144 145 static const std::string empty; 146 return empty; 147 } 148 149 std::string toString() const; 150 151 /** 152 * Returns true if this Status's code is a member of the given category. 153 */ 154 template <ErrorCategory category> isA()155 bool isA() const { 156 return ErrorCodes::isA<category>(code()); 157 } 158 159 /** 160 * Call this method to indicate that it is your intention to ignore a returned status. Ignoring 161 * is only possible if the value being ignored is an xvalue -- it is not appropriate to create a 162 * status variable and then ignore it. 163 */ ignore()164 inline void ignore() && noexcept {} 165 inline void ignore() const& noexcept = delete; 166 167 /** 168 * This method is a transitional tool, to facilitate transition to compile-time enforced status 169 * checking. 170 * 171 * NOTE: DO NOT ADD NEW CALLS TO THIS METHOD. This method serves the same purpose as 172 * `.ignore()`; however, it indicates a situation where the code that presently ignores a status 173 * code has not been audited for correctness. This method will be removed at some point. If you 174 * encounter a compiler error from ignoring the result of a status-returning function be sure to 175 * check the return value, or deliberately ignore the return value. 176 */ transitional_ignore()177 inline void transitional_ignore() && noexcept {}; 178 inline void transitional_ignore() const& noexcept = delete; 179 180 // 181 // Below interface used for testing code only. 182 // 183 184 inline AtomicUInt32::WordType refCount() const; 185 186 private: 187 inline Status(); 188 189 struct ErrorInfo { 190 AtomicUInt32 refs; // reference counter 191 const ErrorCodes::Error code; // error code 192 const std::string reason; // description of error cause 193 194 static ErrorInfo* create(ErrorCodes::Error code, std::string reason); 195 196 ErrorInfo(ErrorCodes::Error code, std::string reason); 197 }; 198 199 ErrorInfo* _error; 200 201 /** 202 * Increment/Decrement the reference counter inside an ErrorInfo 203 * 204 * @param error ErrorInfo to be incremented 205 */ 206 static inline void ref(ErrorInfo* error); 207 static inline void unref(ErrorInfo* error); 208 }; 209 210 inline bool operator==(const ErrorCodes::Error lhs, const Status& rhs); 211 212 inline bool operator!=(const ErrorCodes::Error lhs, const Status& rhs); 213 214 std::ostream& operator<<(std::ostream& os, const Status& status); 215 216 } // namespace mongo 217 218 #include "mongo/base/status-inl.h" 219