1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-02-22 22:20:39 +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.h" /* tr_lock, tr_getTorrentDir() */
#include "platform-quota.h" /* tr_device_info_free() */ #include "platform-quota.h" /* tr_device_info_free() */
#include "port-forwarding.h" #include "port-forwarding.h"
#include "ptrarray.h"
#include "rpc-server.h" #include "rpc-server.h"
#include "session.h" #include "session.h"
#include "session-id.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->cache = tr_cacheNew(1024 * 1024 * 2);
session->magicNumber = SESSION_MAGIC_NUMBER; session->magicNumber = SESSION_MAGIC_NUMBER;
session->session_id = tr_session_id_new(); 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_bandwidthConstruct(&session->bandwidth, session, NULL);
tr_variantInitList(&session->removedTorrents, 0); tr_variantInitList(&session->removedTorrents, 0);
@ -2137,6 +2141,9 @@ void tr_sessionClose(tr_session* session)
} }
tr_device_info_free(session->downloadDir); 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->torrentDoneScript);
tr_free(session->configDir); tr_free(session->configDir);
tr_free(session->resumeDir); tr_free(session->resumeDir);
@ -3117,3 +3124,68 @@ int tr_sessionCountQueueFreeSlots(tr_session* session, tr_direction dir)
return max - active_count; 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 "bandwidth.h"
#include "bitfield.h" #include "bitfield.h"
#include "net.h" #include "net.h"
#include "ptrarray.h"
#include "tr-macros.h" #include "tr-macros.h"
#include "utils.h" #include "utils.h"
#include "variant.h" #include "variant.h"
@ -177,6 +178,9 @@ struct tr_session
int torrentCount; int torrentCount;
tr_torrent* torrentList; tr_torrent* torrentList;
tr_ptrArray torrentsSortedByHash;
tr_ptrArray torrentsSortedByHashString;
tr_ptrArray torrentsSortedById;
char* torrentDoneScript; char* torrentDoneScript;
@ -322,4 +326,7 @@ void tr_sessionGetNextQueuedTorrents(tr_session* session, tr_direction dir, size
int tr_sessionCountQueueFreeSlots(tr_session* session, tr_direction); 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 TR_END_DECLS

View file

@ -73,49 +73,40 @@ int tr_torrentId(tr_torrent const* tor)
return tor != NULL ? tor->uniqueId : -1; 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* 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) static int compareKeyToTorrentHashString(void const* va, void const* vb)
{ {
if (tor->uniqueId == id) tr_torrent const* const a = va;
{ char const* const b = vb;
return tor; return evutil_ascii_strcasecmp(a->info.hashString, b);
}
}
return NULL;
} }
tr_torrent* tr_torrentFindFromHashString(tr_session* session, char const* str) 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) static int compareKeyToTorrentHash(void const* va, void const* vb)
{ {
if (evutil_ascii_strcasecmp(str, tor->info.hashString) == 0) tr_torrent const* const a = va;
{ uint8_t const* const b = vb;
return tor; return memcmp(a->info.hash, b, SHA_DIGEST_LENGTH);
}
}
return NULL;
} }
tr_torrent* tr_torrentFindFromHash(tr_session* session, uint8_t const* torrentHash) tr_torrent* tr_torrentFindFromHash(tr_session* session, uint8_t const* torrentHash)
{ {
tr_torrent* tor = NULL; return tr_ptrArrayFindSorted(&session->torrentsSortedByHash, torrentHash, compareKeyToTorrentHash);
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;
} }
tr_torrent* tr_torrentFindFromMagnetLink(tr_session* session, char const* magnet) 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)); tr_torrentSetIdleLimit(tor, tr_sessionGetIdleLimit(tor->session));
} }
/* add the torrent to tr_session.torrentList */ tr_sessionAddTorrent(session, tor);
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;
}
/* if we don't have a local .torrent file already, assume the torrent is new */ /* if we don't have a local .torrent file already, assume the torrent is new */
isNewTorrent = !tr_sys_path_exists(tor->info.torrent, NULL); 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->downloadDir);
tr_free(tor->incompleteDir); tr_free(tor->incompleteDir);
if (tor == session->torrentList) tr_sessionRemoveTorrent(session, tor);
{
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--;
/* resequence the queue positions */ /* resequence the queue positions */
tr_torrent* t = NULL; tr_torrent* t = NULL;

View file

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