Add NoSpace subcode to IOError (#1320)

Add a sub code to distinguish "out of space" errors from regular I/O errors
This commit is contained in:
Edouard A 2016-09-07 21:37:45 +02:00 committed by Siying Dong
parent 67036c0406
commit 66a91e2607
8 changed files with 53 additions and 23 deletions

View File

@ -111,6 +111,7 @@ TEST_F(DBIOFailureTest, NoSpaceCompactRange) {
Status s = dbfull()->TEST_CompactRange(0, nullptr, nullptr, nullptr,
true /* disallow trivial move */);
ASSERT_TRUE(s.IsIOError());
ASSERT_TRUE(s.IsNoSpace());
env_->no_space_.store(false, std::memory_order_release);
} while (ChangeCompactOptions());

View File

@ -221,7 +221,7 @@ class SpecialEnv : public EnvWrapper {
// Drop writes on the floor
return Status::OK();
} 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 {
env_->bytes_written_ += data.size();
return base_->Append(data);

View File

@ -33,14 +33,14 @@ class Status {
Status& operator=(const Status& s);
Status(Status&& s)
#if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
noexcept
noexcept
#endif
;
;
Status& operator=(Status&& s)
#if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
noexcept
noexcept
#endif
;
;
bool operator==(const Status& rhs) const;
bool operator!=(const Status& rhs) const;
@ -58,7 +58,7 @@ class Status {
kAborted = 10,
kBusy = 11,
kExpired = 12,
kTryAgain = 13,
kTryAgain = 13
};
Code code() const { return code_; }
@ -68,6 +68,7 @@ class Status {
kMutexTimeout = 1,
kLockTimeout = 2,
kLockLimit = 3,
kNoSpace = 4,
kMaxSubCode
};
@ -157,6 +158,11 @@ class Status {
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.
bool ok() const { return code() == kOk; }
@ -200,6 +206,15 @@ class Status {
// re-attempted.
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.
// Returns the string "OK" for success.
std::string ToString() const;
@ -219,7 +234,10 @@ class Status {
explicit Status(Code _code, SubCode _subcode = kNone)
: 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);
};
@ -229,7 +247,7 @@ inline Status::Status(const Status& s) : code_(s.code_), subcode_(s.subcode_) {
inline Status& Status::operator=(const Status& s) {
// The following condition catches both aliasing (when this == &s),
// and the common case where both s and *this are ok.
if(this != &s) {
if (this != &s) {
code_ = s.code_;
subcode_ = s.subcode_;
delete[] state_;
@ -240,23 +258,23 @@ inline Status& Status::operator=(const Status& s) {
inline Status::Status(Status&& s)
#if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
noexcept
noexcept
#endif
: Status() {
: Status() {
*this = std::move(s);
}
inline Status& Status::operator=(Status&& s)
#if !(defined _MSC_VER) || ((defined _MSC_VER) && (_MSC_VER >= 1900))
noexcept
noexcept
#endif
{
if(this != &s) {
if (this != &s) {
code_ = std::move(s.code_);
s.code_ = kOk;
subcode_ = std::move(s.subcode_);
s.subcode_ = kNone;
delete [] state_;
delete[] state_;
state_ = nullptr;
std::swap(state_, s.state_);
}

View File

@ -26,7 +26,9 @@ namespace port {
std::string GetWindowsErrSz(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) {
@ -34,7 +36,9 @@ inline Status IOErrorFromLastWindowsError(const std::string& context) {
}
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

View File

@ -36,7 +36,9 @@ namespace {
// Log error message
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,

View File

@ -9,6 +9,7 @@
#pragma once
#include <unistd.h>
#include <atomic>
#include <errno.h>
#include "rocksdb/env.h"
// For non linux platform, the following macros are used only as place
@ -24,7 +25,9 @@
namespace rocksdb {
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 {

View File

@ -21,9 +21,10 @@ const char* Status::CopyState(const char* state) {
return result;
}
Status::Status(Code _code, const Slice& msg, const Slice& msg2)
: code_(_code), subcode_(kNone) {
Status::Status(Code _code, SubCode _subcode, const Slice& msg, const Slice& msg2)
: code_(_code), subcode_(_subcode) {
assert(code_ != kOk);
assert(subcode_ != kMaxSubCode);
const uint32_t len1 = static_cast<uint32_t>(msg.size());
const uint32_t len2 = static_cast<uint32_t>(msg2.size());
const uint32_t size = len1 + (len2 ? (2 + len2) : 0);

View File

@ -8,10 +8,11 @@
namespace rocksdb {
const char* Status::msgs[] = {
"", // kNone
"Timeout Acquiring Mutex", // kMutexTimeout
"Timeout waiting to lock key", // kLockTimeout
"Failed to acquire lock due to max_num_locks limit" // kLockLimit
"", // kNone
"Timeout Acquiring Mutex", // kMutexTimeout
"Timeout waiting to lock key", // kLockTimeout
"Failed to acquire lock due to max_num_locks limit", // kLockLimit
"No space left on device" // kNoSpace
};
} // namespace rocksdb