提交 66a91e26 编写于 作者: E Edouard A 提交者: Siying Dong

Add NoSpace subcode to IOError (#1320)

Add a sub code to distinguish "out of space" errors from regular I/O errors
上级 67036c04
...@@ -111,6 +111,7 @@ TEST_F(DBIOFailureTest, NoSpaceCompactRange) { ...@@ -111,6 +111,7 @@ TEST_F(DBIOFailureTest, NoSpaceCompactRange) {
Status s = dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr, Status s = dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
true /* disallow trivial move */); true /* disallow trivial move */);
ASSERT_TRUE(s.IsIOError()); ASSERT_TRUE(s.IsIOError());
ASSERT_TRUE(s.IsNoSpace());
env_->no_space_.store(false, std::memory_order_release); env_->no_space_.store(false, std::memory_order_release);
} while (ChangeCompactOptions()); } while (ChangeCompactOptions());
......
...@@ -221,7 +221,7 @@ class SpecialEnv : public EnvWrapper { ...@@ -221,7 +221,7 @@ class SpecialEnv : public EnvWrapper {
// Drop writes on the floor // Drop writes on the floor
return Status::OK(); return Status::OK();
} else if (env_->no_space_.load(std::memory_order_acquire)) { } else if (env_->no_space_.load(std::memory_order_acquire)) {
return Status::IOError("No space left on device"); return Status::NoSpace("No space left on device");
} else { } else {
env_->bytes_written_ += data.size(); env_->bytes_written_ += data.size();
return base_->Append(data); return base_->Append(data);
......
...@@ -33,14 +33,14 @@ class Status { ...@@ -33,14 +33,14 @@ class Status {
Status& operator=(const Status& s); Status& operator=(const Status& s);
Status(Status&& s) Status(Status&& s)
#if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900)) #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
noexcept noexcept
#endif #endif
; ;
Status& operator=(Status&& s) Status& operator=(Status&& s)
#if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900)) #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
noexcept noexcept
#endif #endif
; ;
bool operator==(const Status& rhs) const; bool operator==(const Status& rhs) const;
bool operator!=(const Status& rhs) const; bool operator!=(const Status& rhs) const;
...@@ -58,7 +58,7 @@ class Status { ...@@ -58,7 +58,7 @@ class Status {
kAborted = 10, kAborted = 10,
kBusy = 11, kBusy = 11,
kExpired = 12, kExpired = 12,
kTryAgain = 13, kTryAgain = 13
}; };
Code code() const { return code_; } Code code() const { return code_; }
...@@ -68,6 +68,7 @@ class Status { ...@@ -68,6 +68,7 @@ class Status {
kMutexTimeout = 1, kMutexTimeout = 1,
kLockTimeout = 2, kLockTimeout = 2,
kLockLimit = 3, kLockLimit = 3,
kNoSpace = 4,
kMaxSubCode kMaxSubCode
}; };
...@@ -157,6 +158,11 @@ class Status { ...@@ -157,6 +158,11 @@ class Status {
return Status(kTryAgain, msg, msg2); return Status(kTryAgain, msg, msg2);
} }
static Status NoSpace() { return Status(kIOError, kNoSpace); }
static Status NoSpace(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kIOError, kNoSpace, msg, msg2);
}
// Returns true iff the status indicates success. // Returns true iff the status indicates success.
bool ok() const { return code() == kOk; } bool ok() const { return code() == kOk; }
...@@ -200,6 +206,15 @@ class Status { ...@@ -200,6 +206,15 @@ class Status {
// re-attempted. // re-attempted.
bool IsTryAgain() const { return code() == kTryAgain; } bool IsTryAgain() const { return code() == kTryAgain; }
// Returns true iff the status indicates a NoSpace error
// This is caused by an I/O error returning the specific "out of space"
// error condition. Stricto sensu, an NoSpace error is an I/O error
// with a specific subcode, enabling users to take the appropriate action
// if needed
bool IsNoSpace() const {
return (code() == kIOError) && (subcode() == kNoSpace);
}
// Return a string representation of this status suitable for printing. // Return a string representation of this status suitable for printing.
// Returns the string "OK" for success. // Returns the string "OK" for success.
std::string ToString() const; std::string ToString() const;
...@@ -219,7 +234,10 @@ class Status { ...@@ -219,7 +234,10 @@ class Status {
explicit Status(Code _code, SubCode _subcode = kNone) explicit Status(Code _code, SubCode _subcode = kNone)
: code_(_code), subcode_(_subcode), state_(nullptr) {} : code_(_code), subcode_(_subcode), state_(nullptr) {}
Status(Code _code, const Slice& msg, const Slice& msg2); Status(Code _code, SubCode _subcode, const Slice& msg, const Slice& msg2);
Status(Code _code, const Slice& msg, const Slice& msg2)
: Status(_code, kNone, msg, msg2) {}
static const char* CopyState(const char* s); static const char* CopyState(const char* s);
}; };
...@@ -229,7 +247,7 @@ inline Status::Status(const Status& s) : code_(s.code_), subcode_(s.subcode_) { ...@@ -229,7 +247,7 @@ inline Status::Status(const Status& s) : code_(s.code_), subcode_(s.subcode_) {
inline Status& Status::operator=(const Status& s) { inline Status& Status::operator=(const Status& s) {
// The following condition catches both aliasing (when this == &s), // The following condition catches both aliasing (when this == &s),
// and the common case where both s and *this are ok. // and the common case where both s and *this are ok.
if(this != &s) { if (this != &s) {
code_ = s.code_; code_ = s.code_;
subcode_ = s.subcode_; subcode_ = s.subcode_;
delete[] state_; delete[] state_;
...@@ -240,23 +258,23 @@ inline Status& Status::operator=(const Status& s) { ...@@ -240,23 +258,23 @@ inline Status& Status::operator=(const Status& s) {
inline Status::Status(Status&& s) inline Status::Status(Status&& s)
#if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900)) #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
noexcept noexcept
#endif #endif
: Status() { : Status() {
*this = std::move(s); *this = std::move(s);
} }
inline Status& Status::operator=(Status&& s) inline Status& Status::operator=(Status&& s)
#if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900)) #if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
noexcept noexcept
#endif #endif
{ {
if(this != &s) { if (this != &s) {
code_ = std::move(s.code_); code_ = std::move(s.code_);
s.code_ = kOk; s.code_ = kOk;
subcode_ = std::move(s.subcode_); subcode_ = std::move(s.subcode_);
s.subcode_ = kNone; s.subcode_ = kNone;
delete [] state_; delete[] state_;
state_ = nullptr; state_ = nullptr;
std::swap(state_, s.state_); std::swap(state_, s.state_);
} }
......
...@@ -26,7 +26,9 @@ namespace port { ...@@ -26,7 +26,9 @@ namespace port {
std::string GetWindowsErrSz(DWORD err); std::string GetWindowsErrSz(DWORD err);
inline Status IOErrorFromWindowsError(const std::string& context, DWORD err) { inline Status IOErrorFromWindowsError(const std::string& context, DWORD err) {
return Status::IOError(context, GetWindowsErrSz(err)); return (err == ERROR_HANDLE_DISK_FULL) ?
Status::NoSpace(context, GetWindowsErrSz(err)) :
Status::IOError(context, GetWindowsErrSz(err));
} }
inline Status IOErrorFromLastWindowsError(const std::string& context) { inline Status IOErrorFromLastWindowsError(const std::string& context) {
...@@ -34,7 +36,9 @@ inline Status IOErrorFromLastWindowsError(const std::string& context) { ...@@ -34,7 +36,9 @@ inline Status IOErrorFromLastWindowsError(const std::string& context) {
} }
inline Status IOError(const std::string& context, int err_number) { inline Status IOError(const std::string& context, int err_number) {
return Status::IOError(context, strerror(err_number)); return (err_number == ENOSPC) ?
Status::NoSpace(context, strerror(err_number)) :
Status::IOError(context, strerror(err_number));
} }
// Note the below two do not set errno because they are used only here in this // Note the below two do not set errno because they are used only here in this
......
...@@ -36,7 +36,9 @@ namespace { ...@@ -36,7 +36,9 @@ namespace {
// Log error message // Log error message
static Status IOError(const std::string& context, int err_number) { static Status IOError(const std::string& context, int err_number) {
return Status::IOError(context, strerror(err_number)); return (err_number == ENOSPC) ?
Status::NoSpace(context, strerror(err_number)) :
Status::IOError(context, strerror(err_number));
} }
// assume that there is one global logger for now. It is not thread-safe, // assume that there is one global logger for now. It is not thread-safe,
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#pragma once #pragma once
#include <unistd.h> #include <unistd.h>
#include <atomic> #include <atomic>
#include <errno.h>
#include "rocksdb/env.h" #include "rocksdb/env.h"
// For non linux platform, the following macros are used only as place // For non linux platform, the following macros are used only as place
...@@ -24,7 +25,9 @@ ...@@ -24,7 +25,9 @@
namespace rocksdb { namespace rocksdb {
static Status IOError(const std::string& context, int err_number) { static Status IOError(const std::string& context, int err_number) {
return Status::IOError(context, strerror(err_number)); return (err_number == ENOSPC) ?
Status::NoSpace(context, strerror(err_number)) :
Status::IOError(context, strerror(err_number));
} }
class PosixHelper { class PosixHelper {
......
...@@ -21,9 +21,10 @@ const char* Status::CopyState(const char* state) { ...@@ -21,9 +21,10 @@ const char* Status::CopyState(const char* state) {
return result; return result;
} }
Status::Status(Code _code, const Slice& msg, const Slice& msg2) Status::Status(Code _code, SubCode _subcode, const Slice& msg, const Slice& msg2)
: code_(_code), subcode_(kNone) { : code_(_code), subcode_(_subcode) {
assert(code_ != kOk); assert(code_ != kOk);
assert(subcode_ != kMaxSubCode);
const uint32_t len1 = static_cast<uint32_t>(msg.size()); const uint32_t len1 = static_cast<uint32_t>(msg.size());
const uint32_t len2 = static_cast<uint32_t>(msg2.size()); const uint32_t len2 = static_cast<uint32_t>(msg2.size());
const uint32_t size = len1 + (len2 ? (2 + len2) : 0); const uint32_t size = len1 + (len2 ? (2 + len2) : 0);
......
...@@ -8,10 +8,11 @@ ...@@ -8,10 +8,11 @@
namespace rocksdb { namespace rocksdb {
const char* Status::msgs[] = { const char* Status::msgs[] = {
"", // kNone "", // kNone
"Timeout Acquiring Mutex", // kMutexTimeout "Timeout Acquiring Mutex", // kMutexTimeout
"Timeout waiting to lock key", // kLockTimeout "Timeout waiting to lock key", // kLockTimeout
"Failed to acquire lock due to max_num_locks limit" // kLockLimit "Failed to acquire lock due to max_num_locks limit", // kLockLimit
"No space left on device" // kNoSpace
}; };
} // namespace rocksdb } // namespace rocksdb
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册