Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PathNotFound subcode to IOError #4745

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Enabled checkpoint on readonly db (DBImplReadOnly).
* Make DB ignore dropped column families while committing results of atomic flush.
* RocksDB may choose to preopen some files even if options.max_open_files != -1. This may make DB open slightly longer.
* Introduce a new IOError subcode, PathNotFound, to indicate trying to open a nonexistent file or directory for read.

### Public API Change
* Transaction::GetForUpdate is extended with a do_validate parameter with default value of true. If false it skips validating the snapshot before doing the read. Similarly ::Merge, ::Put, ::Delete, and ::SingleDelete are extended with assume_tracked with default value of false. If true it indicates that call is assumed to be after a ::GetForUpdate.
Expand Down
8 changes: 5 additions & 3 deletions env/env_hdfs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ namespace {

// Log error message
static Status IOError(const std::string& context, int err_number) {
return (err_number == ENOSPC) ?
Status::NoSpace(context, strerror(err_number)) :
Status::IOError(context, strerror(err_number));
return (err_number == ENOSPC)
? Status::NoSpace(context, strerror(err_number))
: (err_number == ENOENT)
? Status::PathNotFound(context, strerror(err_number))
: Status::IOError(context, strerror(err_number));
}

// assume that there is one global logger for now. It is not thread-safe,
Expand Down
3 changes: 3 additions & 0 deletions env/io_posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ static Status IOError(const std::string& context, const std::string& file_name,
strerror(err_number));
case ESTALE:
return Status::IOError(Status::kStaleFile);
case ENOENT:
return Status::PathNotFound(IOErrorMsg(context, file_name),
strerror(err_number));
default:
return Status::IOError(IOErrorMsg(context, file_name),
strerror(err_number));
Expand Down
14 changes: 14 additions & 0 deletions include/rocksdb/status.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class Status {
kStaleFile = 6,
kMemoryLimit = 7,
kSpaceLimit = 8,
kPathNotFound = 9,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we already use kNotFound for this specific case? So, why do we need a new one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Code::kNotFound is intended to denote key-value pair is not found. File not found is an IOError and should be represented with the combination of IOError and a proper subcode. Let me know if I have missed any background context on the meaning of kNotFound.

Copy link
Contributor

@sagar0 sagar0 Dec 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I said that because we use Status::NotFound() at various places when combined with Env::FileExists() check too.

// Returns OK if the named file exists.
// NotFound if the named file does not exist,
// the calling process does not have permission to determine
// whether this file exists, or if the path is invalid.
// IOError if an IO Error was encountered
virtual Status FileExists(const std::string& fname) = 0;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this makes sense. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chatted offline with @siying . Opening a non-existing file for read is an IOError.
TableCache should return IOError instead of NotFound when the file does not exist. Therefore, we still need a new subcode.

kMaxSubCode
};

Expand Down Expand Up @@ -198,6 +199,11 @@ class Status {
return Status(kIOError, kSpaceLimit, msg, msg2);
}

static Status PathNotFound() { return Status(kIOError, kPathNotFound); }
static Status PathNotFound(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kIOError, kPathNotFound, msg, msg2);
}

// Returns true iff the status indicates success.
bool ok() const { return code() == kOk; }

Expand Down Expand Up @@ -266,6 +272,14 @@ class Status {
return (code() == kAborted) && (subcode() == kMemoryLimit);
}

// Returns true iff the status indicates a PathNotFound error
// This is caused by an I/O error returning the specific "no such file or
// directory" error condition. A PathNotFound error is an I/O error with
// a specific subcode, enabling users to take appropriate action if necessary
bool IsPathNotFound() const {
return (code() == kIOError) && (subcode() == kPathNotFound);
}

// Return a string representation of this status suitable for printing.
// Returns the string "OK" for success.
std::string ToString() const;
Expand Down
12 changes: 7 additions & 5 deletions port/win/io_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ std::string GetWindowsErrSz(DWORD err);
inline Status IOErrorFromWindowsError(const std::string& context, DWORD err) {
return ((err == ERROR_HANDLE_DISK_FULL) || (err == ERROR_DISK_FULL))
? Status::NoSpace(context, GetWindowsErrSz(err))
: Status::IOError(context, GetWindowsErrSz(err));
: ((err == ERROR_FILE_NOT_FOUND) || (err == ERROR_PATH_NOT_FOUND))
? Status::PathNotFound(context, GetWindowsErrSz(err))
: Status::IOError(context, GetWindowsErrSz(err));
}

inline Status IOErrorFromLastWindowsError(const std::string& context) {
Expand All @@ -37,7 +39,9 @@ inline Status IOErrorFromLastWindowsError(const std::string& context) {
inline Status IOError(const std::string& context, int err_number) {
return (err_number == ENOSPC)
? Status::NoSpace(context, strerror(err_number))
: Status::IOError(context, strerror(err_number));
: (err_number == ENOENT)
? Status::PathNotFound(context, strerror(err_number))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be these instances could be changed to Status::NotFound() ?

: Status::IOError(context, strerror(err_number));
}

class WinFileData;
Expand Down Expand Up @@ -426,9 +430,7 @@ class WinMemoryMappedBuffer : public MemoryMappedFileBuffer {
class WinDirectory : public Directory {
HANDLE handle_;
public:
explicit
WinDirectory(HANDLE h) noexcept :
handle_(h) {
explicit WinDirectory(HANDLE h) noexcept : handle_(h) {
assert(handle_ != INVALID_HANDLE_VALUE);
}
~WinDirectory() {
Expand Down
3 changes: 2 additions & 1 deletion util/status.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ static const char* msgs[static_cast<int>(Status::kMaxSubCode)] = {
"Deadlock", // kDeadlock
"Stale file handle", // kStaleFile
"Memory limit reached", // kMemoryLimit
"Space limit reached" // kSpaceLimit
"Space limit reached", // kSpaceLimit
"No such file or directory", // kPathNotFound
};

Status::Status(Code _code, SubCode _subcode, const Slice& msg,
Expand Down