1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-02-22 06:00:41 +00:00

perf: lookup tables for faster torrent searching. (#1778)

* perf: lookup tables for faster torrent searching.

tr_torrentFindFromId(), tr_torrentFindFromHashString(), and
tr_torrentFindFromHash() are now O(log N) instead of O(N) where
N is the number of torrents.

* build: fix clang-tidy warning

error: integer to pointer cast pessimizes optimization opportunities
[performance-no-int-to-ptr,-warnings-as-errors] from TR_BAD_SYS_FILE
which expands to INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
This commit is contained in:
Charles Kerr 2021-09-09 00:22:29 -05:00 committed by GitHub
parent 696b0bcab9
commit c0ed82533c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 104 additions and 68 deletions

View file

@ -43,6 +43,7 @@
#include "platform.h" /* tr_lock, tr_getTorrentDir() */
#include "platform-quota.h" /* tr_device_info_free() */
#include "port-forwarding.h"
#include "ptrarray.h"
#include "rpc-server.h"
#include "session.h"
#include "session-id.h"
@ -635,6 +636,9 @@ tr_session* tr_sessionInit(char const* configDir, bool messageQueuingEnabled, tr
session->cache = tr_cacheNew(1024 * 1024 * 2);
session->magicNumber = SESSION_MAGIC_NUMBER;
session->session_id = tr_session_id_new();
session->torrentsSortedByHash = TR_PTR_ARRAY_INIT;
session->torrentsSortedByHashString = TR_PTR_ARRAY_INIT;
session->torrentsSortedById = TR_PTR_ARRAY_INIT;
tr_bandwidthConstruct(&session->bandwidth, session, NULL);
tr_variantInitList(&session->removedTorrents, 0);
@ -2137,6 +2141,9 @@ void tr_sessionClose(tr_session* session)
}
tr_device_info_free(session->downloadDir);
tr_ptrArrayDestruct(&session->torrentsSortedByHash, NULL);
tr_ptrArrayDestruct(&session->torrentsSortedByHashString, NULL);
tr_ptrArrayDestruct(&session->torrentsSortedById, NULL);
tr_free(session->torrentDoneScript);
tr_free(session->configDir);
tr_free(session->resumeDir);
@ -3117,3 +3124,68 @@ int tr_sessionCountQueueFreeSlots(tr_session* session, tr_direction dir)
return max - active_count;
}
static int compareTorrentsById(void const* va, void const* vb)
{
tr_torrent const* const a = va;
tr_torrent const* const b = vb;
return a->uniqueId - b->uniqueId;
}
static int compareTorrentsByHashString(void const* va, void const* vb)
{
tr_torrent const* const a = va;
tr_torrent const* const b = vb;
return evutil_ascii_strcasecmp(a->info.hashString, b->info.hashString);
}
static int compareTorrentsByHash(void const* va, void const* vb)
{
tr_torrent const* const a = va;
tr_torrent const* const b = vb;
return memcmp(a->info.hash, b->info.hash, SHA_DIGEST_LENGTH);
}
void tr_sessionAddTorrent(tr_session* session, tr_torrent* tor)
{
/* add tor to tr_session.torrentList */
tor->next = session->torrentList;
session->torrentList = tor;
/* add tor to tr_session.torrentsSortedByFoo */
tr_ptrArrayInsertSorted(&session->torrentsSortedById, tor, compareTorrentsById);
tr_ptrArrayInsertSorted(&session->torrentsSortedByHashString, tor, compareTorrentsByHashString);
tr_ptrArrayInsertSorted(&session->torrentsSortedByHash, tor, compareTorrentsByHash);
/* increment the torrent count */
++session->torrentCount;
}
void tr_sessionRemoveTorrent(tr_session* session, tr_torrent* tor)
{
/* remove tor from tr_session.torrentList */
if (tor == session->torrentList)
{
session->torrentList = tor->next;
}
else
{
for (tr_torrent* t = session->torrentList; t != NULL; t = t->next)
{
if (t->next == tor)
{
t->next = tor->next;
break;
}
}
}
/* remove tor from tr_session.torrentsSortedByFoo */
tr_ptrArrayRemoveSortedPointer(&session->torrentsSortedById, tor, compareTorrentsById);
tr_ptrArrayRemoveSortedPointer(&session->torrentsSortedByHashString, tor, compareTorrentsByHashString);
tr_ptrArrayRemoveSortedPointer(&session->torrentsSortedByHash, tor, compareTorrentsByHash);
/* decrement the torrent count */
TR_ASSERT(session->torrentCount >= 1);
session->torrentCount--;
}

View file

