diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2012-06-23 21:28:41 +0900 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2012-06-24 16:28:04 +0900 |
| commit | 96720b297d50d290bda746fab75e0078ac5f975b (patch) | |
| tree | f2176e1da9b38c69cb0cba9d495201907dbf4625 /src/AbstractDiskWriter.cc | |
| parent | 38426d744b918088a35e41afd6acbe86a904c441 (diff) | |
Added --enable-mmap option.
If this option is used, map files into memory using mmap(2). This
option is experimental.
Diffstat (limited to 'src/AbstractDiskWriter.cc')
| -rw-r--r-- | src/AbstractDiskWriter.cc | 115 |
1 files changed, 97 insertions, 18 deletions
diff --git a/src/AbstractDiskWriter.cc b/src/AbstractDiskWriter.cc index 11888bc0..4e8d6c76 100644 --- a/src/AbstractDiskWriter.cc +++ b/src/AbstractDiskWriter.cc @@ -35,6 +35,9 @@ #include "AbstractDiskWriter.h" #include <unistd.h> +#ifdef HAVE_MMAP +# include <sys/mman.h> +#endif // HAVE_MMAP #include <cerrno> #include <cstring> @@ -48,13 +51,17 @@ #include "fmt.h" #include "DownloadFailureException.h" #include "error_code.h" +#include "LogFactory.h" namespace aria2 { AbstractDiskWriter::AbstractDiskWriter(const std::string& filename) : filename_(filename), fd_(-1), - readOnly_(false) + readOnly_(false), + enableMmap_(false), + mapaddr_(0), + maplen_(0) {} AbstractDiskWriter::~AbstractDiskWriter() @@ -77,6 +84,20 @@ void AbstractDiskWriter::openFile(off_t totalLength) void AbstractDiskWriter::closeFile() { +#ifdef HAVE_MMAP + if(mapaddr_) { + int rv = munmap(mapaddr_, maplen_); + if(rv == -1) { + int errNum = errno; + A2_LOG_ERROR(fmt("munmap for file %s failed: %s", + filename_.c_str(), strerror(errNum))); + } else { + A2_LOG_INFO(fmt("munmap for file %s succeeded", filename_.c_str())); + } + mapaddr_ = 0; + maplen_ = 0; + } +#endif // HAVE_MMAP if(fd_ != -1) { close(fd_); fd_ = -1; @@ -124,25 +145,46 @@ void AbstractDiskWriter::createFile(int addFlags) } } -ssize_t AbstractDiskWriter::writeDataInternal(const unsigned char* data, size_t len) +ssize_t AbstractDiskWriter::writeDataInternal(const unsigned char* data, + size_t len, off_t offset) { - ssize_t writtenLength = 0; - while((size_t)writtenLength < len) { - ssize_t ret = 0; - while((ret = write(fd_, data+writtenLength, len-writtenLength)) == -1 && errno == EINTR); - if(ret == -1) { - return -1; + if(mapaddr_) { + memcpy(mapaddr_ + offset, data, len); + return len; + } else { + ssize_t writtenLength = 0; + seek(offset); + while((size_t)writtenLength < len) { + ssize_t ret = 0; + while((ret = write(fd_, data+writtenLength, len-writtenLength)) == -1 && + errno == EINTR); + if(ret == -1) { + return -1; + } + writtenLength += ret; } - writtenLength += ret; + return writtenLength; } - return writtenLength; } -ssize_t AbstractDiskWriter::readDataInternal(unsigned char* data, size_t len) +ssize_t AbstractDiskWriter::readDataInternal(unsigned char* data, size_t len, + off_t offset) { - ssize_t ret = 0; - while((ret = read(fd_, data, len)) == -1 && errno == EINTR); - return ret; + if(mapaddr_) { + ssize_t readlen; + if(offset > maplen_) { + readlen = 0; + } else { + readlen = std::min(static_cast<size_t>(maplen_ - offset), len); + } + memcpy(data, mapaddr_ + offset, readlen); + return readlen; + } else { + ssize_t ret = 0; + seek(offset); + while((ret = read(fd_, data, len)) == -1 && errno == EINTR); + return ret; + } } void AbstractDiskWriter::seek(off_t offset) @@ -156,10 +198,43 @@ void AbstractDiskWriter::seek(off_t offset) } } +void AbstractDiskWriter::ensureMmapWrite(size_t len, off_t offset) +{ +#ifdef HAVE_MMAP + if(enableMmap_) { + if(mapaddr_) { + if(static_cast<off_t>(len + offset) > maplen_) { + munmap(mapaddr_, maplen_); + mapaddr_ = 0; + maplen_ = 0; + enableMmap_ = false; + } + } else { + off_t filesize = size(); + if(static_cast<off_t>(len + offset) <= filesize) { + mapaddr_ = reinterpret_cast<unsigned char*> + (mmap(0, size(), PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0)); + if(mapaddr_) { + A2_LOG_DEBUG(fmt("mmap for file %s succeeded, length=%lld", + filename_.c_str(), + static_cast<long long int>(filesize))); + maplen_ = filesize; + } else { + int errNum = errno; + A2_LOG_INFO(fmt("mmap for file %s failed: %s", + filename_.c_str(), strerror(errNum))); + enableMmap_ = false; + } + } + } + } +#endif // HAVE_MMAP +} + void AbstractDiskWriter::writeData(const unsigned char* data, size_t len, off_t offset) { - seek(offset); - if(writeDataInternal(data, len) < 0) { + ensureMmapWrite(len, offset); + if(writeDataInternal(data, len, offset) < 0) { int errNum = errno; // If errno is ENOSPC(not enough space in device), throw // DownloadFailureException and abort download instantly. @@ -184,8 +259,7 @@ void AbstractDiskWriter::writeData(const unsigned char* data, size_t len, off_t ssize_t AbstractDiskWriter::readData(unsigned char* data, size_t len, off_t offset) { ssize_t ret; - seek(offset); - if((ret = readDataInternal(data, len)) < 0) { + if((ret = readDataInternal(data, len, offset)) < 0) { int errNum = errno; throw DL_ABORT_EX3 (errNum, @@ -287,4 +361,9 @@ void AbstractDiskWriter::disableReadOnly() readOnly_ = false; } +void AbstractDiskWriter::enableMmap() +{ + enableMmap_ = true; +} + } // namespace aria2 |
