summaryrefslogtreecommitdiff
path: root/src/AbstractDiskWriter.cc
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2012-06-23 21:28:41 +0900
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2012-06-24 16:28:04 +0900
commit96720b297d50d290bda746fab75e0078ac5f975b (patch)
treef2176e1da9b38c69cb0cba9d495201907dbf4625 /src/AbstractDiskWriter.cc
parent38426d744b918088a35e41afd6acbe86a904c441 (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.cc115
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