@ -17,6 +17,7 @@
#include "bandwidth.h"
#include "bitfield.h"
#include "net.h"
#include "ptrarray.h"
#include "tr-macros.h"
#include "utils.h"
#include "variant.h"
@ -177,6 +178,9 @@ struct tr_session
int torrentCount;
tr_torrent* torrentList;
tr_ptrArray torrentsSortedByHash;
tr_ptrArray torrentsSortedByHashString;
tr_ptrArray torrentsSortedById;
char* torrentDoneScript;
@ -322,4 +326,7 @@ void tr_sessionGetNextQueuedTorrents(tr_session* session, tr_direction dir, size
int tr_sessionCountQueueFreeSlots(tr_session* session, tr_direction);
void tr_sessionAddTorrent(tr_session* session, tr_torrent* tor);
void tr_sessionRemoveTorrent(tr_session* session, tr_torrent* tor);
TR_END_DECLS

View file

@ -73,49 +73,40 @@ int tr_torrentId(tr_torrent const* tor)
return tor != NULL ? tor->uniqueId : -1;
}
static int compareKeyToTorrentId(void const* va, void const* vb)
{
tr_torrent const* const a = va;
int const b = *(int const*)vb;
return a->uniqueId - b;
}
tr_torrent* tr_torrentFindFromId(tr_session* session, int id)
{
tr_torrent* tor = NULL;
return tr_ptrArrayFindSorted(&session->torrentsSortedById, &id, compareKeyToTorrentId);
}
while ((tor = tr_torrentNext(session, tor)) != NULL)
{
if (tor->uniqueId == id)
{
return tor;
}
}
return NULL;
static int compareKeyToTorrentHashString(void const* va, void const* vb)
{
tr_torrent const* const a = va;
char const* const b = vb;
return evutil_ascii_strcasecmp(a->info.hashString, b);
}
tr_torrent* tr_torrentFindFromHashString(tr_session* session, char const* str)
{
tr_torrent* tor = NULL;
return tr_ptrArrayFindSorted(&session->torrentsSortedByHashString, str, compareKeyToTorrentHashString);
}
while ((tor = tr_torrentNext(session, tor)) != NULL)
{
if (evutil_ascii_strcasecmp(str, tor->info.hashString) == 0)
{
return tor;
}
}
return NULL;
static int compareKeyToTorrentHash(void const* va, void const* vb)
{
tr_torrent const* const a = va;
uint8_t const* const b = vb;
return memcmp(a->info.hash, b, SHA_DIGEST_LENGTH);
}
tr_torrent* tr_torrentFindFromHash(tr_session* session, uint8_t const* torrentHash)
{
tr_torrent* tor = NULL;
while ((tor = tr_torrentNext(session, tor)) != NULL)
{
if ((*tor->info.hash == *torrentHash) && (memcmp(tor->info.hash, torrentHash, SHA_DIGEST_LENGTH) == 0))
{
return tor;
}
}
return NULL;
return tr_ptrArrayFindSorted(&session->torrentsSortedByHash, torrentHash, compareKeyToTorrentHash);
}
tr_torrent* tr_torrentFindFromMagnetLink(tr_session* session, char const* magnet)
@ -975,24 +966,7 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
tr_torrentSetIdleLimit(tor, tr_sessionGetIdleLimit(tor->session));
}
/* add the torrent to tr_session.torrentList */
session->torrentCount++;
if (session->torrentList == NULL)
{
session->torrentList = tor;
}
else
{
tr_torrent* it = session->torrentList;
while (it->next != NULL)
{
it = it->next;
}
it->next = tor;
}
tr_sessionAddTorrent(session, tor);
/* if we don't have a local .torrent file already, assume the torrent is new */
isNewTorrent = !tr_sys_path_exists(tor->info.torrent, NULL);
@ -1689,25 +1663,7 @@ static void freeTorrent(tr_torrent* tor)
tr_free(tor->downloadDir);
tr_free(tor->incompleteDir);
if (tor == session->torrentList)
{
session->torrentList = tor->next;
}
else
{
for (tr_torrent* t = session->torrentList; t != NULL; t = t->next)
{
if (t->next == tor)
{
t->next = tor->next;
break;
}
}
}
/* decrement the torrent count */
TR_ASSERT(session->torrentCount >= 1);
session->torrentCount--;
tr_sessionRemoveTorrent(session, tor);
/* resequence the queue positions */
tr_torrent* t = NULL;

View file

@ -50,6 +50,7 @@ Checks: >
-modernize-concat-nested-namespaces,
-modernize-use-trailing-return-type,
performance-*,
-performance-no-int-to-ptr,
readability-*,
-readability-convert-member-functions-to-static,
-readability-function-cognitive-complexity,