| /** |
| * 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. |
| **/ |
| |
| #define __STDC_FORMAT_MACROS |
| |
| #include "storage/FileManagerPosix.hpp" |
| |
| #include <fcntl.h> |
| #include <glob.h> |
| #include <unistd.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| |
| #include <cerrno> |
| #include <cinttypes> |
| #include <cstddef> |
| #include <cstdio> |
| #include <cstring> |
| #include <string> |
| |
| #include "storage/StorageBlockInfo.hpp" |
| #include "storage/StorageConstants.hpp" |
| #include "storage/StorageErrors.hpp" |
| #include "utility/StringUtil.hpp" |
| |
| #include "glog/logging.h" |
| |
| using std::size_t; |
| using std::sscanf; |
| using std::strerror; |
| using std::string; |
| |
| namespace quickstep { |
| |
| block_id_counter FileManagerPosix::getMaxUsedBlockCounter(const block_id_domain block_domain) const { |
| const string block_domain_str(ToZeroPaddedString(block_domain, kBlockIdDomainLengthInDigits)); |
| |
| string glob_pattern(storage_path_); |
| glob_pattern.append("qsblk_"); |
| glob_pattern.append(block_domain_str); |
| glob_pattern.append("_*.qsb"); |
| |
| glob_t glob_result; |
| glob(glob_pattern.c_str(), 0, nullptr, &glob_result); |
| |
| string filename_pattern(storage_path_); |
| filename_pattern.append("qsblk_"); |
| filename_pattern.append(block_domain_str); |
| filename_pattern.append("_%"); |
| filename_pattern.append(SCNu64); |
| filename_pattern.append(".qsb"); |
| |
| block_id_counter counter_max = 0, counter; |
| if (glob_result.gl_pathc > 0 && |
| sscanf(glob_result.gl_pathv[glob_result.gl_pathc - 1], filename_pattern.c_str(), &counter) == 1 && |
| counter > counter_max) { |
| counter_max = counter; |
| } |
| |
| globfree(&glob_result); |
| return counter_max; |
| } |
| |
| size_t FileManagerPosix::numSlots(const block_id block) const { |
| const string filename(blockFilename(block)); |
| |
| struct stat file_stat; |
| if (stat(filename.c_str(), &file_stat) == -1) { |
| if (errno != ENOENT) { |
| LOG(ERROR) << "Failed to retrieve info about file " << filename << " with error: " << strerror(errno); |
| } |
| return 0; |
| } |
| |
| if ((file_stat.st_size % kSlotSizeBytes) != 0) { |
| throw CorruptPersistentStorage(); |
| } |
| |
| return static_cast<size_t>(file_stat.st_size) / kSlotSizeBytes; |
| } |
| |
| bool FileManagerPosix::deleteBlockOrBlob(const block_id block) { |
| const string filename(blockFilename(block)); |
| |
| if ((unlink(filename.c_str()) == 0) || (errno == ENOENT)) { |
| return true; |
| } else { |
| LOG(ERROR) << "Failed to delete file " << filename << " with error: " << strerror(errno); |
| return false; |
| } |
| } |
| |
| bool FileManagerPosix::readBlockOrBlob(const block_id block, |
| void *buffer, |
| const std::size_t length) { |
| DCHECK(buffer != nullptr); |
| DCHECK_EQ(0u, length % kSlotSizeBytes); |
| |
| const string filename(blockFilename(block)); |
| |
| const int fd = open(filename.c_str(), O_RDONLY); |
| if (fd == -1) { |
| LOG(ERROR) << "Failed to open file " << filename << " with error: " << strerror(errno); |
| return false; |
| } |
| |
| size_t bytes_total = 0; |
| while (bytes_total < length) { |
| const ssize_t bytes = read(fd, static_cast<char*>(buffer) + bytes_total, length - bytes_total); |
| if (bytes > 0) { |
| bytes_total += bytes; |
| } else if (bytes == -1) { |
| if (errno != EINTR) { |
| LOG(ERROR) << "Failed to read file " << filename << " with error: " << strerror(errno); |
| break; |
| } |
| } else { |
| LOG(ERROR) << "Failed to read file " << filename << " since EOF was reached unexpectedly"; |
| break; |
| } |
| } |
| |
| if (close(fd) != 0) { |
| LOG(ERROR) << "Failed to close file " << filename << " with error: " << strerror(errno); |
| } |
| |
| return (bytes_total == length); |
| } |
| |
| bool FileManagerPosix::writeBlockOrBlob(const block_id block, |
| const void *buffer, |
| const std::size_t length) { |
| DCHECK(buffer != nullptr); |
| DCHECK_EQ(0u, length % kSlotSizeBytes); |
| |
| const string filename(blockFilename(block)); |
| |
| const int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); |
| if (fd == -1) { |
| LOG(ERROR) << "Failed to open file " << filename << " with error: " << strerror(errno); |
| return false; |
| } |
| |
| size_t bytes_total = 0; |
| while (bytes_total < length) { |
| const ssize_t bytes = write(fd, static_cast<const char*>(buffer) + bytes_total, length - bytes_total); |
| if (bytes > 0) { |
| bytes_total += bytes; |
| } else if (bytes == -1 && errno != EINTR) { |
| LOG(ERROR) << "Failed to write file " << filename << " with error: " << strerror(errno); |
| break; |
| } |
| } |
| |
| if (fsync(fd) != 0) { |
| LOG(ERROR) << "Failed to sync file " << filename << " with error: " << strerror(errno); |
| } |
| |
| if (close(fd) != 0) { |
| LOG(ERROR) << "Failed to close file " << filename << " with error: " << strerror(errno); |
| } |
| |
| return (bytes_total == length); |
| } |
| |
| } // namespace quickstep |