diff --git a/libtransmission/peer-mgr.c b/libtransmission/peer-mgr.c index 883ae19ce..236e54573 100644 --- a/libtransmission/peer-mgr.c +++ b/libtransmission/peer-mgr.c @@ -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 queuePulse (tr_session * session, tr_direction dir) { - assert (tr_isSession (session)); - assert (tr_isDirection (dir)); + assert (tr_isSession (session)); + assert (tr_isDirection (dir)); - if (tr_sessionGetQueueEnabled (session, dir)) + if (tr_sessionGetQueueEnabled (session, dir)) { - int i; - const int n = tr_sessionCountQueueFreeSlots (session, dir); - for (i=0; iqueue_started_callback != NULL) - (*tor->queue_started_callback)(tor, tor->queue_started_user_data); - } - } + tr_ptrArray torrents = TR_PTR_ARRAY_INIT; + + tr_sessionGetNextQueuedTorrents (session, + dir, + tr_sessionCountQueueFreeSlots (session, dir), + &torrents); + + 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; } -#ifndef NDEBUG 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); - assert (storeIndex <= right); - assert (candidates[storeIndex].score == pivotScore); + if (a->score < b->score) + ret = -1; + else if (a->score > b->score) + ret = 1; + else + ret = 0; - for (i=left; i= 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; + return ret; } /* Partial sorting -- selecting the k best candidates Adapted from http://en.wikipedia.org/wiki/Selection_algorithm */ 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) - { - const int pivotIndex = left + (right-left)/2; - - int pivotNewIndex = partitionPeerCandidates (candidates, left, right, pivotIndex); - - 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); - } + tr_quickfindFirstK (candidates, + candidate_count, + sizeof(struct peer_candidate), + comparePeerCandidates, + select_count); } #ifndef NDEBUG @@ -4042,7 +4008,7 @@ getPeerCandidates (tr_session * session, int * candidateCount, int max) *candidateCount = walk - candidates; if (walk != candidates) - selectPeerCandidates (candidates, 0, (walk-candidates)-1, max); + selectPeerCandidates (candidates, walk-candidates, max); assert (checkBestScoresComeFirst (candidates, *candidateCount, max)); diff --git a/libtransmission/session.c b/libtransmission/session.c index 02ab12b78..8087608ca 100644 --- a/libtransmission/session.c +++ b/libtransmission/session.c @@ -2713,33 +2713,74 @@ tr_sessionGetQueueStalledMinutes (const tr_session * session) return session->queueStalledMinutes; } -tr_torrent * -tr_sessionGetNextQueuedTorrent (tr_session * session, tr_direction direction) +struct TorrentAndPosition { - tr_torrent * tor = NULL; - tr_torrent * best_tor = NULL; - int best_position = INT_MAX; + tr_torrent * tor; + int position; +}; - assert (tr_isSession (session)); - assert (tr_isDirection (direction)); +/* higher positions come first */ +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)) - continue; - if (direction != tr_torrentGetQueueDirection (tor)) - continue; + if (direction != tr_torrentGetQueueDirection (tor)) + continue; - position = tr_torrentGetQueuePosition (tor); - if (best_position > position) { - best_position = position; - best_tor = tor; - } + candidates[i].tor = tor; + candidates[i].position = tr_torrentGetQueuePosition (tor); + ++i; } - 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