susumu.yata
null+****@clear*****
Thu Dec 6 18:19:24 JST 2012
susumu.yata 2012-12-06 18:19:24 +0900 (Thu, 06 Dec 2012) New Revision: 20773de307abb65597cbb44dcdfadf857f1f8ca4 https://github.com/groonga/grnxx/commit/20773de307abb65597cbb44dcdfadf857f1f8ca4 Log: Update the interface of grnxx::io::File. Modified files: lib/io/file-posix.cpp lib/io/file-posix.hpp lib/io/file-windows.cpp lib/io/file-windows.hpp lib/io/file.cpp lib/io/file.hpp lib/io/pool-impl.cpp lib/io/view-posix.cpp lib/io/view-windows.cpp lib/io/view-windows.hpp lib/io/view.hpp test/test_io_file.cpp test/test_io_file_info.cpp test/test_io_view.cpp Modified: lib/io/file-posix.cpp (+50 -35) =================================================================== --- lib/io/file-posix.cpp 2012-12-06 16:49:13 +0900 (4f0b140) +++ lib/io/file-posix.cpp 2012-12-06 18:19:24 +0900 (1d6c6ed) @@ -31,6 +31,7 @@ #include "../exception.hpp" #include "../logger.hpp" #include "../thread.hpp" +#include "../time.hpp" #include "path.hpp" namespace grnxx { @@ -44,12 +45,12 @@ FileImpl::~FileImpl() { << ": '::close' " << Error(errno); } } - if (unlink_at_close_ && (~flags_ & GRNXX_IO_TEMPORARY)) { + if (unlink_at_close_ && (~flags_ & FILE_TEMPORARY)) { unlink_if_exists(path_.c_str()); } } -std::unique_ptr<FileImpl> FileImpl::open(const char *path, Flags flags, +std::unique_ptr<FileImpl> FileImpl::open(FileFlags flags, const char *path, int permission) { std::unique_ptr<FileImpl> file(new (std::nothrow) FileImpl); if (!file) { @@ -57,41 +58,54 @@ std::unique_ptr<FileImpl> FileImpl::open(const char *path, Flags flags, GRNXX_THROW(); } - if (flags & GRNXX_IO_TEMPORARY) { - file->open_temporary_file(path, flags, permission); + if (flags & FILE_TEMPORARY) { + file->open_temporary_file(flags, path, permission); } else { - file->open_regular_file(path, flags, permission); + file->open_regular_file(flags, path, permission); } return file; } -bool FileImpl::lock(LockMode mode, int sleep_count, - Duration sleep_duration) { +void FileImpl::lock(FileLockMode mode) { if (locked_) { - return false; + GRNXX_ERROR() << "deadlock: file = " << *this; + GRNXX_THROW(); } + while (!try_lock(mode)) { + Thread::sleep(FILE_LOCK_SLEEP_DURATION); + } +} - for (int i = 0; i < sleep_count; ++i) { +bool FileImpl::lock(FileLockMode mode, Duration timeout) { + if (locked_) { + GRNXX_ERROR() << "deadlock: file = " << *this; + GRNXX_THROW(); + } + if (try_lock(mode)) { + return true; + } + const Time deadline = Time::now() + timeout; + while (Time::now() < deadline) { if (try_lock(mode)) { return true; } - Thread::sleep(sleep_duration); + Thread::sleep(FILE_LOCK_SLEEP_DURATION); } return false; } -bool FileImpl::try_lock(LockMode mode) { +bool FileImpl::try_lock(FileLockMode mode) { if (locked_) { return false; } int operation = LOCK_NB; switch (mode) { - case GRNXX_IO_SHARED_LOCK: { + case FILE_LOCK_SHARED: { operation |= LOCK_SH; break; } - case GRNXX_IO_EXCLUSIVE_LOCK: { + case FILE_LOCK_EXCLUSIVE: { operation |= LOCK_EX; break; } @@ -127,11 +141,12 @@ bool FileImpl::unlock() { return true; } +// TODO: These should be constexpr. const uint64_t FILE_IMPL_MAX_OFFSET = std::numeric_limits<off_t>::max(); const uint64_t FILE_IMPL_MAX_SIZE = std::numeric_limits<ssize_t>::max(); uint64_t FileImpl::read(void *buf, uint64_t size) { - if (flags_ & GRNXX_IO_WRITE_ONLY) { + if (flags_ & FILE_WRITE_ONLY) { GRNXX_ERROR() << "file is write-only"; GRNXX_THROW(); } @@ -148,7 +163,7 @@ uint64_t FileImpl::read(void *buf, uint64_t size) { } uint64_t FileImpl::read(void *buf, uint64_t size, uint64_t offset) { - if (flags_ & GRNXX_IO_WRITE_ONLY) { + if (flags_ & FILE_WRITE_ONLY) { GRNXX_ERROR() << "file is write-only"; GRNXX_THROW(); } @@ -185,7 +200,7 @@ uint64_t FileImpl::read(void *buf, uint64_t size, uint64_t offset) { } uint64_t FileImpl::write(const void *buf, uint64_t size) { - if (flags_ & GRNXX_IO_READ_ONLY) { + if (flags_ & FILE_READ_ONLY) { GRNXX_ERROR() << "file is read-only"; GRNXX_THROW(); } @@ -202,7 +217,7 @@ uint64_t FileImpl::write(const void *buf, uint64_t size) { } uint64_t FileImpl::write(const void *buf, uint64_t size, uint64_t offset) { - if (flags_ & GRNXX_IO_READ_ONLY) { + if (flags_ & FILE_READ_ONLY) { GRNXX_ERROR() << "file is read-only"; GRNXX_THROW(); } @@ -288,7 +303,7 @@ uint64_t FileImpl::tell() const { } void FileImpl::resize(uint64_t size) { - if (flags_ & GRNXX_IO_READ_ONLY) { + if (flags_ & FILE_READ_ONLY) { GRNXX_ERROR() << "file is read-only"; GRNXX_THROW(); } @@ -355,10 +370,10 @@ bool FileImpl::unlink_if_exists(const char *path) { } FileImpl::FileImpl() - : path_(), flags_(Flags::none()), fd_(-1), locked_(false), + : path_(), flags_(FileFlags::none()), fd_(-1), locked_(false), unlink_at_close_(false) {} -void FileImpl::open_regular_file(const char *path, Flags flags, +void FileImpl::open_regular_file(FileFlags flags, const char *path, int permission) { if (!path) { GRNXX_ERROR() << "invalid argument: path = " << path; @@ -368,33 +383,33 @@ void FileImpl::open_regular_file(const char *path, Flags flags, int posix_flags = O_RDWR; - if ((~flags & GRNXX_IO_CREATE) && (flags & GRNXX_IO_READ_ONLY)) { - flags_ |= GRNXX_IO_READ_ONLY; + if ((~flags & FILE_CREATE) && (flags & FILE_READ_ONLY)) { + flags_ |= FILE_READ_ONLY; posix_flags = O_RDONLY; - } else if (flags & GRNXX_IO_WRITE_ONLY) { - flags_ |= GRNXX_IO_WRITE_ONLY; + } else if (flags & FILE_WRITE_ONLY) { + flags_ |= FILE_WRITE_ONLY; posix_flags = O_WRONLY; } - if ((~flags_ & GRNXX_IO_READ_ONLY) && (flags & GRNXX_IO_APPEND)) { - flags_ |= GRNXX_IO_APPEND; + if ((~flags_ & FILE_READ_ONLY) && (flags & FILE_APPEND)) { + flags_ |= FILE_APPEND; posix_flags |= O_APPEND; } - if (flags & GRNXX_IO_CREATE) { - flags_ |= GRNXX_IO_CREATE; + if (flags & FILE_CREATE) { + flags_ |= FILE_CREATE; posix_flags |= O_CREAT; - if (flags & GRNXX_IO_OPEN) { - flags_ |= GRNXX_IO_OPEN; + if (flags & FILE_OPEN) { + flags_ |= FILE_OPEN; } else { posix_flags |= O_EXCL; } } else { - flags_ |= GRNXX_IO_OPEN; + flags_ |= FILE_OPEN; } - if ((flags_ & GRNXX_IO_OPEN) && (flags & GRNXX_IO_TRUNCATE)) { - flags_ |= GRNXX_IO_TRUNCATE; + if ((flags_ & FILE_OPEN) && (flags & FILE_TRUNCATE)) { + flags_ |= FILE_TRUNCATE; posix_flags |= O_TRUNC; } @@ -408,8 +423,8 @@ void FileImpl::open_regular_file(const char *path, Flags flags, } } -void FileImpl::open_temporary_file(const char *path, Flags flags, int) { - flags_ = GRNXX_IO_TEMPORARY; +void FileImpl::open_temporary_file(FileFlags flags, const char *path, int) { + flags_ = FILE_TEMPORARY; int posix_flags = O_RDWR | O_CREAT | O_EXCL | O_NOCTTY; #ifdef O_NOATIME Modified: lib/io/file-posix.hpp (+8 -14) =================================================================== --- lib/io/file-posix.hpp 2012-12-06 16:49:13 +0900 (7b2da12) +++ lib/io/file-posix.hpp 2012-12-06 18:19:24 +0900 (53e8033) @@ -29,20 +29,14 @@ class FileImpl { public: ~FileImpl(); - static std::unique_ptr<FileImpl> open(const char *path, Flags flags, + static std::unique_ptr<FileImpl> open(FileFlags flags, const char *path, int permission); - bool lock(LockMode mode, int sleep_count, Duration sleep_duration); - bool try_lock(LockMode mode); + void lock(FileLockMode mode); + bool lock(FileLockMode mode, Duration timeout); + bool try_lock(FileLockMode mode); bool unlock(); - bool locked() const { - return locked_; - } - bool unlocked() const { - return !locked_; - } - uint64_t read(void *buf, uint64_t size); uint64_t read(void *buf, uint64_t size, uint64_t offset); uint64_t write(const void *buf, uint64_t size); @@ -66,7 +60,7 @@ class FileImpl { String path() const { return path_; } - Flags flags() const { + FileFlags flags() const { return flags_; } @@ -82,15 +76,15 @@ class FileImpl { private: String path_; - Flags flags_; + FileFlags flags_; int fd_; bool locked_; bool unlink_at_close_; FileImpl(); - void open_regular_file(const char *path, Flags flags, int permission); - void open_temporary_file(const char *path, Flags flags, int permission); + void open_regular_file(FileFlags flags, const char *path, int permission); + void open_temporary_file(FileFlags flags, const char *path, int permission); FileImpl(const FileImpl &); FileImpl &operator=(const FileImpl &); Modified: lib/io/file-windows.cpp (+51 -37) =================================================================== --- lib/io/file-windows.cpp 2012-12-06 16:49:13 +0900 (e6fb0d3) +++ lib/io/file-windows.cpp 2012-12-06 18:19:24 +0900 (80567af) @@ -27,6 +27,7 @@ #include "../exception.hpp" #include "../logger.hpp" #include "../thread.hpp" +#include "../time.hpp" #include "path.hpp" namespace grnxx { @@ -40,52 +41,65 @@ FileImpl::~FileImpl() { << ": '::CloseHandle' " << Error(::GetLastError()); } } - if (unlink_at_close_ && (~flags_ & GRNXX_IO_TEMPORARY)) { + if (unlink_at_close_ && (~flags_ & FILE_TEMPORARY)) { unlink_if_exists(path_.c_str()); } } -std::unique_ptr<FileImpl> FileImpl::open(const char *path, Flags flags, +std::unique_ptr<FileImpl> FileImpl::open(FileFlags flags, const char *path, int permission) { std::unique_ptr<FileImpl> file(new (std::nothrow) FileImpl); if (!file) { GRNXX_ERROR() << "new grnxx::io::FileImpl failed"; GRNXX_THROW(); } - if (flags & GRNXX_IO_TEMPORARY) { - file->open_temporary_file(path, flags, permission); + if (flags & FILE_TEMPORARY) { + file->open_temporary_file(flags, path, permission); } else { - file->open_regular_file(path, flags, permission); + file->open_regular_file(flags, path, permission); } return file; } -bool FileImpl::lock(LockMode mode, int sleep_count, - Duration sleep_duration) { +void FileImpl::lock(FileLockMode mode) { if (locked_) { - return false; + GRNXX_ERROR() << "deadlock: file = " << *this; + GRNXX_THROW(); } + while (!try_lock(mode)) { + Thread::sleep(FILE_LOCK_SLEEP_DURATION); + } +} - for (int i = 0; i < sleep_count; ++i) { +bool FileImpl::lock(FileLockMode mode, Duration timeout) { + if (locked_) { + GRNXX_ERROR() << "deadlock: file = " << *this; + GRNXX_THROW(); + } + if (try_lock(mode)) { + return true; + } + const Time deadline = Time::now() + timeout; + while (Time::now() < deadline) { if (try_lock(mode)) { return true; } - Thread::sleep(sleep_duration); + Thread::sleep(FILE_LOCK_SLEEP_DURATION); } return false; } -bool FileImpl::try_lock(LockMode mode) { +bool FileImpl::try_lock(FileLockMode mode) { if (locked_) { return false; } DWORD flags = LOCKFILE_FAIL_IMMEDIATELY; switch (mode) { - case GRNXX_IO_SHARED_LOCK: { + case FILE_LOCK_SHARED: { break; } - case GRNXX_IO_EXCLUSIVE_LOCK: { + case FILE_LOCK_EXCLUSIVE: { flags |= LOCKFILE_EXCLUSIVE_LOCK; break; } @@ -130,7 +144,7 @@ bool FileImpl::unlock() { } uint64_t FileImpl::read(void *buf, uint64_t size) { - if (flags_ & GRNXX_IO_WRITE_ONLY) { + if (flags_ & FILE_WRITE_ONLY) { GRNXX_ERROR() << "file is write-only"; GRNXX_THROW(); } @@ -154,7 +168,7 @@ uint64_t FileImpl::read(void *buf, uint64_t size) { } uint64_t FileImpl::read(void *buf, uint64_t size, uint64_t offset) { - if (flags_ & GRNXX_IO_WRITE_ONLY) { + if (flags_ & FILE_WRITE_ONLY) { GRNXX_ERROR() << "file is write-only"; GRNXX_THROW(); } @@ -174,7 +188,7 @@ uint64_t FileImpl::read(void *buf, uint64_t size, uint64_t offset) { } uint64_t FileImpl::write(const void *buf, uint64_t size) { - if (flags_ & GRNXX_IO_READ_ONLY) { + if (flags_ & FILE_READ_ONLY) { GRNXX_ERROR() << "file is read-only"; GRNXX_THROW(); } @@ -201,7 +215,7 @@ uint64_t FileImpl::write(const void *buf, uint64_t size) { } uint64_t FileImpl::write(const void *buf, uint64_t size, uint64_t offset) { - if (flags_ & GRNXX_IO_READ_ONLY) { + if (flags_ & FILE_READ_ONLY) { GRNXX_ERROR() << "file is read-only"; GRNXX_THROW(); } @@ -274,7 +288,7 @@ uint64_t FileImpl::tell() const { } void FileImpl::resize(uint64_t size) { - if (flags_ & GRNXX_IO_READ_ONLY) { + if (flags_ & FILE_READ_ONLY) { GRNXX_ERROR() << "file is read-only"; GRNXX_THROW(); } @@ -334,10 +348,10 @@ bool FileImpl::unlink_if_exists(const char *path) { } FileImpl::FileImpl() - : path_(), flags_(Flags::none()), handle_(INVALID_HANDLE_VALUE), + : path_(), flags_(FileFlags::none()), handle_(INVALID_HANDLE_VALUE), append_mode_(false), locked_(false), unlink_at_close_(false) {} -void FileImpl::open_regular_file(const char *path, Flags flags, +void FileImpl::open_regular_file(FileFlags flags, const char *path, int permission) { if (!path) { GRNXX_ERROR() << "invalid argument: path = " << path; @@ -346,16 +360,16 @@ void FileImpl::open_regular_file(const char *path, Flags flags, path_ = path; DWORD desired_access = GENERIC_READ | GENERIC_WRITE; - if ((~flags & GRNXX_IO_CREATE) && (flags & GRNXX_IO_READ_ONLY)) { - flags_ |= GRNXX_IO_READ_ONLY; + if ((~flags & FILE_CREATE) && (flags & FILE_READ_ONLY)) { + flags_ |= FILE_READ_ONLY; desired_access = GENERIC_READ; - } else if (flags & GRNXX_IO_WRITE_ONLY) { - flags_ |= GRNXX_IO_WRITE_ONLY; + } else if (flags & FILE_WRITE_ONLY) { + flags_ |= FILE_WRITE_ONLY; desired_access = GENERIC_WRITE; } - if ((~flags_ & GRNXX_IO_READ_ONLY) && (flags & GRNXX_IO_APPEND)) { - flags_ |= GRNXX_IO_APPEND; + if ((~flags_ & FILE_READ_ONLY) && (flags & FILE_APPEND)) { + flags_ |= FILE_APPEND; append_mode_ = true; } @@ -363,22 +377,22 @@ void FileImpl::open_regular_file(const char *path, Flags flags, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; DWORD creation_disposition; - if (flags & GRNXX_IO_CREATE) { - flags_ |= GRNXX_IO_CREATE; + if (flags & FILE_CREATE) { + flags_ |= FILE_CREATE; creation_disposition = CREATE_NEW; - if (flags & GRNXX_IO_OPEN) { - flags_ |= GRNXX_IO_OPEN; + if (flags & FILE_OPEN) { + flags_ |= FILE_OPEN; creation_disposition = OPEN_ALWAYS; - if (flags & GRNXX_IO_TRUNCATE) { - flags_ |= GRNXX_IO_TRUNCATE; + if (flags & FILE_TRUNCATE) { + flags_ |= FILE_TRUNCATE; creation_disposition = CREATE_ALWAYS; } } } else { - flags_ |= GRNXX_IO_OPEN; + flags_ |= FILE_OPEN; creation_disposition = OPEN_EXISTING; - if (flags & GRNXX_IO_TRUNCATE) { - flags_ |= GRNXX_IO_TRUNCATE; + if (flags & FILE_TRUNCATE) { + flags_ |= FILE_TRUNCATE; creation_disposition = TRUNCATE_EXISTING; } } @@ -396,9 +410,9 @@ void FileImpl::open_regular_file(const char *path, Flags flags, } } -void FileImpl::open_temporary_file(const char *path, Flags flags, +void FileImpl::open_temporary_file(FileFlags flags, const char *path, int permission) try { - flags_ = GRNXX_IO_TEMPORARY; + flags_ = FILE_TEMPORARY; const DWORD desired_access = GENERIC_READ | GENERIC_WRITE; const DWORD share_mode = FILE_SHARE_DELETE; Modified: lib/io/file-windows.hpp (+12 -14) =================================================================== --- lib/io/file-windows.hpp 2012-12-06 16:49:13 +0900 (52e46bb) +++ lib/io/file-windows.hpp 2012-12-06 18:19:24 +0900 (26cdaf3) @@ -27,6 +27,10 @@ #endif // NOMINMAX #include <windows.h> +#ifdef FILE_READ_ONLY +# undef FILE_READ_ONLY +#endif // FILE_READ_ONLY + namespace grnxx { namespace io { @@ -34,20 +38,14 @@ class FileImpl { public: ~FileImpl(); - static std::unique_ptr<FileImpl> open(const char *path, Flags flags, + static std::unique_ptr<FileImpl> open(FileFlags flags, const char *path, int permission); - bool lock(LockMode mode, int sleep_count, Duration sleep_duration); - bool try_lock(LockMode mode); + void lock(FileLockMode mode); + bool lock(FileLockMode mode, Duration timeout); + bool try_lock(FileLockMode mode); bool unlock(); - bool locked() const { - return locked_; - } - bool unlocked() const { - return !locked_; - } - uint64_t read(void *buf, uint64_t size); uint64_t read(void *buf, uint64_t size, uint64_t offset); uint64_t write(const void *buf, uint64_t size); @@ -71,7 +69,7 @@ class FileImpl { String path() const { return path_; } - Flags flags() const { + FileFlags flags() const { return flags_; } @@ -87,7 +85,7 @@ class FileImpl { private: String path_; - Flags flags_; + FileFlags flags_; HANDLE handle_; bool append_mode_; bool locked_; @@ -95,8 +93,8 @@ class FileImpl { FileImpl(); - void open_regular_file(const char *path, Flags flags, int permission); - void open_temporary_file(const char *path, Flags flags, int permission); + void open_regular_file(FileFlags flags, const char *path, int permission); + void open_temporary_file(FileFlags flags, const char *path, int permission); FileImpl(const FileImpl &); FileImpl &operator=(const FileImpl &); Modified: lib/io/file.cpp (+38 -17) =================================================================== --- lib/io/file.cpp 2012-12-06 16:49:13 +0900 (854e57b) +++ lib/io/file.cpp 2012-12-06 18:19:24 +0900 (bf14ce5) @@ -25,10 +25,36 @@ namespace grnxx { namespace io { +#define GRNXX_FLAGS_WRITE(flag) do { \ + if (flags & flag) { \ + if (!is_first) { \ + builder << " | "; \ + } \ + builder << #flag; \ + is_first = false; \ + } \ +} while (false) + +StringBuilder &operator<<(StringBuilder &builder, FileFlags flags) { + if (flags) { + bool is_first = true; + GRNXX_FLAGS_WRITE(FILE_READ_ONLY); + GRNXX_FLAGS_WRITE(FILE_WRITE_ONLY); + GRNXX_FLAGS_WRITE(FILE_APPEND); + GRNXX_FLAGS_WRITE(FILE_CREATE); + GRNXX_FLAGS_WRITE(FILE_OPEN); + GRNXX_FLAGS_WRITE(FILE_TEMPORARY); + GRNXX_FLAGS_WRITE(FILE_TRUNCATE); + return builder; + } else { + return builder << "0"; + } +} + File::File() : impl_() {} -File::File(const char *path, Flags flags, int permission) - : impl_(FileImpl::open(path, flags, permission)) {} +File::File(FileFlags flags, const char *path, int permission) + : impl_(FileImpl::open(flags, path, permission)) {} File::~File() {} @@ -46,29 +72,24 @@ File &File::operator=(File &&file) { return *this; } -bool File::lock(LockMode mode, int sleep_count, Duration sleep_duration) { - throw_if_impl_is_invalid(); - return impl_->lock(mode, sleep_count, sleep_duration); -} - -bool File::try_lock(LockMode mode) { +void File::lock(FileLockMode mode) { throw_if_impl_is_invalid(); - return impl_->try_lock(mode); + impl_->lock(mode); } -bool File::unlock() { +bool File::lock(FileLockMode mode, Duration timeout) { throw_if_impl_is_invalid(); - return impl_->unlock(); + return impl_->lock(mode, timeout); } -bool File::locked() const { +bool File::try_lock(FileLockMode mode) { throw_if_impl_is_invalid(); - return impl_->locked(); + return impl_->try_lock(mode); } -bool File::unlocked() const { +bool File::unlock() { throw_if_impl_is_invalid(); - return impl_->unlocked(); + return impl_->unlock(); } uint64_t File::read(void *buf, uint64_t size) { @@ -129,8 +150,8 @@ String File::path() const { return impl_ ? impl_->path() : String(); } -Flags File::flags() const { - return impl_ ? impl_->flags() : Flags::none(); +FileFlags File::flags() const { + return impl_ ? impl_->flags() : FileFlags::none(); } const void *File::handle() const { Modified: lib/io/file.hpp (+60 -18) =================================================================== --- lib/io/file.hpp 2012-12-06 16:49:13 +0900 (0a1a90c) +++ lib/io/file.hpp 2012-12-06 18:19:24 +0900 (c34458a) @@ -15,27 +15,65 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef GRNXX_IO_FILE_HPP -#define GRNXX_IO_FILE_HPP +#ifndef FILE_FILE_HPP +#define FILE_FILE_HPP -#include "flags.hpp" #include "../duration.hpp" namespace grnxx { namespace io { -const int FILE_UNIQUE_PATH_GENERATION_MAX_NUM_TRIALS = 10; +constexpr int FILE_UNIQUE_PATH_GENERATION_MAX_NUM_TRIALS = 10; + +constexpr Duration FILE_LOCK_SLEEP_DURATION = Duration::milliseconds(10); + +class FileFlagsIdentifier {}; +typedef FlagsImpl<FileFlagsIdentifier> FileFlags; + +// FILE_WRITE_ONLY is ignored if FILE_READ_ONLY is enabled. +// FILE_READ_ONLY is disabled if FILE_CREATE is specified. +// If both flags are not set, and object is created/opened/mapped in +// read-write mode. + +// Read-only mode. +constexpr FileFlags FILE_READ_ONLY = FileFlags::define(0x0001); +// Write-only mode. +constexpr FileFlags FILE_WRITE_ONLY = FileFlags::define(0x0002); + +// FILE_APPEND is ignored if FILE_READ_ONLY is enabled. +// FILE_CREATE disables FILE_READ_ONLY. +// FILE_OPEN is enabled if FILE_CREATE is not specified. +// If both FILE_CREATE and FILE_OPEN are set, it first tries to create +// an object and, if already exists, then tries to open the existing object. +// FILE_TEMPORARY disables other flags. + +// Append mode. +constexpr FileFlags FILE_APPEND = FileFlags::define(0x0020); +// Create a file if it does not exist. +constexpr FileFlags FILE_CREATE = FileFlags::define(0x0040); +// Open an existing file. +constexpr FileFlags FILE_OPEN = FileFlags::define(0x0100); +// Create a file, if it does not exist, or open an existing file. +constexpr FileFlags FILE_CREATE_OR_OPEN = FILE_CREATE | FILE_OPEN; +// Create a temporary file. +constexpr FileFlags FILE_TEMPORARY = FileFlags::define(0x0200); +// Truncate an existing file. +constexpr FileFlags FILE_TRUNCATE = FileFlags::define(0x0400); + +StringBuilder &operator<<(StringBuilder &builder, FileFlags flags); + +enum FileLockMode { + FILE_LOCK_EXCLUSIVE = 0x1000, // Create an exclusive lock. + FILE_LOCK_SHARED = 0x2000 // Create a shared lock. +}; class FileImpl; +// Note: Windows ignores permission. class File { public: File(); - // Available flags are as follows: - // GRNXX_IO_READ_ONLY, GRNXX_IO_WRITE_ONLY, GRNXX_IO_APPEND, - // GRNXX_IO_CREATE, GRNXX_IO_OPEN, GRNXX_IO_TEMPORARY, GRNXX_IO_TRUNCATE. - // Windows ignores permission. - explicit File(const char *path, Flags flags = Flags::none(), + explicit File(FileFlags flags, const char *path = nullptr, int permission = 0644); ~File(); @@ -49,21 +87,25 @@ class File { return static_cast<bool>(impl_); } + void open(FileFlags flags, const char *path) { + *this = File(flags | FILE_OPEN, path); + } + void close() { + *this = File(); + } + // The following functions operate advisory locks for files, not for // FileImpl instances. The word "advisory" indicates that the file is // accessible even if it is locked. - // lock() returns false on time-out or deadlock. - bool lock(LockMode mode, int sleep_count = 1000, - Duration sleep_duration = Duration::milliseconds(1)); + void lock(FileLockMode mode); + // lock() returns true on success, false on failure. + bool lock(FileLockMode mode, Duration timeout); // try_lock() returns false if the file is already locked. - bool try_lock(LockMode mode); + bool try_lock(FileLockMode mode); // unlock() returns false if the file is not locked. bool unlock(); - bool locked() const; - bool unlocked() const; - // The following functions are not thread-safe. // read() reads data from file at most size bytes and returns the number of @@ -94,7 +136,7 @@ class File { void set_unlink_at_close(bool value); String path() const; - Flags flags() const; + FileFlags flags() const; const void *handle() const; @@ -123,4 +165,4 @@ inline StringBuilder &operator<<(StringBuilder &builder, const File &file) { } // namespace io } // namespace grnxx -#endif // GRNXX_IO_FILE_HPP +#endif // FILE_FILE_HPP Modified: lib/io/pool-impl.cpp (+15 -15) =================================================================== --- lib/io/pool-impl.cpp 2012-12-06 16:49:13 +0900 (0ddbf97) +++ lib/io/pool-impl.cpp 2012-12-06 18:19:24 +0900 (38fa4e5) @@ -225,8 +225,8 @@ void PoolImpl::unlink(const char *path) { GRNXX_THROW(); } else { // FIXME - File file(path); - if (!file.try_lock(GRNXX_IO_EXCLUSIVE_LOCK)) { + File file(FILE_OPEN, path); + if (!file.try_lock(FILE_LOCK_EXCLUSIVE)) { GRNXX_ERROR() << "failed to lock file: path = " << path; GRNXX_THROW(); } @@ -288,7 +288,7 @@ void PoolImpl::open_temporary_pool(const char *path, Flags, const PoolOptions &options) { path_ = Path::full_path(path); flags_ = GRNXX_IO_TEMPORARY; - files_[0] = File(path_.c_str(), GRNXX_IO_TEMPORARY); + files_[0].open(FILE_TEMPORARY, path_.c_str()); setup_header(options); } @@ -300,29 +300,29 @@ void PoolImpl::open_regular_pool(const char *path, Flags flags, } path_ = Path::full_path(path); - Flags file_flags = Flags::none(); + FileFlags file_flags = FileFlags::none(); if ((~flags & GRNXX_IO_CREATE) && (flags & GRNXX_IO_READ_ONLY)) { flags_ |= GRNXX_IO_READ_ONLY; - file_flags |= GRNXX_IO_READ_ONLY; + file_flags |= FILE_READ_ONLY; } if (flags & GRNXX_IO_CREATE) { flags_ |= GRNXX_IO_CREATE; - file_flags |= GRNXX_IO_CREATE; + file_flags |= FILE_CREATE; } if ((~flags & GRNXX_IO_CREATE) || flags & GRNXX_IO_OPEN) { flags_ |= GRNXX_IO_OPEN; - file_flags |= GRNXX_IO_OPEN; + file_flags |= FILE_OPEN; } - files_[0] = File(path_.c_str(), file_flags); + files_[0].open(file_flags, path_.c_str()); files_[0].set_unlink_at_close(true); if (flags & GRNXX_IO_CREATE) { if (files_[0].size() == 0) { - if (files_[0].lock(GRNXX_IO_EXCLUSIVE_LOCK)) { + if (files_[0].lock(FILE_LOCK_EXCLUSIVE, Duration::seconds(10))) { if (files_[0].size() == 0) { setup_header(options); files_[0].unlock(); - if (!files_[0].lock(GRNXX_IO_SHARED_LOCK)) { + if (!files_[0].lock(FILE_LOCK_SHARED, Duration::seconds(10))) { GRNXX_ERROR() << "failed to lock file: path = " << path << ", full_path = " << path_ << ", flags = " << flags; @@ -345,7 +345,7 @@ void PoolImpl::open_regular_pool(const char *path, Flags flags, Thread::sleep(Duration::milliseconds(10)); } } - if (files_[0].lock(GRNXX_IO_SHARED_LOCK)) { + if (files_[0].lock(FILE_LOCK_SHARED, Duration::seconds(10))) { check_header(); } } @@ -425,14 +425,14 @@ View PoolImpl::mmap_chunk(const ChunkInfo &chunk_info) { } else { File &file = files_[chunk_info.file_id()]; if (!file) { - Flags file_flags = GRNXX_IO_CREATE | GRNXX_IO_OPEN; + FileFlags file_flags = FILE_CREATE_OR_OPEN; if (flags_ & GRNXX_IO_TEMPORARY) { - file_flags = GRNXX_IO_TEMPORARY; + file_flags = FILE_TEMPORARY; } else if (flags_ & GRNXX_IO_READ_ONLY) { - file_flags = GRNXX_IO_READ_ONLY; + file_flags = FILE_READ_ONLY; } const String &path = generate_path(chunk_info.file_id()); - file = File(path.c_str(), file_flags); + file.open(file_flags, path.c_str()); } const uint64_t min_file_size = chunk_info.offset() + chunk_info.size(); Modified: lib/io/view-posix.cpp (+3 -4) =================================================================== --- lib/io/view-posix.cpp 2012-12-06 16:49:13 +0900 (790c67d) +++ lib/io/view-posix.cpp 2012-12-06 18:19:24 +0900 (4aa7031) @@ -153,12 +153,11 @@ void ViewImpl::map_on_file(const File &file, Flags flags, uint64_t offset, size_ = size; int protection_flags = PROT_READ | PROT_WRITE; - if ((file.flags() & GRNXX_IO_READ_ONLY) || - ((~file.flags() & GRNXX_IO_WRITE_ONLY) && - (flags & GRNXX_IO_READ_ONLY))) { + if ((file.flags() & FILE_READ_ONLY) || + ((~file.flags() & FILE_WRITE_ONLY) && (flags & GRNXX_IO_READ_ONLY))) { flags_ |= GRNXX_IO_READ_ONLY; protection_flags = PROT_READ; - } else if ((file.flags() & GRNXX_IO_WRITE_ONLY) || + } else if ((file.flags() & FILE_WRITE_ONLY) || (flags & GRNXX_IO_WRITE_ONLY)) { flags_ |= GRNXX_IO_WRITE_ONLY; protection_flags = PROT_WRITE; Modified: lib/io/view-windows.cpp (+3 -4) =================================================================== --- lib/io/view-windows.cpp 2012-12-06 16:49:13 +0900 (4aa7c62) +++ lib/io/view-windows.cpp 2012-12-06 18:19:24 +0900 (4fe14b5) @@ -163,13 +163,12 @@ void ViewImpl::map_on_file(const File &file, Flags flags, uint64_t offset, int protection_mode = PAGE_READWRITE; DWORD desired_access = FILE_MAP_WRITE; - if ((file.flags() & GRNXX_IO_READ_ONLY) || - ((~file.flags() & GRNXX_IO_WRITE_ONLY) && - (flags & GRNXX_IO_READ_ONLY))) { + if ((file.flags() & FILE_READ_ONLY) || + ((~file.flags() & FILE_WRITE_ONLY) && (flags & GRNXX_IO_READ_ONLY))) { flags_ |= GRNXX_IO_READ_ONLY; protection_mode = PAGE_READONLY; desired_access = FILE_MAP_READ; - } else if (file.flags() & GRNXX_IO_WRITE_ONLY) { + } else if (file.flags() & FILE_WRITE_ONLY) { // Write-only memory mapping is not supported on Windows. GRNXX_ERROR() << "mapping file is write-only: file = " << file; GRNXX_THROW(); Modified: lib/io/view-windows.hpp (+4 -0) =================================================================== --- lib/io/view-windows.hpp 2012-12-06 16:49:13 +0900 (456b30b) +++ lib/io/view-windows.hpp 2012-12-06 18:19:24 +0900 (ccd67d0) @@ -27,6 +27,10 @@ #endif // NOMINMAX #include <windows.h> +#ifdef FILE_READ_ONLY +# undef FILE_READ_ONLY +#endif // FILE_READ_ONLY + namespace grnxx { namespace io { Modified: lib/io/view.hpp (+1 -0) =================================================================== --- lib/io/view.hpp 2012-12-06 16:49:13 +0900 (4c4b747) +++ lib/io/view.hpp 2012-12-06 18:19:24 +0900 (f865cb2) @@ -19,6 +19,7 @@ #define GRNXX_IO_VIEW_HPP #include "file.hpp" +#include "flags.hpp" namespace grnxx { namespace io { Modified: test/test_io_file.cpp (+33 -35) =================================================================== --- test/test_io_file.cpp 2012-12-06 16:49:13 +0900 (11aebcd) +++ test/test_io_file.cpp 2012-12-06 18:19:24 +0900 (2338be9) @@ -28,13 +28,13 @@ void test_create() { assert(!grnxx::io::File::exists(FILE_PATH)); assert(!grnxx::io::File::unlink_if_exists(FILE_PATH)); - grnxx::io::File file(FILE_PATH, grnxx::io::GRNXX_IO_CREATE); + grnxx::io::File file(grnxx::io::FILE_CREATE, FILE_PATH); assert(file.path() == FILE_PATH); assert(file.tell() == 0); assert(file.size() == 0); - file = grnxx::io::File(); + file.close(); assert(grnxx::io::File::exists(FILE_PATH)); grnxx::io::File::unlink(FILE_PATH); @@ -47,11 +47,11 @@ void test_open() { const char FILE_PATH[] = "temp.grn"; grnxx::io::File::unlink_if_exists(FILE_PATH); - grnxx::io::File(FILE_PATH, grnxx::io::GRNXX_IO_CREATE); + grnxx::io::File(grnxx::io::FILE_CREATE, FILE_PATH); - grnxx::io::File file(FILE_PATH); + grnxx::io::File file(grnxx::io::FILE_OPEN, FILE_PATH); - file = grnxx::io::File(); + file.close(); grnxx::io::File::unlink(FILE_PATH); } @@ -60,14 +60,12 @@ void test_create_or_open() { grnxx::io::File::unlink_if_exists(FILE_PATH); - grnxx::io::File file(FILE_PATH, grnxx::io::GRNXX_IO_CREATE | - grnxx::io::GRNXX_IO_OPEN); + grnxx::io::File file(grnxx::io::FILE_CREATE_OR_OPEN, FILE_PATH); - file = grnxx::io::File(); - file = grnxx::io::File(FILE_PATH, grnxx::io::GRNXX_IO_CREATE | - grnxx::io::GRNXX_IO_OPEN); + file.close(); + file.open(grnxx::io::FILE_CREATE_OR_OPEN, FILE_PATH); - file = grnxx::io::File(); + file.close(); grnxx::io::File::unlink(FILE_PATH); } @@ -75,13 +73,13 @@ void test_write() { const char FILE_PATH[] = "temp.grn"; grnxx::io::File::unlink_if_exists(FILE_PATH); - grnxx::io::File file(FILE_PATH, grnxx::io::GRNXX_IO_CREATE); + grnxx::io::File file(grnxx::io::FILE_CREATE, FILE_PATH); assert(file.write("0123456789", 10) == 10); assert(file.tell() == 10); assert(file.size() == 10); - file = grnxx::io::File(); + file.close(); grnxx::io::File::unlink(FILE_PATH); } @@ -90,7 +88,7 @@ void test_resize() { const std::uint64_t FILE_SIZE = 1 << 20; grnxx::io::File::unlink_if_exists(FILE_PATH); - grnxx::io::File file(FILE_PATH, grnxx::io::GRNXX_IO_CREATE); + grnxx::io::File file(grnxx::io::FILE_CREATE, FILE_PATH); file.resize(FILE_SIZE); assert(file.tell() == FILE_SIZE); @@ -100,7 +98,7 @@ void test_resize() { assert(file.tell() == 0); assert(file.size() == 0); - file = grnxx::io::File(); + file.close(); grnxx::io::File::unlink(FILE_PATH); } @@ -109,7 +107,7 @@ void test_seek() { const std::uint64_t FILE_SIZE = 1 << 20; grnxx::io::File::unlink_if_exists(FILE_PATH); - grnxx::io::File file(FILE_PATH, grnxx::io::GRNXX_IO_CREATE); + grnxx::io::File file(grnxx::io::FILE_CREATE, FILE_PATH); file.resize(FILE_SIZE); @@ -126,7 +124,7 @@ void test_seek() { assert(file.seek(-(FILE_SIZE / 2), SEEK_END) == (FILE_SIZE / 2)); assert(file.tell() == (FILE_SIZE / 2)); - file = grnxx::io::File(); + file.close(); grnxx::io::File::unlink(FILE_PATH); } @@ -134,7 +132,7 @@ void test_read() { const char FILE_PATH[] = "temp.grn"; grnxx::io::File::unlink_if_exists(FILE_PATH); - grnxx::io::File file(FILE_PATH, grnxx::io::GRNXX_IO_CREATE); + grnxx::io::File file(grnxx::io::FILE_CREATE, FILE_PATH); file.write("0123456789", 10); file.seek(0); @@ -150,14 +148,14 @@ void test_read() { assert(file.tell() == 8); assert(std::memcmp(buf, "34567", 5) == 0); - file = grnxx::io::File(); + file.close(); grnxx::io::File::unlink(FILE_PATH); } void test_temporary() { const char FILE_PATH[] = "temp.grn"; - grnxx::io::File file(FILE_PATH, grnxx::io::GRNXX_IO_TEMPORARY); + grnxx::io::File file(grnxx::io::FILE_TEMPORARY, FILE_PATH); assert(file.write("0123456789", 10) == 10); assert(file.seek(0) == 0); @@ -168,7 +166,7 @@ void test_temporary() { grnxx::String path = file.path(); - file = grnxx::io::File(); + file.close(); assert(!grnxx::io::File::exists(path.c_str())); } @@ -176,13 +174,13 @@ void test_temporary() { void test_unlink_at_close() { const char FILE_PATH[] = "temp.grn"; - grnxx::io::File file(FILE_PATH, grnxx::io::GRNXX_IO_CREATE); + grnxx::io::File file(grnxx::io::FILE_CREATE, FILE_PATH); file.set_unlink_at_close(true); assert(file.unlink_at_close()); - file = grnxx::io::File(); + file.close(); assert(!grnxx::io::File::exists(FILE_PATH)); } @@ -191,30 +189,30 @@ void test_lock() { const char FILE_PATH[] = "temp.grn"; grnxx::io::File::unlink_if_exists(FILE_PATH); - grnxx::io::File file_1(FILE_PATH, grnxx::io::GRNXX_IO_CREATE); + grnxx::io::File file_1(grnxx::io::FILE_CREATE, FILE_PATH); assert(!file_1.unlock()); - assert(file_1.try_lock(grnxx::io::GRNXX_IO_EXCLUSIVE_LOCK)); - assert(!file_1.try_lock(grnxx::io::GRNXX_IO_SHARED_LOCK)); + assert(file_1.try_lock(grnxx::io::FILE_LOCK_EXCLUSIVE)); + assert(!file_1.try_lock(grnxx::io::FILE_LOCK_SHARED)); assert(file_1.unlock()); - assert(file_1.try_lock(grnxx::io::GRNXX_IO_SHARED_LOCK)); + assert(file_1.try_lock(grnxx::io::FILE_LOCK_SHARED)); assert(file_1.unlock()); assert(!file_1.unlock()); - grnxx::io::File file_2(FILE_PATH, grnxx::io::GRNXX_IO_OPEN); + grnxx::io::File file_2(grnxx::io::FILE_OPEN, FILE_PATH); - assert(file_1.try_lock(grnxx::io::GRNXX_IO_EXCLUSIVE_LOCK)); - assert(!file_2.try_lock(grnxx::io::GRNXX_IO_SHARED_LOCK)); - assert(!file_2.try_lock(grnxx::io::GRNXX_IO_EXCLUSIVE_LOCK)); + assert(file_1.try_lock(grnxx::io::FILE_LOCK_EXCLUSIVE)); + assert(!file_2.try_lock(grnxx::io::FILE_LOCK_SHARED)); + assert(!file_2.try_lock(grnxx::io::FILE_LOCK_EXCLUSIVE)); assert(!file_2.unlock()); assert(file_1.unlock()); - assert(file_1.try_lock(grnxx::io::GRNXX_IO_SHARED_LOCK)); - assert(!file_2.try_lock(grnxx::io::GRNXX_IO_EXCLUSIVE_LOCK)); - assert(file_2.try_lock(grnxx::io::GRNXX_IO_SHARED_LOCK)); + assert(file_1.try_lock(grnxx::io::FILE_LOCK_SHARED)); + assert(!file_2.try_lock(grnxx::io::FILE_LOCK_EXCLUSIVE)); + assert(file_2.try_lock(grnxx::io::FILE_LOCK_SHARED)); assert(file_1.unlock()); - assert(!file_1.try_lock(grnxx::io::GRNXX_IO_EXCLUSIVE_LOCK)); + assert(!file_1.try_lock(grnxx::io::FILE_LOCK_EXCLUSIVE)); assert(file_2.unlock()); file_1 = grnxx::io::File(); Modified: test/test_io_file_info.cpp (+4 -5) =================================================================== --- test/test_io_file_info.cpp 2012-12-06 16:49:13 +0900 (b0ce2fe) +++ test/test_io_file_info.cpp 2012-12-06 18:19:24 +0900 (4694f29) @@ -40,7 +40,7 @@ void test_existent_file() { const std::uint64_t FILE_SIZE = 12345; grnxx::io::File::unlink_if_exists(FILE_PATH); - grnxx::io::File file(FILE_PATH, grnxx::io::GRNXX_IO_CREATE); + grnxx::io::File file(grnxx::io::FILE_CREATE, FILE_PATH); file.resize(FILE_SIZE); grnxx::io::FileInfo file_info(FILE_PATH); @@ -54,7 +54,7 @@ void test_existent_file() { assert(grnxx::io::FileInfo(file)); - file = grnxx::io::File(); + file.close(); grnxx::io::File::unlink(FILE_PATH); } @@ -100,8 +100,7 @@ int main() { assert(!file_info); - grnxx::io::File file("temp.dat", grnxx::io::GRNXX_IO_CREATE | - grnxx::io::GRNXX_IO_TEMPORARY); + grnxx::io::File file(grnxx::io::FILE_TEMPORARY, FILE_PATH); file.resize(12345); file_info = grnxx::io::FileInfo(file); @@ -115,7 +114,7 @@ int main() { assert(!file_info.is_directory()); assert(file_info.size() == 12345); - file = grnxx::io::File(); + file.close(); assert(!grnxx::io::File::exists("temp.dat")); Modified: test/test_io_view.cpp (+1 -1) =================================================================== --- test/test_io_view.cpp 2012-12-06 16:49:13 +0900 (e2379f7) +++ test/test_io_view.cpp 2012-12-06 18:19:24 +0900 (741cdcc) @@ -45,7 +45,7 @@ void test_file_backed_mmap() { const std::uint64_t FILE_SIZE = 1 << 24; const std::uint64_t MMAP_SIZE = 1 << 20; - grnxx::io::File file(FILE_PATH, grnxx::io::GRNXX_IO_TEMPORARY); + grnxx::io::File file(grnxx::io::FILE_TEMPORARY, FILE_PATH); file.resize(FILE_SIZE); assert(file.size() == FILE_SIZE); -------------- next part -------------- HTML����������������������������... Download