diff --git a/.clang-format-ignore b/.clang-format-ignore index 53c1970f7..20f5b0bbb 100644 --- a/.clang-format-ignore +++ b/.clang-format-ignore @@ -3,6 +3,7 @@ # untracked files .*/* build/* +cmake-build-*/* libtransmission/version.h web/node_modules/* diff --git a/.gitignore b/.gitignore index 5d2ebd26b..cb906aeeb 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ po/*.mo third-party/miniupnp/miniupnpcstrings.h web/public_html/transmission-app.js.map .DS_Store + +# CLion IDE build directory +/cmake-build-*/ diff --git a/libtransmission/cache.cc b/libtransmission/cache.cc index d87363a4a..a0a0360be 100644 --- a/libtransmission/cache.cc +++ b/libtransmission/cache.cc @@ -3,8 +3,11 @@ // or any future license endorsed by Mnemosyne LLC. // License text can be found in the licenses/ folder. -#include /* qsort() */ -#include +#include // std::lldiv() +#include // std::distance(), std::next(), std::prev() +#include // std::numeric_limits::max() +#include // std::accumulate() +#include // std::make_pair() #include @@ -14,438 +17,252 @@ #include "cache.h" #include "inout.h" #include "log.h" -#include "ptrarray.h" #include "torrent.h" +#include "torrents.h" #include "tr-assert.h" #include "trevent.h" -#include "utils.h" -/**** -***** -****/ - -struct cache_block +Cache::Key Cache::makeKey(tr_torrent const* torrent, tr_block_info::Location loc) noexcept { - tr_torrent* tor; + return std::make_pair(torrent->uniqueId, loc.block); +} - tr_block_info::Location loc; - uint32_t length; - - time_t time; - - struct evbuffer* evbuf; -}; - -struct tr_cache +std::pair Cache::findContiguous(CIter const begin, CIter const end, CIter const iter) noexcept { - tr_ptrArray blocks; - int max_blocks; - size_t max_bytes; - - size_t disk_writes; - size_t disk_write_bytes; - size_t cache_writes; - size_t cache_write_bytes; -}; - -/**** -***** -****/ - -struct run_info -{ - int pos; - int rank; - time_t last_block_time; - bool is_multi_piece; - bool is_piece_done; - unsigned int len; -}; - -/* return a count of how many contiguous blocks there are starting at this pos */ -static int getBlockRun(tr_cache const* cache, int pos, struct run_info* info) -{ - int const n = tr_ptrArraySize(&cache->blocks); - auto const* const* blocks = (struct cache_block const* const*)tr_ptrArrayBase(&cache->blocks); - struct cache_block const* ref = blocks[pos]; - auto block = ref->loc.block; - int len = 0; - - for (int i = pos; i < n; ++i) + if (iter == end) { - struct cache_block const* b = blocks[i]; + return std::make_pair(end, end); + } - if (b->loc.block != block) + auto span_begin = iter; + for (auto key = iter->key;;) + { + if (span_begin == begin) { break; } - if (b->tor != ref->tor) + --key.second; + auto const prev = std::prev(span_begin); + if (prev->key != key) + { + break; + } + } + + auto span_end = std::next(iter); + for (auto key = iter->key;;) + { + if (span_end == end) { break; } - ++block; - ++len; - } - - if (info != nullptr) - { - struct cache_block const* b = blocks[pos + len - 1]; - info->last_block_time = b->time; - info->is_piece_done = b->tor->hasPiece(b->loc.piece); - info->is_multi_piece = b->loc.piece != blocks[pos]->loc.piece; - info->len = len; - info->pos = pos; - } - - return len; -} - -/* higher rank comes before lower rank */ -static int compareRuns(void const* va, void const* vb) -{ - auto const* const a = static_cast(va); - auto const* const b = static_cast(vb); - return b->rank - a->rank; -} - -enum -{ - MULTIFLAG = 0x1000, - DONEFLAG = 0x2000, - SESSIONFLAG = 0x4000 -}; - -/* Calculte runs - * - Stale runs, runs sitting in cache for a long time or runs not growing, get priority. - * Returns number of runs. - */ -// TODO: return std::vector -static int calcRuns(tr_cache const* cache, struct run_info* runs) -{ - int const n = tr_ptrArraySize(&cache->blocks); - int i = 0; - time_t const now = tr_time(); - - for (int pos = 0; pos < n; pos += runs[i++].len) - { - int rank = getBlockRun(cache, pos, &runs[i]); - - /* This adds ~2 to the relative length of a run for every minute it has - * languished in the cache. */ - rank += (now - runs[i].last_block_time) / 32; - - /* Flushing stale blocks should be a top priority as the probability of them - * growing is very small, for blocks on piece boundaries, and nonexistant for - * blocks inside pieces. */ - rank |= runs[i].is_piece_done ? DONEFLAG : 0; - - /* Move the multi piece runs higher */ - rank |= runs[i].is_multi_piece ? MULTIFLAG : 0; - - runs[i].rank = rank; - } - - qsort(runs, i, sizeof(struct run_info), compareRuns); - return i; -} - -static int flushContiguous(tr_cache* cache, int pos, int n) -{ - int err = 0; - auto* const buf = tr_new(uint8_t, n * tr_block_info::BlockSize); - auto* walk = buf; - auto** blocks = (struct cache_block**)tr_ptrArrayBase(&cache->blocks); - - auto* b = blocks[pos]; - auto* const tor = b->tor; - auto const loc = b->loc; - - for (int i = 0; i < n; ++i) - { - b = blocks[pos + i]; - evbuffer_copyout(b->evbuf, walk, b->length); - walk += b->length; - evbuffer_free(b->evbuf); - tr_free(b); - } - - tr_ptrArrayErase(&cache->blocks, pos, pos + n); - - err = tr_ioWrite(tor, loc, walk - buf, buf); - tr_free(buf); - - ++cache->disk_writes; - cache->disk_write_bytes += walk - buf; - return err; -} - -static int flushRuns(tr_cache* cache, struct run_info* runs, int n) -{ - int err = 0; - - for (int i = 0; err == 0 && i < n; i++) - { - err = flushContiguous(cache, runs[i].pos, runs[i].len); - - for (int j = i + 1; j < n; j++) + ++key.second; + if (span_end->key != key) { - if (runs[j].pos > runs[i].pos) - { - runs[j].pos -= runs[i].len; - } + break; } } - return err; + return std::make_pair(span_begin, span_end); } -static int cacheTrim(tr_cache* cache) +int Cache::writeContiguous(CIter const begin, CIter const end) const { - int err = 0; - - if (tr_ptrArraySize(&cache->blocks) > cache->max_blocks) + // join the blocks together into contiguous memory `buf` + auto buf = std::vector{}; + auto const buflen = std::accumulate( + begin, + end, + size_t{}, + [](size_t sum, auto const& block) { return sum + std::size(block.buf); }); + buf.reserve(buflen); + for (auto iter = begin; iter != end; ++iter) { - /* Amount of cache that should be removed by the flush. This influences how large - * runs can grow as well as how often flushes will happen. */ - int const cacheCutoff = 1 + cache->max_blocks / 4; - auto* const runs = tr_new(struct run_info, tr_ptrArraySize(&cache->blocks)); - int i = 0; - int j = 0; + TR_ASSERT(begin->key.first == iter->key.first); + TR_ASSERT(begin->key.second + std::distance(begin, iter) == iter->key.second); + buf.insert(std::end(buf), std::begin(iter->buf), std::end(iter->buf)); + } + TR_ASSERT(std::size(buf) == buflen); - calcRuns(cache, runs); + // save it + auto* const tor = torrents_.get(begin->key.first); + auto const loc = tor->blockLoc(begin->key.second); - while (j < cacheCutoff) - { - j += runs[i++].len; - } - - err = flushRuns(cache, runs, i); - tr_free(runs); + if (auto const err = tr_ioWrite(tor, loc, std::size(buf), std::data(buf)); err != 0) + { + return err; } - return err; + ++disk_writes_; + disk_write_bytes_ += std::size(buf); + return {}; } -/*** -**** -***/ - -static int getMaxBlocks(int64_t max_bytes) +size_t Cache::getMaxBlocks(int64_t max_bytes) noexcept { return std::lldiv(max_bytes, tr_block_info::BlockSize).quot; } -int tr_cacheSetLimit(tr_cache* cache, int64_t max_bytes) +int Cache::setLimit(int64_t new_limit) { - cache->max_bytes = max_bytes; - cache->max_blocks = getMaxBlocks(max_bytes); + max_bytes_ = new_limit; + max_blocks_ = getMaxBlocks(new_limit); - tr_logAddDebug( - fmt::format("Maximum cache size set to {} ({} blocks)", tr_formatter_mem_B(cache->max_bytes), cache->max_blocks)); + tr_logAddDebug(fmt::format("Maximum cache size set to {} ({} blocks)", tr_formatter_mem_B(max_bytes_), max_blocks_)); - return cacheTrim(cache); + return cacheTrim(); } -int64_t tr_cacheGetLimit(tr_cache const* cache) +Cache::Cache(tr_torrents& torrents, int64_t max_bytes) + : torrents_{ torrents } + , max_blocks_(getMaxBlocks(max_bytes)) + , max_bytes_(max_bytes) { - return cache->max_bytes; -} - -tr_cache* tr_cacheNew(int64_t max_bytes) -{ - auto* const cache = tr_new0(tr_cache, 1); - cache->blocks = {}; - cache->max_bytes = max_bytes; - cache->max_blocks = getMaxBlocks(max_bytes); - return cache; -} - -void tr_cacheFree(tr_cache* cache) -{ - tr_ptrArrayDestruct(&cache->blocks, nullptr); - tr_free(cache); } /*** **** ***/ -static int cache_block_compare(void const* va, void const* vb) -{ - auto const* a = static_cast(va); - auto const* b = static_cast(vb); - - /* primary key: torrent id */ - if (a->tor->uniqueId != b->tor->uniqueId) - { - return a->tor->uniqueId < b->tor->uniqueId ? -1 : 1; - } - - /* secondary key: block # */ - if (a->loc.block != b->loc.block) - { - return a->loc.block < b->loc.block ? -1 : 1; - } - - /* they're equal */ - return 0; -} - -static struct cache_block* findBlock(tr_cache* cache, tr_torrent* torrent, tr_block_info::Location loc) -{ - auto key = cache_block{}; - key.tor = torrent; - key.loc = loc; - return static_cast(tr_ptrArrayFindSorted(&cache->blocks, &key, cache_block_compare)); -} - -int tr_cacheWriteBlock( - tr_cache* cache, - tr_torrent* torrent, - tr_block_info::Location loc, - uint32_t length, - struct evbuffer* writeme) +int Cache::writeBlock(tr_torrent* torrent, tr_block_info::Location loc, uint32_t length, struct evbuffer* writeme) { TR_ASSERT(tr_amInEventThread(torrent->session)); TR_ASSERT(loc.block_offset == 0); TR_ASSERT(torrent->blockSize(loc.block) == length); TR_ASSERT(torrent->blockSize(loc.block) <= evbuffer_get_length(writeme)); - auto* cb = findBlock(cache, torrent, loc); - if (cb == nullptr) + auto const key = makeKey(torrent, loc); + auto iter = std::lower_bound(std::begin(blocks_), std::end(blocks_), key, CompareCacheBlockByKey{}); + if (iter == std::end(blocks_) || iter->key != key) { - cb = tr_new(struct cache_block, 1); - cb->tor = torrent; - cb->loc = loc; - cb->length = length; - cb->evbuf = evbuffer_new(); - tr_ptrArrayInsertSorted(&cache->blocks, cb, cache_block_compare); + iter = blocks_.emplace(iter); + iter->key = key; } - TR_ASSERT(cb->length == length); + iter->time_added = tr_time(); - cb->time = tr_time(); + iter->buf.resize(length); + evbuffer_remove(writeme, std::data(iter->buf), std::size(iter->buf)); - evbuffer_drain(cb->evbuf, evbuffer_get_length(cb->evbuf)); - evbuffer_remove_buffer(writeme, cb->evbuf, cb->length); + ++cache_writes_; + cache_write_bytes_ += length; - cache->cache_writes++; - cache->cache_write_bytes += cb->length; - - return cacheTrim(cache); + return cacheTrim(); } -int tr_cacheReadBlock(tr_cache* cache, tr_torrent* torrent, tr_block_info::Location loc, uint32_t len, uint8_t* setme) +Cache::CIter Cache::getBlock(tr_torrent const* torrent, tr_block_info::Location loc) noexcept { - int err = 0; - - if (auto* const cb = findBlock(cache, torrent, loc); cb != nullptr) + if (auto const [begin, end] = std::equal_range( + std::begin(blocks_), + std::end(blocks_), + makeKey(torrent, loc), + CompareCacheBlockByKey{}); + begin < end) { - evbuffer_copyout(cb->evbuf, setme, len); - } - else - { - err = tr_ioRead(torrent, loc, len, setme); + return begin; } - return err; + return std::end(blocks_); } -int tr_cachePrefetchBlock(tr_cache* cache, tr_torrent* torrent, tr_block_info::Location loc, uint32_t len) +int Cache::readBlock(tr_torrent* torrent, tr_block_info::Location loc, uint32_t len, uint8_t* setme) { - int err = 0; - - if (auto const* const cb = findBlock(cache, torrent, loc); cb == nullptr) + if (auto const iter = getBlock(torrent, loc); iter != std::end(blocks_)) { - err = tr_ioPrefetch(torrent, loc, len); + std::copy_n(std::begin(iter->buf), len, setme); + return {}; } - return err; + return tr_ioRead(torrent, loc, len, setme); +} + +int Cache::prefetchBlock(tr_torrent* torrent, tr_block_info::Location loc, uint32_t len) +{ + if (auto const iter = getBlock(torrent, loc); iter != std::end(blocks_)) + { + return {}; // already have it + } + + return tr_ioPrefetch(torrent, loc, len); } /*** **** ***/ -static int findBlockPos(tr_cache const* cache, tr_torrent* torrent, tr_block_info::Location loc) +int Cache::flushSpan(CIter const begin, CIter const end) { - struct cache_block key; - key.tor = torrent; - key.loc = loc; - return tr_ptrArrayLowerBound(&cache->blocks, &key, cache_block_compare, nullptr); -} - -int tr_cacheFlushDone(tr_cache* cache) -{ - int err = 0; - - if (tr_ptrArraySize(&cache->blocks) > 0) + for (auto walk = begin; walk < end;) { - auto* const runs = tr_new(struct run_info, tr_ptrArraySize(&cache->blocks)); - int i = 0; - int const n = calcRuns(cache, runs); + auto const [contig_begin, contig_end] = findContiguous(begin, end, walk); - while (i < n && (runs[i].is_piece_done || runs[i].is_multi_piece)) + if (auto const err = writeContiguous(contig_begin, contig_end); err != 0) { - runs[i++].rank |= SESSIONFLAG; + return err; } - err = flushRuns(cache, runs, i); - tr_free(runs); + walk = contig_end; } - return err; + blocks_.erase(begin, end); + return {}; } -int tr_cacheFlushFile(tr_cache* cache, tr_torrent* torrent, tr_file_index_t i) +int Cache::flushFile(tr_torrent* torrent, tr_file_index_t i) { - auto const [begin, end] = tr_torGetFileBlockSpan(torrent, i); + auto const compare = CompareCacheBlockByKey{}; + auto const tor_id = torrent->uniqueId; + auto const [block_begin, block_end] = tr_torGetFileBlockSpan(torrent, i); - int const pos = findBlockPos(cache, torrent, torrent->blockLoc(begin)); + return flushSpan( + std::lower_bound(std::begin(blocks_), std::end(blocks_), std::make_pair(tor_id, block_begin), compare), + std::lower_bound(std::begin(blocks_), std::end(blocks_), std::make_pair(tor_id, block_end), compare)); +} - tr_logAddTrace(fmt::format("flushing file {} from cache to disk: blocks [{}...{})", i, begin, end)); +int Cache::flushTorrent(tr_torrent* torrent) +{ + auto const compare = CompareCacheBlockByKey{}; + auto const tor_id = torrent->uniqueId; - /* flush out all the blocks in that file */ - int err = 0; - while (err == 0 && pos < tr_ptrArraySize(&cache->blocks)) + return flushSpan( + std::lower_bound(std::begin(blocks_), std::end(blocks_), std::make_pair(tor_id, 0), compare), + std::lower_bound(std::begin(blocks_), std::end(blocks_), std::make_pair(tor_id + 1, 0), compare)); +} + +int Cache::flushOldest() +{ + auto const oldest = std::min_element( + std::begin(blocks_), + std::end(blocks_), + [](auto const& a, auto const& b) { return a.time_added < b.time_added; }); + + if (oldest == std::end(blocks_)) // nothing to flush { - auto const* b = static_cast(tr_ptrArrayNth(&cache->blocks, pos)); - - if (b->tor != torrent) - { - break; - } - - if (b->loc.block < begin || b->loc.block >= end) - { - break; - } - - err = flushContiguous(cache, pos, getBlockRun(cache, pos, nullptr)); + return 0; } - return err; -} + auto const [begin, end] = findContiguous(std::begin(blocks_), std::end(blocks_), oldest); -int tr_cacheFlushTorrent(tr_cache* cache, tr_torrent* torrent) -{ - int err = 0; - int const pos = findBlockPos(cache, torrent, {}); - - /* flush out all the blocks in that torrent */ - while (err == 0 && pos < tr_ptrArraySize(&cache->blocks)) + if (auto const err = writeContiguous(begin, end); err != 0) { - auto const* b = static_cast(tr_ptrArrayNth(&cache->blocks, pos)); - - if (b->tor != torrent) - { - break; - } - - err = flushContiguous(cache, pos, getBlockRun(cache, pos, nullptr)); + return err; } - return err; + blocks_.erase(begin, end); + return 0; +} + +int Cache::cacheTrim() +{ + while (std::size(blocks_) > max_blocks_) + { + if (auto const err = flushOldest(); err != 0) + { + return err; + } + } + + return 0; } diff --git a/libtransmission/cache.h b/libtransmission/cache.h index dca723cd4..c00b7ac2e 100644 --- a/libtransmission/cache.h +++ b/libtransmission/cache.h @@ -10,48 +10,88 @@ #endif #include // intX_t, uintX_t +#include // std::pair +#include #include "transmission.h" #include "block-info.h" +class tr_torrents; struct evbuffer; -struct tr_cache; struct tr_torrent; -/*** -**** -***/ +class Cache +{ +public: + Cache(tr_torrents& torrents, int64_t max_bytes); -tr_cache* tr_cacheNew(int64_t max_bytes); + int setLimit(int64_t new_limit); -void tr_cacheFree(tr_cache*); + [[nodiscard]] constexpr auto getLimit() const noexcept + { + return max_bytes_; + } -/*** -**** -***/ + int writeBlock(tr_torrent* torrent, tr_block_info::Location loc, uint32_t length, struct evbuffer* writeme); + int readBlock(tr_torrent* torrent, tr_block_info::Location loc, uint32_t len, uint8_t* setme); + int prefetchBlock(tr_torrent* torrent, tr_block_info::Location loc, uint32_t len); + int flushTorrent(tr_torrent* torrent); + int flushFile(tr_torrent* torrent, tr_file_index_t file); -int tr_cacheSetLimit(tr_cache* cache, int64_t max_bytes); +private: + using Key = std::pair; -int64_t tr_cacheGetLimit(tr_cache const*); + struct CacheBlock + { + Key key; + std::vector buf; + time_t time_added = {}; + }; -int tr_cacheWriteBlock( - tr_cache* cache, - tr_torrent* torrent, - tr_block_info::Location loc, - uint32_t len, - struct evbuffer* writeme); + using Blocks = std::vector; + using CIter = Blocks::const_iterator; -int tr_cacheReadBlock(tr_cache* cache, tr_torrent* torrent, tr_block_info::Location loc, uint32_t len, uint8_t* setme); + struct CompareCacheBlockByKey + { + [[nodiscard]] constexpr bool operator()(Key const& key, CacheBlock const& block) + { + return key < block.key; + } + [[nodiscard]] constexpr bool operator()(CacheBlock const& block, Key const& key) + { + return block.key < key; + } + }; -int tr_cachePrefetchBlock(tr_cache* cache, tr_torrent* torrent, tr_block_info::Location loc, uint32_t len); + [[nodiscard]] static Key makeKey(tr_torrent const* torrent, tr_block_info::Location loc) noexcept; -/*** -**** -***/ + [[nodiscard]] static std::pair findContiguous(CIter const begin, CIter const end, CIter const iter) noexcept; -int tr_cacheFlushDone(tr_cache* cache); + // @return any error code from tr_ioWrite() + [[nodiscard]] int writeContiguous(CIter const begin, CIter const end) const; -int tr_cacheFlushTorrent(tr_cache* cache, tr_torrent* torrent); + // @return any error code from writeContiguous() + [[nodiscard]] int flushSpan(CIter const begin, CIter const end); -int tr_cacheFlushFile(tr_cache* cache, tr_torrent* torrent, tr_file_index_t file); + // @return any error code from writeContiguous() + [[nodiscard]] int flushOldest(); + + // @return any error code from writeContiguous() + [[nodiscard]] int cacheTrim(); + + [[nodiscard]] static size_t getMaxBlocks(int64_t max_bytes) noexcept; + + [[nodiscard]] CIter getBlock(tr_torrent const* torrent, tr_block_info::Location loc) noexcept; + + tr_torrents& torrents_; + + Blocks blocks_ = {}; + size_t max_blocks_ = 0; + size_t max_bytes_ = 0; + + mutable size_t disk_writes_ = 0; + mutable size_t disk_write_bytes_ = 0; + mutable size_t cache_writes_ = 0; + mutable size_t cache_write_bytes_ = 0; +}; diff --git a/libtransmission/inout.cc b/libtransmission/inout.cc index 9accfed63..2d5d6f2b8 100644 --- a/libtransmission/inout.cc +++ b/libtransmission/inout.cc @@ -242,7 +242,7 @@ std::optional recalculateHash(tr_torrent* tor, tr_piece_index_ while (bytes_left != 0) { size_t const len = std::min(bytes_left, std::size(buffer)); - if (auto const success = tr_cacheReadBlock(tor->session->cache, tor, loc, len, std::data(buffer)) == 0; !success) + if (auto const success = tor->session->cache->readBlock(tor, loc, len, std::data(buffer)) == 0; !success) { tr_sha1_final(sha); return {}; diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc index 6dcd8c4cf..fc2afb50d 100644 --- a/libtransmission/peer-msgs.cc +++ b/libtransmission/peer-msgs.cc @@ -1444,11 +1444,7 @@ static void prefetchPieces(tr_peerMsgsImpl* msgs) { if (auto& req = requests[i]; !req.prefetched) { - tr_cachePrefetchBlock( - msgs->session->cache, - msgs->torrent, - msgs->torrent->pieceLoc(req.index, req.offset), - req.length); + msgs->session->cache->prefetchBlock(msgs->torrent, msgs->torrent->pieceLoc(req.index, req.offset), req.length); req.prefetched = true; } } @@ -1920,8 +1916,7 @@ static int clientGotBlock(tr_peerMsgsImpl* msgs, struct evbuffer* data, struct p *** Save the block **/ - if (int const - err = tr_cacheWriteBlock(msgs->session->cache, tor, tor->pieceLoc(req->index, req->offset), req->length, data); + if (int const err = msgs->session->cache->writeBlock(tor, tor->pieceLoc(req->index, req->offset), req->length, data); err != 0) { return err; @@ -2218,8 +2213,7 @@ static size_t fillOutputBuffer(tr_peerMsgsImpl* msgs, time_t now) evbuffer_add_uint32(out, req.offset); evbuffer_reserve_space(out, req.length, iovec, 1); - bool err = tr_cacheReadBlock( - msgs->session->cache, + bool err = msgs->session->cache->readBlock( msgs->torrent, msgs->torrent->pieceLoc(req.index, req.offset), req.length, diff --git a/libtransmission/session.cc b/libtransmission/session.cc index 0588c99a6..8018f13bf 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -566,11 +566,6 @@ static void onSaveTimer(evutil_socket_t /*fd*/, short /*what*/, void* vsession) { auto* session = static_cast(vsession); - if (tr_cacheFlushDone(session->cache) != 0) - { - tr_logAddError("Error while flushing completed pieces from cache"); - } - for (auto* const tor : session->torrents()) { tr_torrentSave(tor); @@ -606,7 +601,7 @@ tr_session* tr_sessionInit(char const* config_dir, bool messageQueuingEnabled, t auto* session = new tr_session{}; session->udp_socket = TR_BAD_SOCKET; session->udp6_socket = TR_BAD_SOCKET; - session->cache = tr_cacheNew(1024 * 1024 * 2); + session->cache = std::make_unique(session->torrents(), 1024 * 1024 * 2); session->magicNumber = SESSION_MAGIC_NUMBER; session->session_id = tr_session_id_new(); bandwidthGroupRead(session, config_dir); @@ -1880,8 +1875,7 @@ static void sessionCloseImplStart(tr_session* session) it won't be idle until the announce events are sent... */ session->web->closeSoon(); - tr_cacheFree(session->cache); - session->cache = nullptr; + session->cache.reset(); /* saveTimer is not used at this point, reusing for UDP shutdown wait */ TR_ASSERT(session->saveTimer == nullptr); @@ -2238,14 +2232,14 @@ void tr_sessionSetCacheLimit_MB(tr_session* session, int max_bytes) { TR_ASSERT(tr_isSession(session)); - tr_cacheSetLimit(session->cache, tr_toMemBytes(max_bytes)); + session->cache->setLimit(tr_toMemBytes(max_bytes)); } int tr_sessionGetCacheLimit_MB(tr_session const* session) { TR_ASSERT(tr_isSession(session)); - return tr_toMemMB(tr_cacheGetLimit(session->cache)); + return tr_toMemMB(session->cache->getLimit()); } /*** @@ -2932,12 +2926,12 @@ static int bandwidthGroupWrite(tr_session const* session, std::string_view confi void tr_session::closeTorrentFiles(tr_torrent* tor) noexcept { - tr_cacheFlushTorrent(this->cache, tor); + this->cache->flushTorrent(tor); openFiles().closeTorrent(tor->uniqueId); } void tr_session::closeTorrentFile(tr_torrent* tor, tr_file_index_t file_num) noexcept { - tr_cacheFlushFile(this->cache, tor, file_num); + this->cache->flushFile(tor, file_num); openFiles().closeFile(tor->uniqueId, file_num); } diff --git a/libtransmission/session.h b/libtransmission/session.h index af5a03f6c..f63a4b3b9 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -26,6 +26,7 @@ #include "announce-list.h" #include "bandwidth.h" +#include "cache.h" #include "interned-string.h" #include "net.h" // tr_socket_t #include "open-files.h" @@ -54,7 +55,6 @@ struct tr_announcer; struct tr_announcer_udp; struct tr_bindsockets; struct BlocklistFile; -struct tr_cache; struct tr_fdInfo; struct tr_bindinfo @@ -296,60 +296,60 @@ public: TR_SCRIPT_ON_TORRENT_DONE_SEEDING } } }; - bool isPortRandom; - bool isPexEnabled; - bool isDHTEnabled; - bool isUTPEnabled; - bool isLPDEnabled; - bool isPrefetchEnabled; + bool isPortRandom = false; + bool isPexEnabled = false; + bool isDHTEnabled = false; + bool isUTPEnabled = false; + bool isLPDEnabled = false; + bool isPrefetchEnabled = false; bool is_closing_ = false; - bool isClosed; - bool isRatioLimited; - bool isIdleLimited; - bool isIncompleteFileNamingEnabled; - bool pauseAddedTorrent; - bool deleteSourceTorrent; - bool scrapePausedTorrents; + bool isClosed = false; + bool isRatioLimited = false; + bool isIdleLimited = false; + bool isIncompleteFileNamingEnabled = false; + bool pauseAddedTorrent = false; + bool deleteSourceTorrent = false; + bool scrapePausedTorrents = false; - uint8_t peer_id_ttl_hours; + uint8_t peer_id_ttl_hours = 0; - bool stalledEnabled; - bool queueEnabled[2]; - int queueSize[2]; - int queueStalledMinutes; + bool stalledEnabled = false; + bool queueEnabled[2] = { false, false }; + int queueSize[2] = { 0, 0 }; + int queueStalledMinutes = 0; - int umask; + int umask = 0; - unsigned int speedLimit_Bps[2]; - bool speedLimitEnabled[2]; + unsigned int speedLimit_Bps[2] = { 0, 0 }; + bool speedLimitEnabled[2] = { false, false }; struct tr_turtle_info turtle; - int magicNumber; + int magicNumber = 0; tr_encryption_mode encryptionMode; tr_preallocation_mode preallocationMode; - struct event_base* event_base; - struct evdns_base* evdns_base; - struct tr_event_handle* events; + struct event_base* event_base = nullptr; + struct evdns_base* evdns_base = nullptr; + struct tr_event_handle* events = nullptr; uint16_t peerCount = 0; uint16_t peerLimit = 200; uint16_t peerLimitPerTorrent = 50; - int uploadSlotsPerTorrent; + int uploadSlotsPerTorrent = 0; /* The UDP sockets used for the DHT and uTP. */ tr_port udp_port; tr_socket_t udp_socket = TR_BAD_SOCKET; tr_socket_t udp6_socket = TR_BAD_SOCKET; - unsigned char* udp6_bound; - struct event* udp_event; - struct event* udp6_event; + unsigned char* udp6_bound = nullptr; + struct event* udp_event = nullptr; + struct event* udp6_event = nullptr; - struct event* utp_timer; + struct event* utp_timer = nullptr; /* The open port on the local machine for incoming peer requests */ tr_port private_peer_port; @@ -380,10 +380,10 @@ public: std::string torrent_dir; std::vector> blocklists; - struct tr_peerMgr* peerMgr; - struct tr_shared* shared; + struct tr_peerMgr* peerMgr = nullptr; + struct tr_shared* shared = nullptr; - struct tr_cache* cache; + std::unique_ptr cache; class WebMediator final : public tr_web::Mediator { diff --git a/libtransmission/webseed.cc b/libtransmission/webseed.cc index 9f4ccd32e..b548d2404 100644 --- a/libtransmission/webseed.cc +++ b/libtransmission/webseed.cc @@ -316,7 +316,7 @@ public: { auto const len = evbuffer_get_length(buf); TR_ASSERT(tor->blockSize(this->loc.block) == len); - tr_cacheWriteBlock(tor->session->cache, tor, this->loc, len, buf); + tor->session->cache->writeBlock(tor, this->loc, len, buf); webseed->publishGotBlock(tor, this->loc); TR_ASSERT(evbuffer_get_length(buf) == 0); } diff --git a/tests/libtransmission/move-test.cc b/tests/libtransmission/move-test.cc index b3366346d..5eeaf8e40 100644 --- a/tests/libtransmission/move-test.cc +++ b/tests/libtransmission/move-test.cc @@ -89,12 +89,7 @@ TEST_P(IncompleteDirTest, incompleteDir) auto const test_incomplete_dir_threadfunc = [](void* vdata) noexcept { auto* data = static_cast(vdata); - tr_cacheWriteBlock( - data->session->cache, - data->tor, - data->tor->pieceLoc(0, data->offset), - tr_block_info::BlockSize, - data->buf); + data->session->cache->writeBlock(data->tor, data->tor->pieceLoc(0, data->offset), tr_block_info::BlockSize, data->buf); tr_torrentGotBlock(data->tor, data->block); data->done = true; };