mirror of
https://github.com/transmission/transmission
synced 2024-12-27 18:18:10 +00:00
(trunk, libT) #5199 'tr_sessionGetNextQueuedTorrent() can be faster' -- modify session.c's tr_sessionGetNextQueuedTorrents() and peer-mgr.c's getPeerCandidates() functions use the new tr_quickfindFirstK() utility"
This commit is contained in:
parent
25b8b60245
commit
aa906ced75
3 changed files with 104 additions and 97 deletions
|
@ -3590,24 +3590,36 @@ pumpAllPeers (tr_peerMgr * mgr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
queuePulseForeach (void * vtor)
|
||||||
|
{
|
||||||
|
tr_torrent * tor = vtor;
|
||||||
|
|
||||||
|
tr_torrentStartNow (tor);
|
||||||
|
|
||||||
|
if (tor->queue_started_callback != NULL)
|
||||||
|
(*tor->queue_started_callback)(tor, tor->queue_started_user_data);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
queuePulse (tr_session * session, tr_direction dir)
|
queuePulse (tr_session * session, tr_direction dir)
|
||||||
{
|
{
|
||||||
assert (tr_isSession (session));
|
assert (tr_isSession (session));
|
||||||
assert (tr_isDirection (dir));
|
assert (tr_isDirection (dir));
|
||||||
|
|
||||||
if (tr_sessionGetQueueEnabled (session, dir))
|
if (tr_sessionGetQueueEnabled (session, dir))
|
||||||
{
|
{
|
||||||
int i;
|
tr_ptrArray torrents = TR_PTR_ARRAY_INIT;
|
||||||
const int n = tr_sessionCountQueueFreeSlots (session, dir);
|
|
||||||
for (i=0; i<n; i++) {
|
tr_sessionGetNextQueuedTorrents (session,
|
||||||
tr_torrent * tor = tr_sessionGetNextQueuedTorrent (session, dir);
|
dir,
|
||||||
if (tor != NULL) {
|
tr_sessionCountQueueFreeSlots (session, dir),
|
||||||
tr_torrentStartNow (tor);
|
&torrents);
|
||||||
if (tor->queue_started_callback != NULL)
|
|
||||||
(*tor->queue_started_callback)(tor, tor->queue_started_user_data);
|
tr_ptrArrayForeach (&torrents, queuePulseForeach);
|
||||||
}
|
|
||||||
}
|
tr_ptrArrayDestruct (&torrents, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3877,79 +3889,33 @@ getPeerCandidateScore (const tr_torrent * tor, const struct peer_atom * atom, ui
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
static int
|
static int
|
||||||
checkPartition (const struct peer_candidate * candidates, int left, int right, uint64_t pivotScore, int storeIndex)
|
comparePeerCandidates (const void * va, const void * vb)
|
||||||
{
|
{
|
||||||
int i;
|
int ret;
|
||||||
|
const struct peer_candidate * a = va;
|
||||||
|
const struct peer_candidate * b = vb;
|
||||||
|
|
||||||
assert (storeIndex >= left);
|
if (a->score < b->score)
|
||||||
assert (storeIndex <= right);
|
ret = -1;
|
||||||
assert (candidates[storeIndex].score == pivotScore);
|
else if (a->score > b->score)
|
||||||
|
ret = 1;
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
for (i=left; i<storeIndex; ++i)
|
return ret;
|
||||||
assert (candidates[i].score < pivotScore);
|
|
||||||
for (i=storeIndex+1; i<=right; ++i)
|
|
||||||
assert (candidates[i].score >= pivotScore);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Helper to selectPeerCandidates().
|
|
||||||
* Adapted from http://en.wikipedia.org/wiki/Selection_algorithm */
|
|
||||||
static int
|
|
||||||
partitionPeerCandidates (struct peer_candidate * candidates, int left, int right, int pivotIndex)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int storeIndex;
|
|
||||||
struct peer_candidate tmp;
|
|
||||||
const struct peer_candidate pivotValue = candidates[pivotIndex];
|
|
||||||
|
|
||||||
/* move pivot to end */
|
|
||||||
tmp = candidates[right];
|
|
||||||
candidates[right] = pivotValue;
|
|
||||||
candidates[pivotIndex] = tmp;
|
|
||||||
|
|
||||||
storeIndex = left;
|
|
||||||
for (i=left; i<=right; ++i)
|
|
||||||
{
|
|
||||||
if (candidates[i].score < pivotValue.score)
|
|
||||||
{
|
|
||||||
tmp = candidates[storeIndex];
|
|
||||||
candidates[storeIndex] = candidates[i];
|
|
||||||
candidates[i] = tmp;
|
|
||||||
storeIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* move pivot to its final place */
|
|
||||||
tmp = candidates[right];
|
|
||||||
candidates[right] = candidates[storeIndex];
|
|
||||||
candidates[storeIndex] = tmp;
|
|
||||||
|
|
||||||
/* sanity check */
|
|
||||||
assert (checkPartition (candidates, left, right, pivotValue.score, storeIndex));
|
|
||||||
|
|
||||||
return storeIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Partial sorting -- selecting the k best candidates
|
/* Partial sorting -- selecting the k best candidates
|
||||||
Adapted from http://en.wikipedia.org/wiki/Selection_algorithm */
|
Adapted from http://en.wikipedia.org/wiki/Selection_algorithm */
|
||||||
static void
|
static void
|
||||||
selectPeerCandidates (struct peer_candidate * candidates, int left, int right, int k)
|
selectPeerCandidates (struct peer_candidate * candidates, int candidate_count, int select_count)
|
||||||
{
|
{
|
||||||
if (right > left)
|
tr_quickfindFirstK (candidates,
|
||||||
{
|
candidate_count,
|
||||||
const int pivotIndex = left + (right-left)/2;
|
sizeof(struct peer_candidate),
|
||||||
|
comparePeerCandidates,
|
||||||
int pivotNewIndex = partitionPeerCandidates (candidates, left, right, pivotIndex);
|
select_count);
|
||||||
|
|
||||||
if (pivotNewIndex > left + k) /* new condition */
|
|
||||||
selectPeerCandidates (candidates, left, pivotNewIndex-1, k);
|
|
||||||
else if (pivotNewIndex < left + k)
|
|
||||||
selectPeerCandidates (candidates, pivotNewIndex+1, right, k+left-pivotNewIndex-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -4042,7 +4008,7 @@ getPeerCandidates (tr_session * session, int * candidateCount, int max)
|
||||||
|
|
||||||
*candidateCount = walk - candidates;
|
*candidateCount = walk - candidates;
|
||||||
if (walk != candidates)
|
if (walk != candidates)
|
||||||
selectPeerCandidates (candidates, 0, (walk-candidates)-1, max);
|
selectPeerCandidates (candidates, walk-candidates, max);
|
||||||
|
|
||||||
assert (checkBestScoresComeFirst (candidates, *candidateCount, max));
|
assert (checkBestScoresComeFirst (candidates, *candidateCount, max));
|
||||||
|
|
||||||
|
|
|
@ -2713,33 +2713,74 @@ tr_sessionGetQueueStalledMinutes (const tr_session * session)
|
||||||
return session->queueStalledMinutes;
|
return session->queueStalledMinutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr_torrent *
|
struct TorrentAndPosition
|
||||||
tr_sessionGetNextQueuedTorrent (tr_session * session, tr_direction direction)
|
|
||||||
{
|
{
|
||||||
tr_torrent * tor = NULL;
|
tr_torrent * tor;
|
||||||
tr_torrent * best_tor = NULL;
|
int position;
|
||||||
int best_position = INT_MAX;
|
};
|
||||||
|
|
||||||
assert (tr_isSession (session));
|
/* higher positions come first */
|
||||||
assert (tr_isDirection (direction));
|
static int
|
||||||
|
compareTorrentAndPositions (const void * va, const void * vb)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
const struct TorrentAndPosition * a = va;
|
||||||
|
const struct TorrentAndPosition * b = vb;
|
||||||
|
|
||||||
while ((tor = tr_torrentNext (session, tor)))
|
if (a->position > b->position)
|
||||||
|
ret = -1;
|
||||||
|
else if (a->position < b->position)
|
||||||
|
ret = 1;
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
tr_sessionGetNextQueuedTorrents (tr_session * session,
|
||||||
|
tr_direction direction,
|
||||||
|
size_t num_wanted,
|
||||||
|
tr_ptrArray * setme)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
tr_torrent * tor;
|
||||||
|
struct TorrentAndPosition * candidates;
|
||||||
|
|
||||||
|
assert (tr_isSession (session));
|
||||||
|
assert (tr_isDirection (direction));
|
||||||
|
|
||||||
|
/* build an array of the candidates */
|
||||||
|
candidates = tr_new (struct TorrentAndPosition, session->torrentCount);
|
||||||
|
tor = NULL;
|
||||||
|
while ((tor = tr_torrentNext (session, tor)))
|
||||||
{
|
{
|
||||||
int position;
|
if (!tr_torrentIsQueued (tor))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!tr_torrentIsQueued (tor))
|
if (direction != tr_torrentGetQueueDirection (tor))
|
||||||
continue;
|
continue;
|
||||||
if (direction != tr_torrentGetQueueDirection (tor))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
position = tr_torrentGetQueuePosition (tor);
|
candidates[i].tor = tor;
|
||||||
if (best_position > position) {
|
candidates[i].position = tr_torrentGetQueuePosition (tor);
|
||||||
best_position = position;
|
++i;
|
||||||
best_tor = tor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return best_tor;
|
/* find the best n candidates */
|
||||||
|
if (num_wanted > i)
|
||||||
|
num_wanted = i;
|
||||||
|
else if (num_wanted < i)
|
||||||
|
tr_quickfindFirstK (candidates, i,
|
||||||
|
sizeof(struct TorrentAndPosition),
|
||||||
|
compareTorrentAndPositions, num_wanted);
|
||||||
|
|
||||||
|
/* add them to the return array */
|
||||||
|
for (i=0; i<num_wanted; ++i)
|
||||||
|
tr_ptrArrayAppend (setme, candidates[i].tor);
|
||||||
|
|
||||||
|
/* cleanup */
|
||||||
|
tr_free (candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -329,7 +329,7 @@ bool tr_sessionGetActiveSpeedLimit_Bps (const tr_session * session,
|
||||||
unsigned int * setme);
|
unsigned int * setme);
|
||||||
|
|
||||||
tr_torrent * tr_sessionGetNextQueuedSeed (tr_session * session);
|
tr_torrent * tr_sessionGetNextQueuedSeed (tr_session * session);
|
||||||
tr_torrent * tr_sessionGetNextQueuedTorrent (tr_session * session, tr_direction);
|
void tr_sessionGetNextQueuedTorrents (tr_session * session, tr_direction, size_t n, tr_ptrArray * steme);
|
||||||
|
|
||||||
int tr_sessionCountQueueFreeSlots (tr_session * session, tr_direction);
|
int tr_sessionCountQueueFreeSlots (tr_session * session, tr_direction);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue