]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
2 | // This source code is licensed under both the GPLv2 (found in the |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
7c673cae FG |
5 | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
6 | // Use of this source code is governed by a BSD-style license that can be | |
7 | // found in the LICENSE file. See the AUTHORS file for names of contributors. | |
8 | // | |
9 | // A Status encapsulates the result of an operation. It may indicate success, | |
10 | // or it may indicate an error with an associated error message. | |
11 | // | |
12 | // Multiple threads can invoke const methods on a Status without | |
13 | // external synchronization, but if any of the threads may call a | |
14 | // non-const method, all threads accessing the same Status must use | |
15 | // external synchronization. | |
16 | ||
11fdf7f2 | 17 | #pragma once |
7c673cae FG |
18 | |
19 | #include <string> | |
20 | #include "rocksdb/slice.h" | |
21 | ||
22 | namespace rocksdb { | |
23 | ||
24 | class Status { | |
25 | public: | |
26 | // Create a success status. | |
11fdf7f2 | 27 | Status() : code_(kOk), subcode_(kNone), sev_(kNoError), state_(nullptr) {} |
7c673cae FG |
28 | ~Status() { delete[] state_; } |
29 | ||
30 | // Copy the specified status. | |
31 | Status(const Status& s); | |
32 | Status& operator=(const Status& s); | |
33 | Status(Status&& s) | |
34 | #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900)) | |
35 | noexcept | |
36 | #endif | |
37 | ; | |
38 | Status& operator=(Status&& s) | |
39 | #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900)) | |
40 | noexcept | |
41 | #endif | |
42 | ; | |
43 | bool operator==(const Status& rhs) const; | |
44 | bool operator!=(const Status& rhs) const; | |
45 | ||
11fdf7f2 | 46 | enum Code : unsigned char { |
7c673cae FG |
47 | kOk = 0, |
48 | kNotFound = 1, | |
49 | kCorruption = 2, | |
50 | kNotSupported = 3, | |
51 | kInvalidArgument = 4, | |
52 | kIOError = 5, | |
53 | kMergeInProgress = 6, | |
54 | kIncomplete = 7, | |
55 | kShutdownInProgress = 8, | |
56 | kTimedOut = 9, | |
57 | kAborted = 10, | |
58 | kBusy = 11, | |
59 | kExpired = 12, | |
11fdf7f2 TL |
60 | kTryAgain = 13, |
61 | kCompactionTooLarge = 14 | |
7c673cae FG |
62 | }; |
63 | ||
64 | Code code() const { return code_; } | |
65 | ||
11fdf7f2 | 66 | enum SubCode : unsigned char { |
7c673cae FG |
67 | kNone = 0, |
68 | kMutexTimeout = 1, | |
69 | kLockTimeout = 2, | |
70 | kLockLimit = 3, | |
71 | kNoSpace = 4, | |
72 | kDeadlock = 5, | |
73 | kStaleFile = 6, | |
74 | kMemoryLimit = 7, | |
11fdf7f2 | 75 | kSpaceLimit = 8, |
494da23a | 76 | kPathNotFound = 9, |
7c673cae FG |
77 | kMaxSubCode |
78 | }; | |
79 | ||
80 | SubCode subcode() const { return subcode_; } | |
81 | ||
11fdf7f2 TL |
82 | enum Severity : unsigned char { |
83 | kNoError = 0, | |
84 | kSoftError = 1, | |
85 | kHardError = 2, | |
86 | kFatalError = 3, | |
87 | kUnrecoverableError = 4, | |
88 | kMaxSeverity | |
89 | }; | |
90 | ||
91 | Status(const Status& s, Severity sev); | |
92 | Severity severity() const { return sev_; } | |
93 | ||
7c673cae FG |
94 | // Returns a C style string indicating the message of the Status |
95 | const char* getState() const { return state_; } | |
96 | ||
97 | // Return a success status. | |
98 | static Status OK() { return Status(); } | |
99 | ||
100 | // Return error status of an appropriate type. | |
101 | static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) { | |
102 | return Status(kNotFound, msg, msg2); | |
103 | } | |
104 | // Fast path for not found without malloc; | |
105 | static Status NotFound(SubCode msg = kNone) { return Status(kNotFound, msg); } | |
106 | ||
107 | static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) { | |
108 | return Status(kCorruption, msg, msg2); | |
109 | } | |
110 | static Status Corruption(SubCode msg = kNone) { | |
111 | return Status(kCorruption, msg); | |
112 | } | |
113 | ||
114 | static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) { | |
115 | return Status(kNotSupported, msg, msg2); | |
116 | } | |
117 | static Status NotSupported(SubCode msg = kNone) { | |
118 | return Status(kNotSupported, msg); | |
119 | } | |
120 | ||
121 | static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) { | |
122 | return Status(kInvalidArgument, msg, msg2); | |
123 | } | |
124 | static Status InvalidArgument(SubCode msg = kNone) { | |
125 | return Status(kInvalidArgument, msg); | |
126 | } | |
127 | ||
128 | static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) { | |
129 | return Status(kIOError, msg, msg2); | |
130 | } | |
131 | static Status IOError(SubCode msg = kNone) { return Status(kIOError, msg); } | |
132 | ||
133 | static Status MergeInProgress(const Slice& msg, const Slice& msg2 = Slice()) { | |
134 | return Status(kMergeInProgress, msg, msg2); | |
135 | } | |
136 | static Status MergeInProgress(SubCode msg = kNone) { | |
137 | return Status(kMergeInProgress, msg); | |
138 | } | |
139 | ||
140 | static Status Incomplete(const Slice& msg, const Slice& msg2 = Slice()) { | |
141 | return Status(kIncomplete, msg, msg2); | |
142 | } | |
143 | static Status Incomplete(SubCode msg = kNone) { | |
144 | return Status(kIncomplete, msg); | |
145 | } | |
146 | ||
147 | static Status ShutdownInProgress(SubCode msg = kNone) { | |
148 | return Status(kShutdownInProgress, msg); | |
149 | } | |
150 | static Status ShutdownInProgress(const Slice& msg, | |
151 | const Slice& msg2 = Slice()) { | |
152 | return Status(kShutdownInProgress, msg, msg2); | |
153 | } | |
154 | static Status Aborted(SubCode msg = kNone) { return Status(kAborted, msg); } | |
155 | static Status Aborted(const Slice& msg, const Slice& msg2 = Slice()) { | |
156 | return Status(kAborted, msg, msg2); | |
157 | } | |
158 | ||
159 | static Status Busy(SubCode msg = kNone) { return Status(kBusy, msg); } | |
160 | static Status Busy(const Slice& msg, const Slice& msg2 = Slice()) { | |
161 | return Status(kBusy, msg, msg2); | |
162 | } | |
163 | ||
164 | static Status TimedOut(SubCode msg = kNone) { return Status(kTimedOut, msg); } | |
165 | static Status TimedOut(const Slice& msg, const Slice& msg2 = Slice()) { | |
166 | return Status(kTimedOut, msg, msg2); | |
167 | } | |
168 | ||
169 | static Status Expired(SubCode msg = kNone) { return Status(kExpired, msg); } | |
170 | static Status Expired(const Slice& msg, const Slice& msg2 = Slice()) { | |
171 | return Status(kExpired, msg, msg2); | |
172 | } | |
173 | ||
174 | static Status TryAgain(SubCode msg = kNone) { return Status(kTryAgain, msg); } | |
175 | static Status TryAgain(const Slice& msg, const Slice& msg2 = Slice()) { | |
176 | return Status(kTryAgain, msg, msg2); | |
177 | } | |
178 | ||
11fdf7f2 TL |
179 | static Status CompactionTooLarge(SubCode msg = kNone) { |
180 | return Status(kCompactionTooLarge, msg); | |
181 | } | |
182 | static Status CompactionTooLarge(const Slice& msg, | |
183 | const Slice& msg2 = Slice()) { | |
184 | return Status(kCompactionTooLarge, msg, msg2); | |
185 | } | |
186 | ||
7c673cae FG |
187 | static Status NoSpace() { return Status(kIOError, kNoSpace); } |
188 | static Status NoSpace(const Slice& msg, const Slice& msg2 = Slice()) { | |
189 | return Status(kIOError, kNoSpace, msg, msg2); | |
190 | } | |
191 | ||
192 | static Status MemoryLimit() { return Status(kAborted, kMemoryLimit); } | |
193 | static Status MemoryLimit(const Slice& msg, const Slice& msg2 = Slice()) { | |
194 | return Status(kAborted, kMemoryLimit, msg, msg2); | |
195 | } | |
196 | ||
11fdf7f2 TL |
197 | static Status SpaceLimit() { return Status(kIOError, kSpaceLimit); } |
198 | static Status SpaceLimit(const Slice& msg, const Slice& msg2 = Slice()) { | |
199 | return Status(kIOError, kSpaceLimit, msg, msg2); | |
200 | } | |
201 | ||
494da23a TL |
202 | static Status PathNotFound() { return Status(kIOError, kPathNotFound); } |
203 | static Status PathNotFound(const Slice& msg, const Slice& msg2 = Slice()) { | |
204 | return Status(kIOError, kPathNotFound, msg, msg2); | |
205 | } | |
206 | ||
7c673cae FG |
207 | // Returns true iff the status indicates success. |
208 | bool ok() const { return code() == kOk; } | |
209 | ||
210 | // Returns true iff the status indicates a NotFound error. | |
211 | bool IsNotFound() const { return code() == kNotFound; } | |
212 | ||
213 | // Returns true iff the status indicates a Corruption error. | |
214 | bool IsCorruption() const { return code() == kCorruption; } | |
215 | ||
216 | // Returns true iff the status indicates a NotSupported error. | |
217 | bool IsNotSupported() const { return code() == kNotSupported; } | |
218 | ||
219 | // Returns true iff the status indicates an InvalidArgument error. | |
220 | bool IsInvalidArgument() const { return code() == kInvalidArgument; } | |
221 | ||
222 | // Returns true iff the status indicates an IOError. | |
223 | bool IsIOError() const { return code() == kIOError; } | |
224 | ||
225 | // Returns true iff the status indicates an MergeInProgress. | |
226 | bool IsMergeInProgress() const { return code() == kMergeInProgress; } | |
227 | ||
228 | // Returns true iff the status indicates Incomplete | |
229 | bool IsIncomplete() const { return code() == kIncomplete; } | |
230 | ||
231 | // Returns true iff the status indicates Shutdown In progress | |
232 | bool IsShutdownInProgress() const { return code() == kShutdownInProgress; } | |
233 | ||
234 | bool IsTimedOut() const { return code() == kTimedOut; } | |
235 | ||
236 | bool IsAborted() const { return code() == kAborted; } | |
237 | ||
238 | bool IsLockLimit() const { | |
239 | return code() == kAborted && subcode() == kLockLimit; | |
240 | } | |
241 | ||
242 | // Returns true iff the status indicates that a resource is Busy and | |
243 | // temporarily could not be acquired. | |
244 | bool IsBusy() const { return code() == kBusy; } | |
245 | ||
246 | bool IsDeadlock() const { return code() == kBusy && subcode() == kDeadlock; } | |
247 | ||
248 | // Returns true iff the status indicated that the operation has Expired. | |
249 | bool IsExpired() const { return code() == kExpired; } | |
250 | ||
251 | // Returns true iff the status indicates a TryAgain error. | |
252 | // This usually means that the operation failed, but may succeed if | |
253 | // re-attempted. | |
254 | bool IsTryAgain() const { return code() == kTryAgain; } | |
255 | ||
11fdf7f2 TL |
256 | // Returns true iff the status indicates the proposed compaction is too large |
257 | bool IsCompactionTooLarge() const { return code() == kCompactionTooLarge; } | |
258 | ||
7c673cae FG |
259 | // Returns true iff the status indicates a NoSpace error |
260 | // This is caused by an I/O error returning the specific "out of space" | |
261 | // error condition. Stricto sensu, an NoSpace error is an I/O error | |
262 | // with a specific subcode, enabling users to take the appropriate action | |
263 | // if needed | |
264 | bool IsNoSpace() const { | |
265 | return (code() == kIOError) && (subcode() == kNoSpace); | |
266 | } | |
267 | ||
268 | // Returns true iff the status indicates a memory limit error. There may be | |
269 | // cases where we limit the memory used in certain operations (eg. the size | |
270 | // of a write batch) in order to avoid out of memory exceptions. | |
271 | bool IsMemoryLimit() const { | |
272 | return (code() == kAborted) && (subcode() == kMemoryLimit); | |
273 | } | |
274 | ||
494da23a TL |
275 | // Returns true iff the status indicates a PathNotFound error |
276 | // This is caused by an I/O error returning the specific "no such file or | |
277 | // directory" error condition. A PathNotFound error is an I/O error with | |
278 | // a specific subcode, enabling users to take appropriate action if necessary | |
279 | bool IsPathNotFound() const { | |
280 | return (code() == kIOError) && (subcode() == kPathNotFound); | |
281 | } | |
282 | ||
7c673cae FG |
283 | // Return a string representation of this status suitable for printing. |
284 | // Returns the string "OK" for success. | |
285 | std::string ToString() const; | |
286 | ||
287 | private: | |
288 | // A nullptr state_ (which is always the case for OK) means the message | |
289 | // is empty. | |
290 | // of the following form: | |
291 | // state_[0..3] == length of message | |
292 | // state_[4..] == message | |
293 | Code code_; | |
294 | SubCode subcode_; | |
11fdf7f2 | 295 | Severity sev_; |
7c673cae FG |
296 | const char* state_; |
297 | ||
7c673cae | 298 | explicit Status(Code _code, SubCode _subcode = kNone) |
11fdf7f2 | 299 | : code_(_code), subcode_(_subcode), sev_(kNoError), state_(nullptr) {} |
7c673cae FG |
300 | |
301 | Status(Code _code, SubCode _subcode, const Slice& msg, const Slice& msg2); | |
302 | Status(Code _code, const Slice& msg, const Slice& msg2) | |
303 | : Status(_code, kNone, msg, msg2) {} | |
304 | ||
305 | static const char* CopyState(const char* s); | |
306 | }; | |
307 | ||
494da23a TL |
308 | inline Status::Status(const Status& s) |
309 | : code_(s.code_), subcode_(s.subcode_), sev_(s.sev_) { | |
11fdf7f2 TL |
310 | state_ = (s.state_ == nullptr) ? nullptr : CopyState(s.state_); |
311 | } | |
312 | inline Status::Status(const Status& s, Severity sev) | |
494da23a | 313 | : code_(s.code_), subcode_(s.subcode_), sev_(sev) { |
7c673cae FG |
314 | state_ = (s.state_ == nullptr) ? nullptr : CopyState(s.state_); |
315 | } | |
316 | inline Status& Status::operator=(const Status& s) { | |
317 | // The following condition catches both aliasing (when this == &s), | |
318 | // and the common case where both s and *this are ok. | |
319 | if (this != &s) { | |
320 | code_ = s.code_; | |
321 | subcode_ = s.subcode_; | |
11fdf7f2 | 322 | sev_ = s.sev_; |
7c673cae FG |
323 | delete[] state_; |
324 | state_ = (s.state_ == nullptr) ? nullptr : CopyState(s.state_); | |
325 | } | |
326 | return *this; | |
327 | } | |
328 | ||
329 | inline Status::Status(Status&& s) | |
330 | #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900)) | |
331 | noexcept | |
332 | #endif | |
333 | : Status() { | |
334 | *this = std::move(s); | |
335 | } | |
336 | ||
337 | inline Status& Status::operator=(Status&& s) | |
338 | #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900)) | |
339 | noexcept | |
340 | #endif | |
341 | { | |
342 | if (this != &s) { | |
343 | code_ = std::move(s.code_); | |
344 | s.code_ = kOk; | |
345 | subcode_ = std::move(s.subcode_); | |
346 | s.subcode_ = kNone; | |
11fdf7f2 TL |
347 | sev_ = std::move(s.sev_); |
348 | s.sev_ = kNoError; | |
7c673cae FG |
349 | delete[] state_; |
350 | state_ = nullptr; | |
351 | std::swap(state_, s.state_); | |
352 | } | |
353 | return *this; | |
354 | } | |
355 | ||
356 | inline bool Status::operator==(const Status& rhs) const { | |
357 | return (code_ == rhs.code_); | |
358 | } | |
359 | ||
360 | inline bool Status::operator!=(const Status& rhs) const { | |
361 | return !(*this == rhs); | |
362 | } | |
363 | ||
364 | } // namespace rocksdb |