perf: add tr_buildBuf() (#2068)

* refactor: add tr_buildBuf() utility
This commit is contained in:
Charles Kerr 2021-10-31 11:38:10 -05:00 committed by GitHub
parent b8c01a581e
commit cedec74d26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 99 deletions

View File

@ -445,20 +445,6 @@ tr_sys_file_t tr_fdFileGetCached(tr_session* s, int torrent_id, tr_file_index_t
return o->fd;
}
bool tr_fdFileGetCachedMTime(tr_session* s, int torrent_id, tr_file_index_t i, time_t* mtime)
{
struct tr_cached_file const* o = fileset_lookup(get_fileset(s), torrent_id, i);
auto info = tr_sys_path_info{};
bool const success = o != nullptr && tr_sys_file_get_info(o->fd, &info, nullptr);
if (success)
{
*mtime = info.last_modified_at;
}
return success;
}
void tr_fdTorrentClose(tr_session* session, int torrent_id)
{
TR_ASSERT(tr_sessionIsLocked(session));

View File

@ -51,8 +51,6 @@ tr_sys_file_t tr_fdFileCheckout(
tr_sys_file_t tr_fdFileGetCached(tr_session* session, int torrent_id, tr_file_index_t file_num, bool doWrite);
bool tr_fdFileGetCachedMTime(tr_session* session, int torrent_id, tr_file_index_t file_num, time_t* mtime);
/**
* Closes a file that's being held by our file repository.
*

View File

@ -2116,20 +2116,20 @@ static void sessionLoadTorrents(void* vdata)
if (odir != TR_BAD_SYS_DIR)
{
char const* name = nullptr;
auto const dirname_sv = std::string_view{ dirname };
auto path = std::string{};
while ((name = tr_sys_dir_read_name(odir, nullptr)) != nullptr)
{
if (tr_str_has_suffix(name, ".torrent"))
{
char* const path = tr_buildPath(dirname, name, nullptr);
tr_ctorSetMetainfoFromFile(data->ctor, path);
tr_buildBuf(path, dirname_sv, "/", name);
tr_ctorSetMetainfoFromFile(data->ctor, path.c_str());
tr_torrent* const tor = tr_torrentNew(data->ctor, nullptr, nullptr);
if (tor != nullptr)
{
torrents.push_back(tor);
}
tr_free(path);
}
}

View File

@ -808,9 +808,11 @@ void tr_torrentGotNewInfoDict(tr_torrent* tor)
static bool hasAnyLocalData(tr_torrent const* tor)
{
auto filename = std::string{};
for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i)
{
if (tr_torrentFindFile2(tor, i, nullptr, nullptr, nullptr))
if (tor->findFile(filename, i))
{
return true;
}
@ -2584,18 +2586,6 @@ bool tr_torrent::checkPiece(tr_piece_index_t piece)
return pass;
}
time_t tr_torrentGetFileMTime(tr_torrent const* tor, tr_file_index_t i)
{
auto mtime = time_t{};
if (!tr_fdFileGetCachedMTime(tor->session, tor->uniqueId, i, &mtime))
{
tr_torrentFindFile2(tor, i, nullptr, nullptr, &mtime);
}
return mtime;
}
/***
****
***/
@ -3305,96 +3295,84 @@ void tr_torrentGotBlock(tr_torrent* tor, tr_block_index_t block)
****
***/
static void find_file_in_dir(
char const* name,
char const* search_dir,
char const** base,
char const** subpath,
tr_sys_path_info* file_info)
std::optional<tr_torrent::tr_found_file_t> tr_torrent::findFile(std::string& filename, tr_file_index_t i) const
{
char* filename = tr_buildPath(search_dir, name, nullptr);
if (tr_sys_path_get_info(filename, 0, file_info, nullptr))
{
*base = search_dir;
*subpath = name;
}
tr_free(filename);
}
bool tr_torrentFindFile2(tr_torrent const* tor, tr_file_index_t fileNum, char const** base, char** subpath, time_t* mtime)
{
TR_ASSERT(tr_isTorrent(tor));
TR_ASSERT(fileNum < tor->info.fileCount);
char* part = nullptr;
char const* s = nullptr;
TR_ASSERT(i < this->info.fileCount);
tr_file const& file = info.files[i];
auto file_info = tr_sys_path_info{};
tr_file const* const file = &tor->info.files[fileNum];
/* look in the download dir... */
char const* b = nullptr;
find_file_in_dir(file->name, tor->downloadDir, &b, &s, &file_info);
/* look in the incomplete dir... */
if (b == nullptr && tor->incompleteDir != nullptr)
if (this->downloadDir != nullptr)
{
find_file_in_dir(file->name, tor->incompleteDir, &b, &s, &file_info);
auto base = std::string_view{ this->downloadDir };
tr_buildBuf(filename, base, "/"sv, file.name);
if (tr_sys_path_get_info(filename.c_str(), 0, &file_info, nullptr))
{
return tr_found_file_t{ file_info, filename, base };
}
tr_buildBuf(filename, base, "/"sv, file.name, ".part"sv);
if (tr_sys_path_get_info(filename.c_str(), 0, &file_info, nullptr))
{
return tr_found_file_t{ file_info, filename, base };
}
}
if (b == nullptr)
if (this->incompleteDir != nullptr)
{
part = tr_torrentBuildPartial(tor, fileNum);
auto const base = std::string_view{ this->incompleteDir };
tr_buildBuf(filename, base, "/"sv, file.name);
if (tr_sys_path_get_info(filename.c_str(), 0, &file_info, nullptr))
{
return tr_found_file_t{ file_info, filename, base };
}
tr_buildBuf(filename, base, "/"sv, file.name, ".part"sv);
if (tr_sys_path_get_info(filename.c_str(), 0, &file_info, nullptr))
{
return tr_found_file_t{ file_info, filename, base };
}
}
/* look for a .part file in the incomplete dir... */
if (b == nullptr && tor->incompleteDir != nullptr)
return {};
}
// TODO: clients that call this should call tr_torrent::findFile() instead
bool tr_torrentFindFile2(tr_torrent const* tor, tr_file_index_t fileNum, char const** base, char** subpath, time_t* mtime)
{
auto filename = std::string{};
auto const found = tor->findFile(filename, fileNum);
if (!found)
{
find_file_in_dir(part, tor->incompleteDir, &b, &s, &file_info);
return false;
}
/* look for a .part file in the download dir... */
if (b == nullptr)
{
find_file_in_dir(part, tor->downloadDir, &b, &s, &file_info);
}
/* return the results */
if (base != nullptr)
{
*base = b;
*base = std::data(found->base);
}
if (subpath != nullptr)
{
*subpath = tr_strdup(s);
*subpath = tr_strndup(std::data(found->subpath), std::size(found->subpath));
}
if (mtime != nullptr)
{
*mtime = file_info.last_modified_at;
*mtime = found->last_modified_at;
}
/* cleanup */
tr_free(part);
return b != nullptr;
return true;
}
// TODO: clients that call this should call tr_torrent::findFile() instead
char* tr_torrentFindFile(tr_torrent const* tor, tr_file_index_t fileNum)
{
char* ret = nullptr;
char const* base = nullptr;
char* subpath = nullptr;
if (tr_torrentFindFile2(tor, fileNum, &base, &subpath, nullptr))
{
ret = tr_buildPath(base, subpath, nullptr);
tr_free(subpath);
}
return ret;
auto filename = std::string{};
auto const found = tor->findFile(filename, fileNum);
return found ? tr_strdup(filename.c_str()) : nullptr;
}
/* Decide whether we should be looking for files in downloadDir or incompleteDir. */

View File

@ -22,6 +22,7 @@
#include "bandwidth.h" /* tr_bandwidth */
#include "bitfield.h"
#include "completion.h" /* tr_completion */
#include "file.h"
#include "session.h" /* tr_sessionLock(), tr_sessionUnlock() */
#include "tr-assert.h"
#include "tr-macros.h"
@ -109,8 +110,6 @@ void tr_torrentSetDateActive(tr_torrent* torrent, time_t activityDate);
void tr_torrentSetDateDone(tr_torrent* torrent, time_t doneDate);
time_t tr_torrentGetFileMTime(tr_torrent const* tor, tr_file_index_t i);
/** Return the mime-type (e.g. "audio/x-flac") that matches more of the
torrent's content than any other mime-type. */
std::string_view tr_torrentPrimaryMimeType(tr_torrent const* tor);
@ -214,20 +213,41 @@ struct tr_torrent
TR_ASSERT(std::size(checked) == info.pieceCount);
checked_pieces_ = checked;
auto filename = std::string{};
for (size_t i = 0; i < info.fileCount; ++i)
{
auto const mtime = tr_torrentGetFileMTime(this, i);
auto const found = this->findFile(filename, i);
auto const mtime = found ? found->last_modified_at : 0;
info.files[i].mtime = mtime;
// if a file has changed, mark its pieces as unchecked
if (mtime != mtimes[i])
if (mtime == 0 || mtime != mtimes[i])
{
checked_pieces_.unsetRange(info.files[i].firstPiece, info.files[i].lastPiece);
}
}
}
/// FINDING FILES
struct tr_found_file_t : public tr_sys_path_info
{
std::string& filename; // /home/foo/Downloads/torrent/01-file-one.txt
std::string_view base; // /home/foo/Downloads
std::string_view subpath; // /torrent/01-file-one.txt
tr_found_file_t(tr_sys_path_info info, std::string& f, std::string_view b)
: tr_sys_path_info{ info }
, filename{ f }
, base{ b }
, subpath{ f.c_str() + std::size(b) + 1 }
{
}
};
std::optional<tr_found_file_t> findFile(std::string& filename, tr_file_index_t i) const;
///
uint8_t obfuscatedHash[SHA_DIGEST_LENGTH];

View File

@ -11,8 +11,10 @@
#include <inttypes.h>
#include <stdarg.h>
#include <stddef.h> /* size_t */
#include <string>
#include <string_view>
#include <time.h> /* time_t */
#include <type_traits>
#include <vector>
#include "tr-macros.h"
@ -80,6 +82,19 @@ uint8_t* tr_loadFile(char const* filename, size_t* size, struct tr_error** error
platform's correct directory separator. */
char* tr_buildPath(char const* first_element, ...) TR_GNUC_NULL_TERMINATED TR_GNUC_MALLOC;
template<typename... T, typename std::enable_if_t<(std::is_convertible_v<T, std::string_view> && ...), bool> = true>
std::string& tr_buildBuf(std::string& setme, T... args)
{
setme.clear();
auto const n = (std::size(std::string_view{ args }) + ...);
if (setme.capacity() < n)
{
setme.reserve(n);
}
((setme += args), ...);
return setme;
}
/**
* @brief Get disk capacity and free disk space (in bytes) for the specified folder.
* @return struct with free and total as zero or positive integer on success, -1 in case of error.