Ignore:
Timestamp:
Aug 1, 2011, 10:24:24 PM (10 years ago)
Author:
jordan
Message:

(trunk) #671 "torrent queuing" -- Preliminary implementation. Covers libtransmission; GTK+ and Qt clients, and rudimentary web client support.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/torrent.c

    r12600 r12607  
    670670}
    671671
    672 static void torrentStart( tr_torrent * tor );
     672static void torrentStart( tr_torrent * tor, bool bypass_queue );
    673673
    674674/**
     
    803803    tor->uniqueId = nextUniqueId++;
    804804    tor->magicNumber = TORRENT_MAGIC_NUMBER;
     805    tor->queuePosition = -1;
    805806
    806807    tr_peerIdInit( tor->peer_id );
     
    906907    else if( doStart )
    907908    {
    908         torrentStart( tor );
     909        tr_torrentStart( tor );
    909910    }
    910911
     
    10901091}
    10911092
     1093static tr_torrent_activity
     1094torrentGetActivity( const tr_torrent * tor )
     1095{
     1096    const bool is_seed = tr_torrentIsSeed( tor );
     1097    assert( tr_isTorrent( tor ) );
     1098
     1099    if( tor->verifyState == TR_VERIFY_NOW )
     1100        return TR_STATUS_CHECK;
     1101
     1102    if( tor->verifyState == TR_VERIFY_WAIT )
     1103        return TR_STATUS_CHECK_WAIT;
     1104
     1105    if( tor->isRunning )
     1106        return is_seed ? TR_STATUS_SEED : TR_STATUS_DOWNLOAD;
     1107
     1108    if( tor->queuePosition >= 0 ) {
     1109        if( is_seed && tr_sessionGetQueueEnabled( tor->session, TR_UP ) )
     1110            return TR_STATUS_SEED_WAIT;
     1111        if( !is_seed && tr_sessionGetQueueEnabled( tor->session, TR_DOWN ) )
     1112            return TR_STATUS_DOWNLOAD_WAIT;
     1113    }
     1114
     1115    return TR_STATUS_STOPPED;
     1116}
     1117
    10921118tr_torrent_activity
    10931119tr_torrentGetActivity( tr_torrent * tor )
    10941120{
    1095     assert( tr_isTorrent( tor ) );
    1096 
     1121    /* FIXME: is this call still needed? */
    10971122    tr_torrentRecheckCompleteness( tor );
    10981123
    1099     if( tor->verifyState == TR_VERIFY_NOW )
    1100         return TR_STATUS_CHECK;
    1101     if( tor->verifyState == TR_VERIFY_WAIT )
    1102         return TR_STATUS_CHECK_WAIT;
    1103     if( !tor->isRunning )
    1104         return TR_STATUS_STOPPED;
    1105     if( tor->completeness == TR_LEECH )
    1106         return TR_STATUS_DOWNLOAD;
    1107 
    1108     return TR_STATUS_SEED;
    1109 }
     1124    return torrentGetActivity( tor );
     1125}
     1126
     1127static time_t
     1128torrentGetIdleSecs( const tr_torrent * tor )
     1129{
     1130    int idle_secs;
     1131    const tr_torrent_activity activity = torrentGetActivity( tor );
     1132
     1133    if ((activity == TR_STATUS_DOWNLOAD || activity == TR_STATUS_SEED) && tor->startDate != 0)
     1134        idle_secs = difftime(tr_time(), MAX(tor->startDate, tor->activityDate));
     1135    else
     1136        idle_secs = -1;
     1137
     1138    return idle_secs;
     1139}
     1140
     1141bool
     1142tr_torrentIsStalled( const tr_torrent * tor )
     1143{
     1144    return torrentGetIdleSecs( tor ) > ( tr_sessionGetQueueStalledMinutes( tor->session ) * 60 );
     1145}
     1146
    11101147
    11111148static double
     
    11461183    s->activity = tr_torrentGetActivity( tor );
    11471184    s->error = tor->error;
     1185    s->queuePosition = tor->queuePosition;
    11481186    tr_strlcpy( s->errorString, tor->errorString, sizeof( s->errorString ) );
    11491187
     
    11761214    s->secondsSeeding      = tor->secondsSeeding;
    11771215    s->secondsDownloading  = tor->secondsDownloading;
    1178 
    1179     if ((s->activity == TR_STATUS_DOWNLOAD || s->activity == TR_STATUS_SEED) && s->startDate != 0)
    1180         s->idleSecs = difftime(tr_time(), MAX(s->startDate, s->activityDate));
    1181     else
    1182         s->idleSecs = -1;
     1216    s->idleSecs            = torrentGetIdleSecs( tor );
    11831217
    11841218    s->corruptEver      = tor->corruptCur    + tor->corruptPrev;
     
    15061540**/
    15071541
     1542static void queueRemove( tr_torrent * tor );
     1543
    15081544static void
    15091545torrentStartImpl( void * vtor )
     
    15171553
    15181554    tr_torrentRecheckCompleteness( tor );
     1555    queueRemove( tor );
    15191556
    15201557    now = tr_time( );
     
    15571594}
    15581595
     1596static bool
     1597torrentShouldQueue( const tr_torrent * tor )
     1598{
     1599    const tr_direction dir = tr_torrentGetQueueDirection( tor );
     1600
     1601    return tr_sessionCountQueueFreeSlots( tor->session, dir ) == 0;
     1602}
     1603
     1604static void queueAppend( tr_torrent * tor );
     1605
    15591606static void
    1560 torrentStart( tr_torrent * tor )
    1561 {
    1562     /* already running... */
    1563     if( tor->isRunning )
    1564         return;
     1607torrentStart( tr_torrent * tor, bool bypass_queue )
     1608{
     1609    switch( torrentGetActivity( tor ) )
     1610    {
     1611        case TR_STATUS_SEED:
     1612        case TR_STATUS_DOWNLOAD:
     1613            return; /* already started */
     1614            break;
     1615
     1616        case TR_STATUS_SEED_WAIT:
     1617        case TR_STATUS_DOWNLOAD_WAIT:
     1618            if( !bypass_queue )
     1619                return; /* already queued */
     1620            break;
     1621
     1622        case TR_STATUS_CHECK:
     1623        case TR_STATUS_CHECK_WAIT:
     1624            /* verifying right now... wait until that's done so
     1625             * we'll know what completeness to use/announce */
     1626            tor->startAfterVerify = true;
     1627            return;
     1628            break;
     1629
     1630        case TR_STATUS_STOPPED:
     1631            if( !bypass_queue && torrentShouldQueue( tor ) ) {
     1632                queueAppend( tor );
     1633                return;
     1634            }
     1635            break;
     1636    }
    15651637
    15661638    /* don't allow the torrent to be started if the files disappeared */
    15671639    if( setLocalErrorIfFilesDisappeared( tor ) )
    15681640        return;
    1569 
    1570     /* verifying right now... wait until that's done so
    1571      * we'll know what completeness to use/announce */
    1572     if( tor->verifyState != TR_VERIFY_NONE ) {
    1573         tor->startAfterVerify = true;
    1574         return;
    1575     }
    15761641
    15771642    /* otherwise, start it now... */
     
    16011666{
    16021667    if( tr_isTorrent( tor ) )
    1603         torrentStart( tor );
     1668        torrentStart( tor, false );
     1669}
     1670
     1671void
     1672tr_torrentStartNow( tr_torrent * tor )
     1673{
     1674    if( tr_isTorrent( tor ) )
     1675        torrentStart( tor, true );
    16041676}
    16051677
     
    16141686    if( tor->startAfterVerify ) {
    16151687        tor->startAfterVerify = false;
    1616         torrentStart( tor );
     1688        torrentStart( tor, false );
    16171689    }
    16181690}
     
    16821754
    16831755    tr_verifyRemove( tor );
     1756    queueRemove( tor );
    16841757    tr_peerMgrStopTorrent( tor );
    16851758    tr_announcerTorrentStopped( tor );
     
    30863159    return tr_strdup_printf( "%s.part", tor->info.files[fileNum].name );
    30873160}
     3161
     3162/***
     3163****
     3164***/
     3165
     3166static int
     3167compareTorrentByQueuePosition( const void * va, const void * vb )
     3168{
     3169    const tr_torrent * a = * (const tr_torrent **) va;
     3170    const tr_torrent * b = * (const tr_torrent **) vb;
     3171
     3172    return a->queuePosition - b->queuePosition;
     3173}
     3174
     3175static bool
     3176queueIsSequenced( tr_torrent * tor )
     3177{
     3178    int i ;
     3179    int n ;
     3180    bool is_sequenced = true;
     3181    tr_session * session = tor->session;
     3182    tr_direction direction = tr_torrentGetQueueDirection( tor );
     3183    tr_torrent ** tmp = tr_new( tr_torrent *, session->torrentCount );
     3184
     3185    /* get all the torrents in that queue */
     3186    n = 0;
     3187    tor = NULL;
     3188    while(( tor = tr_torrentNext( session, tor )))
     3189        if( tr_torrentIsQueued( tor ) && ( direction == tr_torrentGetQueueDirection( tor ) ) )
     3190            tmp[n++] = tor;
     3191
     3192    /* sort them by position */
     3193    qsort( tmp, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition );
     3194
     3195#if 0
     3196    /* print them */
     3197    fprintf( stderr, "sequence: " );
     3198    for( i=0; i<n; ++i )
     3199        fprintf( stderr, "%d ", tmp[i]->queuePosition );
     3200    fprintf( stderr, "\n" );
     3201#endif
     3202
     3203    /* test them */
     3204    for( i=0; is_sequenced && i<n; ++i )
     3205        if( tmp[i]->queuePosition != i )
     3206            is_sequenced = false;
     3207
     3208    tr_free( tmp );
     3209    return is_sequenced;
     3210}
     3211
     3212int
     3213tr_torrentGetQueuePosition( const tr_torrent * tor )
     3214{
     3215    return tor->queuePosition;
     3216}
     3217
     3218void
     3219tr_torrentSetQueuePosition( tr_torrent * tor, int pos )
     3220{
     3221    if( tr_torrentIsQueued( tor ) )
     3222    {
     3223        int back = -1;
     3224        tr_torrent * walk;
     3225        const tr_direction direction = tr_torrentGetQueueDirection( tor );
     3226        const int old_pos = tor->queuePosition;
     3227        const time_t now = tr_time( );
     3228
     3229        if( pos < 0 )
     3230            pos = 0;
     3231
     3232        tor->queuePosition = -1;
     3233
     3234        walk = NULL;
     3235        while(( walk = tr_torrentNext( tor->session, walk )))
     3236        {
     3237            if( tr_torrentIsQueued( walk ) && ( tr_torrentGetQueueDirection( walk ) == direction ) )
     3238            {
     3239                if( old_pos < pos ) {
     3240                    if( ( old_pos <= walk->queuePosition ) && ( walk->queuePosition <= pos ) ) {
     3241                        walk->queuePosition--;
     3242                        walk->anyDate = now;
     3243                    }
     3244                }
     3245
     3246                if( old_pos > pos ) {
     3247                    if( ( pos <= walk->queuePosition ) && ( walk->queuePosition < old_pos ) ) {
     3248                        walk->queuePosition++;
     3249                        walk->anyDate = now;
     3250                    }
     3251                }
     3252
     3253                if( back < walk->queuePosition )
     3254                    back = walk->queuePosition;
     3255            }
     3256        }
     3257
     3258        tor->queuePosition = MIN( pos, (back+1) );
     3259        tor->anyDate = now;
     3260    }
     3261
     3262    assert( queueIsSequenced( tor ) );
     3263}
     3264
     3265void
     3266tr_torrentsQueueMoveTop( tr_torrent ** torrents_in, int n )
     3267{
     3268    int i;
     3269    tr_torrent ** torrents = tr_memdup( torrents_in, sizeof( tr_torrent * ) * n );
     3270    qsort( torrents, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition );
     3271    for( i=n-1; i>=0; --i )
     3272        tr_torrentSetQueuePosition( torrents[i], 0 );
     3273    tr_free( torrents );
     3274}
     3275
     3276void
     3277tr_torrentsQueueMoveUp( tr_torrent ** torrents_in, int n )
     3278{
     3279    int i;
     3280    tr_torrent ** torrents = tr_memdup( torrents_in, sizeof( tr_torrent * ) * n );
     3281    qsort( torrents, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition );
     3282    for( i=0; i<n; ++i )
     3283        tr_torrentSetQueuePosition( torrents[i], torrents[i]->queuePosition - 1 );
     3284    tr_free( torrents );
     3285}
     3286
     3287void
     3288tr_torrentsQueueMoveDown( tr_torrent ** torrents_in, int n )
     3289{
     3290    int i;
     3291    tr_torrent ** torrents = tr_memdup( torrents_in, sizeof( tr_torrent * ) * n );
     3292    qsort( torrents, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition );
     3293    for( i=n-1; i>=0; --i )
     3294        tr_torrentSetQueuePosition( torrents[i], torrents[i]->queuePosition + 1 );
     3295    tr_free( torrents );
     3296}
     3297
     3298void
     3299tr_torrentsQueueMoveBottom( tr_torrent ** torrents_in, int n )
     3300{
     3301    int i;
     3302    tr_torrent ** torrents = tr_memdup( torrents_in, sizeof( tr_torrent * ) * n );
     3303    qsort( torrents, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition );
     3304    for( i=0; i<n; ++i )
     3305        tr_torrentSetQueuePosition( torrents[i], INT_MAX );
     3306    tr_free( torrents );
     3307}
     3308
     3309/* Ensure that the torrents queued for downloads have queuePositions contiguous from [0...n] */
     3310static void
     3311queueResequence( tr_session * session, tr_direction direction )
     3312{
     3313    int i;
     3314    int n;
     3315    tr_torrent * tor = NULL;
     3316    tr_torrent ** tmp = tr_new( tr_torrent *, session->torrentCount );
     3317    const time_t now = tr_time( );
     3318
     3319    assert( tr_isSession( session ) );
     3320    assert( tr_isDirection( direction ) );
     3321
     3322    /* get all the torrents in that queue */
     3323    n = 0;
     3324    while(( tor = tr_torrentNext( session, tor ))) {
     3325        if( direction == tr_torrentGetQueueDirection( tor )) {
     3326            const int position = tr_torrentGetQueuePosition( tor );
     3327            if( position >= 0 )
     3328                tmp[n++] = tor;
     3329        }
     3330    }
     3331
     3332    /* sort them by position */
     3333    qsort( tmp, n, sizeof( tr_torrent * ), compareTorrentByQueuePosition );
     3334
     3335    /* sequence them... */
     3336    for( i=0; i<n; ++i ) {
     3337        tr_torrent * tor = tmp[i];
     3338        if( tor->queuePosition != i ) {
     3339            tor->queuePosition = i;
     3340            tor->anyDate = now;
     3341        }
     3342    }
     3343
     3344    tr_free( tmp );
     3345}
     3346
     3347static void
     3348queueRemove( tr_torrent * tor )
     3349{
     3350    if( tr_torrentIsQueued( tor ) )
     3351    {
     3352        tor->queuePosition = -1;
     3353        queueResequence( tor->session, tr_torrentGetQueueDirection( tor ) );
     3354    }
     3355}
     3356
     3357static void
     3358queueAppend( tr_torrent * tor )
     3359{
     3360    if( !tr_torrentIsQueued( tor ) )
     3361    {
     3362        /* tr_torrentSetQueuePosition() requres the torrent to be queued,
     3363           so init tor->queuePosition to the back... */
     3364        tor->queuePosition = INT_MAX;
     3365
     3366        tr_torrentSetQueuePosition( tor, INT_MAX );
     3367    }
     3368}
Note: See TracChangeset for help on using the changeset viewer.