1 // Copyright (c) 2019-present, Facebook, Inc.  All rights reserved.
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).
5 //
6 // An IOStatus encapsulates the result of an operation.  It may indicate
7 // success, or it may indicate an error with an associated error message.
8 //
9 // Multiple threads can invoke const methods on an IOStatus without
10 // external synchronization, but if any of the threads may call a
11 // non-const method, all threads accessing the same IOStatus must use
12 // external synchronization.
13 
14 #pragma once
15 
16 #include <string>
17 #include "rocksdb/slice.h"
18 #ifdef OS_WIN
19 #include <string.h>
20 #endif
21 #include <cstring>
22 #include "status.h"
23 
24 namespace ROCKSDB_NAMESPACE {
25 
26 class IOStatus : public Status {
27  public:
28   using Code = Status::Code;
29   using SubCode = Status::SubCode;
30 
31   enum IOErrorScope {
32     kIOErrorScopeFileSystem,
33     kIOErrorScopeFile,
34     kIOErrorScopeRange,
35     kIOErrorScopeMax,
36   };
37 
38   // Create a success status.
IOStatus()39   IOStatus() : IOStatus(kOk, kNone) {}
~IOStatus()40   ~IOStatus() {}
41 
42   // Copy the specified status.
43   IOStatus(const IOStatus& s);
44   IOStatus& operator=(const IOStatus& s);
45   IOStatus(IOStatus&& s)
46 #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
47       noexcept
48 #endif
49       ;
50   IOStatus& operator=(IOStatus&& s)
51 #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
52       noexcept
53 #endif
54       ;
55   bool operator==(const IOStatus& rhs) const;
56   bool operator!=(const IOStatus& rhs) const;
57 
SetRetryable(bool retryable)58   void SetRetryable(bool retryable) { retryable_ = retryable; }
SetDataLoss(bool data_loss)59   void SetDataLoss(bool data_loss) { data_loss_ = data_loss; }
SetScope(IOErrorScope scope)60   void SetScope(IOErrorScope scope) { scope_ = scope; }
61 
GetRetryable()62   bool GetRetryable() const { return retryable_; }
GetDataLoss()63   bool GetDataLoss() const { return data_loss_; }
GetScope()64   IOErrorScope GetScope() const { return scope_; }
65 
66   // Return a success status.
OK()67   static IOStatus OK() { return IOStatus(); }
68 
69   static IOStatus NotSupported(const Slice& msg, const Slice& msg2 = Slice()) {
70     return IOStatus(kNotSupported, msg, msg2);
71   }
72   static IOStatus NotSupported(SubCode msg = kNone) {
73     return IOStatus(kNotSupported, msg);
74   }
75 
76   // Return error status of an appropriate type.
77   static IOStatus NotFound(const Slice& msg, const Slice& msg2 = Slice()) {
78     return IOStatus(kNotFound, msg, msg2);
79   }
80   // Fast path for not found without malloc;
81   static IOStatus NotFound(SubCode msg = kNone) {
82     return IOStatus(kNotFound, msg);
83   }
84 
85   static IOStatus Corruption(const Slice& msg, const Slice& msg2 = Slice()) {
86     return IOStatus(kCorruption, msg, msg2);
87   }
88   static IOStatus Corruption(SubCode msg = kNone) {
89     return IOStatus(kCorruption, msg);
90   }
91 
92   static IOStatus InvalidArgument(const Slice& msg,
93                                   const Slice& msg2 = Slice()) {
94     return IOStatus(kInvalidArgument, msg, msg2);
95   }
96   static IOStatus InvalidArgument(SubCode msg = kNone) {
97     return IOStatus(kInvalidArgument, msg);
98   }
99 
100   static IOStatus IOError(const Slice& msg, const Slice& msg2 = Slice()) {
101     return IOStatus(kIOError, msg, msg2);
102   }
103   static IOStatus IOError(SubCode msg = kNone) {
104     return IOStatus(kIOError, msg);
105   }
106 
107   static IOStatus Busy(SubCode msg = kNone) { return IOStatus(kBusy, msg); }
108   static IOStatus Busy(const Slice& msg, const Slice& msg2 = Slice()) {
109     return IOStatus(kBusy, msg, msg2);
110   }
111 
112   static IOStatus TimedOut(SubCode msg = kNone) {
113     return IOStatus(kTimedOut, msg);
114   }
115   static IOStatus TimedOut(const Slice& msg, const Slice& msg2 = Slice()) {
116     return IOStatus(kTimedOut, msg, msg2);
117   }
118 
NoSpace()119   static IOStatus NoSpace() { return IOStatus(kIOError, kNoSpace); }
120   static IOStatus NoSpace(const Slice& msg, const Slice& msg2 = Slice()) {
121     return IOStatus(kIOError, kNoSpace, msg, msg2);
122   }
123 
PathNotFound()124   static IOStatus PathNotFound() { return IOStatus(kIOError, kPathNotFound); }
125   static IOStatus PathNotFound(const Slice& msg, const Slice& msg2 = Slice()) {
126     return IOStatus(kIOError, kPathNotFound, msg, msg2);
127   }
128 
129   // Return a string representation of this status suitable for printing.
130   // Returns the string "OK" for success.
131   // std::string ToString() const;
132 
133  private:
134   friend IOStatus status_to_io_status(Status&&);
135   bool retryable_;
136   bool data_loss_;
137   IOErrorScope scope_;
138 
139   explicit IOStatus(Code _code, SubCode _subcode = kNone)
Status(_code,_subcode)140       : Status(_code, _subcode),
141         retryable_(false),
142         data_loss_(false),
143         scope_(kIOErrorScopeFileSystem) {}
144 
145   IOStatus(Code _code, SubCode _subcode, const Slice& msg, const Slice& msg2);
IOStatus(Code _code,const Slice & msg,const Slice & msg2)146   IOStatus(Code _code, const Slice& msg, const Slice& msg2)
147       : IOStatus(_code, kNone, msg, msg2) {}
148 };
149 
IOStatus(Code _code,SubCode _subcode,const Slice & msg,const Slice & msg2)150 inline IOStatus::IOStatus(Code _code, SubCode _subcode, const Slice& msg,
151                           const Slice& msg2)
152     : Status(_code, _subcode),
153       retryable_(false),
154       data_loss_(false),
155       scope_(kIOErrorScopeFileSystem) {
156   assert(code_ != kOk);
157   assert(subcode_ != kMaxSubCode);
158   const size_t len1 = msg.size();
159   const size_t len2 = msg2.size();
160   const size_t size = len1 + (len2 ? (2 + len2) : 0);
161   char* const result = new char[size + 1];  // +1 for null terminator
162   memcpy(result, msg.data(), len1);
163   if (len2) {
164     result[len1] = ':';
165     result[len1 + 1] = ' ';
166     memcpy(result + len1 + 2, msg2.data(), len2);
167   }
168   result[size] = '\0';  // null terminator for C style string
169   state_ = result;
170 }
171 
IOStatus(const IOStatus & s)172 inline IOStatus::IOStatus(const IOStatus& s) : Status(s.code_, s.subcode_) {
173   retryable_ = s.retryable_;
174   data_loss_ = s.data_loss_;
175   scope_ = s.scope_;
176   state_ = (s.state_ == nullptr) ? nullptr : CopyState(s.state_);
177 }
178 inline IOStatus& IOStatus::operator=(const IOStatus& s) {
179   // The following condition catches both aliasing (when this == &s),
180   // and the common case where both s and *this are ok.
181   if (this != &s) {
182     code_ = s.code_;
183     subcode_ = s.subcode_;
184     retryable_ = s.retryable_;
185     data_loss_ = s.data_loss_;
186     scope_ = s.scope_;
187     delete[] state_;
188     state_ = (s.state_ == nullptr) ? nullptr : CopyState(s.state_);
189   }
190   return *this;
191 }
192 
IOStatus(IOStatus && s)193 inline IOStatus::IOStatus(IOStatus&& s)
194 #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
195     noexcept
196 #endif
197     : IOStatus() {
198   *this = std::move(s);
199 }
200 
201 inline IOStatus& IOStatus::operator=(IOStatus&& s)
202 #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
203     noexcept
204 #endif
205 {
206   if (this != &s) {
207     code_ = std::move(s.code_);
208     s.code_ = kOk;
209     subcode_ = std::move(s.subcode_);
210     s.subcode_ = kNone;
211     retryable_ = s.retryable_;
212     data_loss_ = s.data_loss_;
213     scope_ = s.scope_;
214     scope_ = kIOErrorScopeFileSystem;
215     delete[] state_;
216     state_ = nullptr;
217     std::swap(state_, s.state_);
218   }
219   return *this;
220 }
221 
222 inline bool IOStatus::operator==(const IOStatus& rhs) const {
223   return (code_ == rhs.code_);
224 }
225 
226 inline bool IOStatus::operator!=(const IOStatus& rhs) const {
227   return !(*this == rhs);
228 }
229 
status_to_io_status(Status && status)230 inline IOStatus status_to_io_status(Status&& status) {
231   if (status.ok()) {
232     // Fast path
233     return IOStatus::OK();
234   } else {
235     const char* state = status.getState();
236     if (state) {
237       return IOStatus(status.code(), status.subcode(),
238                       Slice(state, strlen(status.getState()) + 1), Slice());
239     } else {
240       return IOStatus(status.code(), status.subcode());
241     }
242   }
243 }
244 
245 }  // namespace ROCKSDB_NAMESPACE
246