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:
parent
696b0bcab9
commit
c0ed82533c
4 changed files with 104 additions and 68 deletions
|
@ -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--;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue