| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #include "runtime/io/error-converter.h" |
| |
| #include "gutil/strings/substitute.h" |
| #include "util/debug-util.h" |
| #include "util/error-util.h" |
| #include "util/string-parser.h" |
| |
| #include "common/names.h" |
| |
| namespace impala { |
| |
| using std::unordered_map; |
| |
| unordered_map<int, string> ErrorConverter::errno_to_error_text_map_( |
| {{EACCES, "Access denied for the process' user"}, |
| {EINTR, "Internal error occured."}, |
| {EINVAL, "Invalid inputs."}, |
| {EMFILE, "Process level opened file descriptor count is reached."}, |
| {ENAMETOOLONG, |
| "Either the path length or a path component exceeds the maximum length."}, |
| {ENFILE, "OS level opened file descriptor count is reached."}, |
| {ENOENT, "The given path doesn't exist."}, |
| {ENOSPC, "No space left on device."}, |
| {ENOTDIR, "It is not a directory."}, |
| {EOVERFLOW, "File size can't be represented."}, |
| {EROFS, "The file system is read only."}, |
| {EAGAIN, "Resource temporarily unavailable."}, |
| {EBADF, "The given file descriptor is invalid."}, |
| {ENOMEM, "Not enough memory."}, |
| {EFBIG, "Maximum file size reached."}, |
| {EIO, "Disk level I/O error occured."}, |
| {ENXIO, "Device doesn't exist."}}); |
| |
| Status ErrorConverter::GetErrorStatusFromErrno(const string& function_name, |
| const string& file_path, int err_no, const Params& params) { |
| return Status(ErrorMsg(TErrorCode::DISK_IO_ERROR, GetBackendString(), |
| GetErrorText(function_name, file_path, err_no, params))); |
| } |
| |
| bool ErrorConverter::IsBlacklistableError(int err_no) { |
| // A set of disk IO related non-transient error codes that should cause failure for |
| // reading/writing file on local disk. These errors could be caused by incorrect |
| // configurations or file system errors, but are not caused by temporarily unavailable |
| // resource, like EAGAIN, ENOMEM, EMFILE, ENFILE and ENOSPC. Since these errors are not |
| // likely disappear soon, the node which frequently hits such disk errors should be |
| // blacklisted. |
| static const set<int32_t> blacklistable_disk_error_codes = { |
| EPERM, // Operation not permitted. |
| ENOENT, // No such file or directory. |
| ESRCH, // No such process. |
| EINTR, // Interrupted system call. |
| EIO, // Disk level I/O error. |
| ENXIO, // No such device or address. |
| E2BIG, // Argument list too long. |
| ENOEXEC, // Exec format error. |
| EBADF, // The given file descriptor is invalid. |
| EACCES, // Permission denied. |
| EFAULT, // Bad address. |
| ENODEV, // No such device |
| ENOTDIR, // It is not a directory. |
| EINVAL, // Invalid argument. |
| EFBIG, // Maximum file size reached. |
| ESPIPE, // Illegal seek. |
| EROFS, // The file system is read only. |
| ENAMETOOLONG, // Either the path length or a path component exceeds the max length. |
| EOVERFLOW}; // File size can't be represented. |
| |
| // Return true if the err_no matches any of the 'blacklistable' error code. |
| return (blacklistable_disk_error_codes.find(err_no) |
| != blacklistable_disk_error_codes.end()); |
| } |
| |
| bool ErrorConverter::IsBlacklistableError(const Status& status) { |
| // Return true if the error is generated by Debug Action. |
| // Return false if error code is not set as DISK_IO_ERROR, or there is no 'err_no' in |
| // error text, or 'err_no' is set in wrong format. |
| if (status.IsInternalError()) { |
| return (status.msg().msg().find("Debug Action") != string::npos); |
| } else if (!status.IsDiskIoError()) { |
| return false; |
| } |
| |
| size_t found = status.msg().msg().find("errno="); |
| if (found == string::npos) return false; |
| size_t start_pos = found + 6; |
| size_t end_pos = status.msg().msg().find(",", start_pos); |
| string value = (end_pos != string::npos) ? |
| status.msg().msg().substr(start_pos, end_pos - start_pos) : |
| status.msg().msg().substr(start_pos); |
| if (value.empty()) return false; |
| StringParser::ParseResult result; |
| int err_no = StringParser::StringToInt<int32_t>(value.c_str(), value.length(), &result); |
| if (result != StringParser::PARSE_SUCCESS) { |
| return false; |
| } else { |
| return IsBlacklistableError(err_no); |
| } |
| } |
| |
| string ErrorConverter::GetErrorText(const string& function_name, |
| const string& file_path, int err_no, Params params) { |
| const string* error_text_body = GetErrorTextBody(err_no); |
| if (error_text_body != nullptr) { |
| params["errno"] = SimpleItoa(err_no); |
| return Substitute("$0 failed for $1. $2 $3", function_name, file_path, |
| *error_text_body, GetParamsString(params), err_no); |
| } |
| return Substitute("$0 failed for $1. errno=$2, description=$3", function_name, |
| file_path, err_no, GetStrErrMsg(err_no)); |
| } |
| |
| string ErrorConverter::GetParamsString(const Params& params) { |
| string result = ""; |
| bool first = true; |
| for (const auto& item : params) { |
| if (!first) result.append(", "); |
| result.append(item.first).append("=").append(item.second); |
| first = false; |
| } |
| return result; |
| } |
| |
| const string* ErrorConverter::GetErrorTextBody(int err_no) { |
| auto error_mapping_it = errno_to_error_text_map_.find(err_no); |
| if (error_mapping_it != errno_to_error_text_map_.end()) { |
| return &error_mapping_it->second; |
| } |
| return nullptr; |
| } |
| |
| } |