diff options
| author | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2012-11-27 22:04:59 +0900 |
|---|---|---|
| committer | Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> | 2012-12-03 01:39:10 +0900 |
| commit | f314719618d181036ceebcf45338ab76559daf55 (patch) | |
| tree | f85677a7afad929a7cf320ff93ec4265cda0dc6a /src/Piece.cc | |
| parent | 8ac433a8e9ab8bddd96c62db4bbeac3adce2b3ba (diff) | |
Added --disk-cache option
This option enables disk cache. If SIZE is 0, the disk cache is
disabled. This feature caches the downloaded data in memory, which
grows to at most SIZE bytes. The cache storage is created for aria2
instance and shared by all downloads. The one advantage of the disk
cache is reduce the disk seek time because the data is written in
larger unit and it is reordered by the offset of the file. If the
underlying file is heavily fragmented it is not the case.
Diffstat (limited to 'src/Piece.cc')
| -rw-r--r-- | src/Piece.cc | 111 |
1 files changed, 109 insertions, 2 deletions
diff --git a/src/Piece.cc b/src/Piece.cc index 283a34ee..1f7e4596 100644 --- a/src/Piece.cc +++ b/src/Piece.cc @@ -38,6 +38,11 @@ #include "A2STR.h" #include "util.h" #include "a2functional.h" +#include "WrDiskCache.h" +#include "WrDiskCacheEntry.h" +#include "LogFactory.h" +#include "fmt.h" +#include "DiskAdaptor.h" #ifdef ENABLE_MESSAGE_DIGEST # include "MessageDigest.h" #endif // ENABLE_MESSAGE_DIGEST @@ -45,7 +50,7 @@ namespace aria2 { Piece::Piece():index_(0), length_(0), blockLength_(BLOCK_LENGTH), bitfield_(0), - usedBySegment_(false) + usedBySegment_(false), wrCache_(0) #ifdef ENABLE_MESSAGE_DIGEST , nextBegin_(0) #endif // ENABLE_MESSAGE_DIGEST @@ -56,7 +61,7 @@ Piece::Piece(size_t index, int32_t length, int32_t blockLength) length_(length), blockLength_(blockLength), bitfield_(new BitfieldMan(blockLength_, length)), - usedBySegment_(false) + usedBySegment_(false), wrCache_(0) #ifdef ENABLE_MESSAGE_DIGEST ,nextBegin_(0) #endif // ENABLE_MESSAGE_DIGEST @@ -64,6 +69,7 @@ Piece::Piece(size_t index, int32_t length, int32_t blockLength) Piece::~Piece() { + delete wrCache_; delete bitfield_; } @@ -232,6 +238,56 @@ std::string Piece::getDigest() } } +namespace { +void updateHashWithRead(const SharedHandle<MessageDigest>& mdctx, + const SharedHandle<DiskAdaptor>& adaptor, + int64_t offset, size_t len) +{ + const size_t BUFSIZE = 4096; + unsigned char buf[BUFSIZE]; + ldiv_t res = ldiv(len, BUFSIZE); + for(int j = 0; j < res.quot; ++j) { + ssize_t nread = adaptor->readData(buf, BUFSIZE, offset); + if((size_t)nread != BUFSIZE) { + throw DL_ABORT_EX(fmt(EX_FILE_READ, "n/a", "data is too short")); + } + mdctx->update(buf, nread); + offset += nread; + } + if(res.rem) { + ssize_t nread = adaptor->readData(buf, res.rem, offset); + if(nread != res.rem) { + throw DL_ABORT_EX(fmt(EX_FILE_READ, "n/a", "data is too short")); + } + mdctx->update(buf, nread); + offset += nread; + } +} +} // namespace + +std::string Piece::getDigestWithWrCache +(size_t pieceLength, const SharedHandle<DiskAdaptor>& adaptor) +{ + SharedHandle<MessageDigest> mdctx(MessageDigest::create(hashType_)); + int64_t start = static_cast<int64_t>(index_)*pieceLength; + int64_t goff = start; + if(wrCache_) { + const WrDiskCacheEntry::DataCellSet& dataSet = wrCache_->getDataSet(); + for(WrDiskCacheEntry::DataCellSet::iterator i = dataSet.begin(), + eoi = dataSet.end(); i != eoi; ++i) { + if(goff < (*i)->goff) { + updateHashWithRead(mdctx, adaptor, goff, (*i)->goff - goff); + } + mdctx->update((*i)->data+(*i)->offset, (*i)->len); + goff = (*i)->goff + (*i)->len; + } + updateHashWithRead(mdctx, adaptor, goff, start+length_-goff); + } else { + updateHashWithRead(mdctx, adaptor, goff, length_); + } + return mdctx->digest(); +} + void Piece::destroyHashContext() { mdctx_.reset(); @@ -257,4 +313,55 @@ void Piece::removeUser(cuid_t cuid) users_.erase(std::remove(users_.begin(), users_.end(), cuid), users_.end()); } +void Piece::initWrCache(WrDiskCache* diskCache, + const SharedHandle<DiskAdaptor>& diskAdaptor) +{ + assert(wrCache_ == 0); + wrCache_ = new WrDiskCacheEntry(diskAdaptor); + bool rv = diskCache->add(wrCache_); + assert(rv); +} + +void Piece::flushWrCache(WrDiskCache* diskCache) +{ + assert(wrCache_); + ssize_t size = static_cast<ssize_t>(wrCache_->getSize()); + diskCache->update(wrCache_, -size); + wrCache_->writeToDisk(); +} + +void Piece::clearWrCache(WrDiskCache* diskCache) +{ + assert(wrCache_); + ssize_t size = static_cast<ssize_t>(wrCache_->getSize()); + diskCache->update(wrCache_, -size); + wrCache_->clear(); +} + +void Piece::updateWrCache(WrDiskCache* diskCache, unsigned char* data, + size_t offset, size_t len, int64_t goff) +{ + A2_LOG_DEBUG(fmt("updateWrCache entry=%p", wrCache_)); + assert(wrCache_); + WrDiskCacheEntry::DataCell* cell = new WrDiskCacheEntry::DataCell(); + cell->goff = goff; + cell->data = data; + cell->offset = offset; + cell->len = len; + bool rv; + rv = wrCache_->cacheData(cell); + assert(rv); + rv = diskCache->update(wrCache_, len); + assert(rv); +} + +void Piece::releaseWrCache(WrDiskCache* diskCache) +{ + if(wrCache_) { + diskCache->remove(wrCache_); + delete wrCache_; + wrCache_ = 0; + } +} + } // namespace aria2 |
