Changeset 11833


Ignore:
Timestamp:
Feb 5, 2011, 6:46:10 PM (11 years ago)
Author:
jordan
Message:

(trunk libT) #3931 "'Announce is Queued' but doesn't get announced" -- remove the 'unresponsive tracker' penalty from torrents whose announce time has been reached.

The 'bad tracker' penalty was introduced in 2009 after a top tier trackers went down. Announces to it would hang, tying up an announce slot in libcurl for minutes at a time. If a user had enough torrents from that tracker, it could bottleneck all announce slots. The workaround was to deprioritize failing trackers so that they wouldn't obstruct other trackers.

Its implementation could be better, however. There are two parts:

  1. Deciding how frequently to retry unresponsive trackers
  1. Once an unresponsive tracker announce was ready to go, it would be bumped down the queue if other announces were ready too.

Part 2 probably contributes to #3931. If there are enough torrents loaded, there will always be good tracker announces that get pushed ahead of a bad one in the queue. Modifying 2's heuristics would be one option, but it seems simpler to remove it altogether now that getRetryInterval() grades more hashly for consecutive failures. Altering the retry interval also gives better visual feedback to users than Part 2 did.

This commit removes "Part 2" as described above.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/announcer.c

    r11832 r11833  
    3737  char name[128]; \
    3838  tr_snprintf( name, sizeof( name ), "[%s--%s]", tr_torrentName( tier->tor ), \
    39       ( tier->currentTracker ? tier->currentTracker->host->name : "" ) ); \
     39      ( tier->currentTracker ? tier->currentTracker->hostname : "" ) ); \
    4040  tr_deepLog( __FILE__, __LINE__, name, __VA_ARGS__ ); \
    4141} while( 0 )
     
    5858    MAX_CONCURRENT_TASKS = 48,
    5959
    60     /* if a tracker takes more than this long to respond,
    61      * we treat it as nonresponsive */
    62     MAX_TRACKER_RESPONSE_TIME_SECS = ( 60 * 2 ),
    63 
    6460    /* the value of the 'numwant' argument passed in tracker requests. */
    6561    NUMWANT = 80,
    66 
    67     /* how long to put slow (nonresponsive) trackers in the penalty box */
    68     SLOW_HOST_PENALTY_SECS = ( 60 * 10 ),
    6962
    7063    UPKEEP_INTERVAL_SECS = 1,
     
    7972***/
    8073
     74/**
     75 * Since we can't poll a tr_torrent's fields after it's destroyed,
     76 * we pre-build the "stop" announcement message when a torrent
     77 * is removed from Transmission
     78 */
     79struct stop_message
     80{
     81    char * url;
     82    uint64_t up;
     83    uint64_t down;
     84};
     85
     86static void
     87stopFree( struct stop_message * stop )
     88{
     89    tr_free( stop->url );
     90    tr_free( stop );
     91}
     92
    8193static int
    8294compareTransfer( uint64_t a_uploaded, uint64_t a_downloaded,
     
    94106}
    95107
     108static int
     109compareStops( const void * va, const void * vb )
     110{
     111    const struct stop_message * a = va;
     112    const struct stop_message * b = vb;
     113    return compareTransfer( a->up, a->down, b->up, b->down);
     114}
     115
    96116/***
    97117****
     
    99119
    100120/**
    101  * used by tr_announcer to recognize nonresponsive
    102  * trackers and de-prioritize them
     121 * "global" (per-tr_session) fields
    103122 */
    104 typedef struct
    105 {
    106     char * name;
    107 
    108     /* how many seconds it took to get the last tracker response */
    109     int lastResponseInterval;
    110 
    111     /* the last time we sent an announce or scrape message */
    112     time_t lastRequestTime;
    113 
    114     /* the last successful announce/scrape time for this host */
    115     time_t lastSuccessfulRequest;
    116 }
    117 tr_host;
    118 
    119 static int
    120 compareHosts( const void * va, const void * vb )
    121 {
    122     const tr_host * a = va;
    123     const tr_host * b = vb;
    124     return strcmp( a->name, b->name );
    125 }
    126 
    127 static int
    128 compareHostToName( const void * va, const void * vb )
    129 {
    130     const tr_host * a = va;
    131     return strcmp( a->name, vb );
     123typedef struct tr_announcer
     124{
     125    tr_ptrArray stops; /* struct stop_message */
     126    tr_session * session;
     127    struct event * upkeepTimer;
     128    int slotsAvailable;
     129    time_t lpdHouseKeepingAt;
     130}
     131tr_announcer;
     132
     133tr_bool
     134tr_announcerHasBacklog( const struct tr_announcer * announcer )
     135{
     136    return announcer->slotsAvailable < 1;
    132137}
    133138
     
    145150}
    146151
    147 static tr_host*
    148 hostNew( const char * name )
    149 {
    150     tr_host * host = tr_new0( tr_host, 1 );
    151     host->name = tr_strdup( name );
    152     return host;
    153 }
    154 
    155 static void
    156 hostFree( void * vhost )
    157 {
    158     tr_host * host = vhost;
    159 
    160     tr_free( host->name );
    161     tr_free( host );
    162 }
    163 
    164 /***
    165 ****
    166 ***/
    167 
    168 /**
    169  * Since we can't poll a tr_torrent's fields after it's destroyed,
    170  * we pre-build the "stop" announcement message when a torrent
    171  * is removed from Transmission
    172  */
    173 struct stop_message
    174 {
    175     tr_host * host;
    176     char * url;
    177     uint64_t up;
    178     uint64_t down;
    179 };
    180 
    181 static void
    182 stopFree( struct stop_message * stop )
    183 {
    184     tr_free( stop->url );
    185     tr_free( stop );
    186 }
    187 
    188 static int
    189 compareStops( const void * va, const void * vb )
    190 {
    191     const struct stop_message * a = va;
    192     const struct stop_message * b = vb;
    193     return compareTransfer( a->up, a->down, b->up, b->down);
    194 }
    195 
    196 /***
    197 ****
    198 ***/
    199 
    200 /**
    201  * "global" (per-tr_session) fields
    202  */
    203 typedef struct tr_announcer
    204 {
    205     tr_ptrArray hosts; /* tr_host */
    206     tr_ptrArray stops; /* struct stop_message */
    207     tr_session * session;
    208     struct event * upkeepTimer;
    209     int slotsAvailable;
    210     time_t lpdHouseKeepingAt;
    211 }
    212 tr_announcer;
    213 
    214 tr_bool
    215 tr_announcerHasBacklog( const struct tr_announcer * announcer )
    216 {
    217     return announcer->slotsAvailable < 1;
    218 }
    219 
    220 static tr_host *
    221 getHost( tr_announcer * announcer, const char * url )
    222 {
    223     char * name = getHostName( url );
    224     tr_host * host;
    225 
    226     host = tr_ptrArrayFindSorted( &announcer->hosts, name, compareHostToName );
    227     if( host == NULL )
    228     {
    229         host = hostNew( name );
    230         tr_ptrArrayInsertSorted( &announcer->hosts, host, compareHosts );
    231     }
    232 
    233     tr_free( name );
    234     return host;
    235 }
    236 
    237152static inline time_t
    238153calcRescheduleWithJitter( const int minPeriod )
     
    261176
    262177    a = tr_new0( tr_announcer, 1 );
    263     a->hosts = TR_PTR_ARRAY_INIT;
    264178    a->stops = TR_PTR_ARRAY_INIT;
    265179    a->session = session;
     
    285199
    286200    tr_ptrArrayDestruct( &announcer->stops, NULL );
    287     tr_ptrArrayDestruct( &announcer->hosts, hostFree );
    288201
    289202    session->announcer = NULL;
     
    298211typedef struct
    299212{
    300     tr_host * host;
    301 
     213    char * hostname;
    302214    char * announce;
    303215    char * scrape;
     
    336248
    337249static tr_tracker_item*
    338 trackerNew( tr_announcer  * announcer,
    339             const char    * announce,
    340             const char    * scrape,
    341             uint32_t        id )
     250trackerNew( const char  * announce,
     251            const char  * scrape,
     252            uint32_t      id )
    342253{
    343254    tr_tracker_item * tracker = tr_new0( tr_tracker_item, 1  );
    344     tracker->host = getHost( announcer, announce );
     255    tracker->hostname = getHostName( announce );
    345256    tracker->announce = tr_strdup( announce );
    346257    tracker->scrape = tr_strdup( scrape );
     
    361272    tr_free( tracker->scrape );
    362273    tr_free( tracker->announce );
     274    tr_free( tracker->hostname );
    363275    tr_free( tracker );
    364276}
     
    468380
    469381static void
    470 tierAddTracker( tr_announcer * announcer,
    471                 tr_tier      * tier,
     382tierAddTracker( tr_tier      * tier,
    472383                const char   * announce,
    473384                const char   * scrape,
    474385                uint32_t       id )
    475386{
    476     tr_tracker_item * tracker = trackerNew( announcer, announce, scrape, id );
     387    tr_tracker_item * tracker = trackerNew( announce, scrape, id );
    477388
    478389    tr_ptrArrayAppend( &tier->trackers, tracker );
     
    745656
    746657static void
    747 addTorrentToTier( tr_announcer      * announcer,
    748                   tr_torrent_tiers  * tiers,
     658addTorrentToTier( tr_torrent_tiers  * tiers,
    749659                  tr_torrent        * tor )
    750660{
     
    781691            }
    782692
    783             tierAddTracker( announcer, tier, info->announce, info->scrape, info->id );
     693            tierAddTracker( tier, info->announce, info->scrape, info->id );
    784694        }
    785695    }
     
    801711    tiers->callbackData = callbackData;
    802712
    803     addTorrentToTier( announcer, tiers, tor );
     713    addTorrentToTier( tiers, tor );
    804714
    805715    return tiers;
     
    957867                s->down = tier->byteCounts[TR_ANN_DOWN];
    958868                s->url = createAnnounceURL( announcer, tor, tier, "stopped" );
    959                 s->host = tier->currentTracker->host;
    960869                tr_ptrArrayInsertSorted( &announcer->stops, s, compareStops );
    961870            }
     
    10991008}
    11001009
     1010static int
     1011getRetryInterval( const tr_tracker_item * t )
     1012{
     1013    int minutes;
     1014    const unsigned int jitter_seconds = tr_cryptoWeakRandInt( 60 );
     1015    switch( t->consecutiveAnnounceFailures ) {
     1016        case 0:  minutes =   1; break;
     1017        case 1:  minutes =   5; break;
     1018        case 2:  minutes =  15; break;
     1019        case 3:  minutes =  30; break;
     1020        case 4:  minutes =  60; break;
     1021        default: minutes = 120; break;
     1022    }
     1023    return ( minutes * 60 ) + jitter_seconds;
     1024}
     1025
    11011026struct announce_data
    11021027{
     
    11091034    tr_bool isRunningOnSuccess;
    11101035};
    1111 
    1112 static int
    1113 getRetryInterval( const tr_tracker_item * t )
    1114 {
    1115     int minutes;
    1116     const unsigned int jitter_seconds = tr_cryptoWeakRandInt( 60 );
    1117     switch( t->consecutiveAnnounceFailures ) {
    1118         case 0:  minutes =   1; break;
    1119         case 1:  minutes =   2; break;
    1120         case 2:  minutes =   4; break;
    1121         case 3:  minutes =   8; break;
    1122         case 4:  minutes =  16; break;
    1123         case 5:  minutes =  32; break;
    1124         case 6:  minutes =  64; break;
    1125         default: minutes = 128; break;
    1126     }
    1127     return ( minutes * 60 ) + jitter_seconds;
    1128 }
    11291036
    11301037static void
     
    11521059
    11531060        if(( tracker = tier->currentTracker ))
    1154         {
    11551061            ++tracker->consecutiveAnnounceFailures;
    1156 
    1157             if( tracker->host )
    1158             {
    1159                 tracker->host->lastRequestTime = data->timeSent;
    1160                 tracker->host->lastResponseInterval = now - data->timeSent;
    1161             }
    1162         }
    11631062
    11641063        if( responseCode == HTTP_OK )
     
    11751074                {
    11761075                    tracker->consecutiveAnnounceFailures = 0;
    1177    
    1178                     if( tracker->host )
    1179                         tracker->host->lastSuccessfulRequest = now;
    11801076                }
    11811077
     
    14321328        tier->lastScrapeTime = now;
    14331329
    1434         if( tier->currentTracker->host )
    1435         {
    1436             tr_host * host = tier->currentTracker->host;
    1437             host->lastRequestTime = data->timeSent;
    1438             host->lastResponseInterval = now - data->timeSent;
    1439         }
    1440 
    14411330        if( 200 <= responseCode && responseCode <= 299 )
    14421331        {
     
    14861375        tier->lastScrapeSucceeded = success;
    14871376        tier->lastScrapeTimedOut = responseCode == 0;
    1488 
    1489         if( success && tier->currentTracker->host )
    1490             tier->currentTracker->host->lastSuccessfulRequest = now;
    14911377    }
    14921378
     
    15621448}
    15631449
    1564 /* return true if (1) we've tried it recently AND (2) it didn't respond... */
    1565 static tr_bool
    1566 hostIsNotResponding( const tr_host * host, const time_t now )
    1567 {
    1568     tr_bool b = ( host->lastRequestTime )
    1569              && ( host->lastRequestTime >= ( now - SLOW_HOST_PENALTY_SECS ) )
    1570              && ( host->lastResponseInterval > MAX_TRACKER_RESPONSE_TIME_SECS );
    1571     return b;
    1572 }
    1573 
    1574 static tr_bool
    1575 tierIsNotResponding( const tr_tier * tier, const time_t now )
    1576 {
    1577     return !tier->currentTracker
    1578         || hostIsNotResponding( tier->currentTracker->host, now );
    1579 }
    1580 
    15811450static int
    15821451compareTiers( const void * va, const void * vb )
    15831452{
    1584     int ret = 0;
    1585     tr_bool af, bf;
     1453    int ret;
    15861454    const tr_tier * a = *(const tr_tier**)va;
    15871455    const tr_tier * b = *(const tr_tier**)vb;
    15881456
    1589     /* working domains come before non-working */
    1590     if( !ret ) {
    1591         const time_t now = tr_time( );
    1592         af = tierIsNotResponding( a, now );
    1593         bf = tierIsNotResponding( b, now );
    1594         if( af != bf )
    1595             ret = !af ? -1 : 1;
    1596     }
    1597 
    1598     /* stops come before starts */
    1599     if( !ret ) {
    1600         af = a->tor->isRunning;
    1601         bf = b->tor->isRunning;
    1602         if( af != bf )
    1603             ret = af ? 1 : -1;
    1604     }
    1605 
    1606     /* upload comes before download */
    1607     if( !ret )
    1608         ret = compareTransfer( a->byteCounts[TR_ANN_UP], a->byteCounts[TR_ANN_DOWN],
    1609                                b->byteCounts[TR_ANN_UP], b->byteCounts[TR_ANN_DOWN] );
    1610 
    1611     /* incomplete comes before complete */
    1612     if( !ret ) {
    1613         af = a->tor->completeness == TR_LEECH;
    1614         bf = b->tor->completeness == TR_LEECH;
    1615         if( af != bf )
    1616             return af ? -1 : 1;
    1617     }
    1618 
    1619     /* private before public */
    1620     if( !ret ) {
    1621         af = tr_torrentIsPrivate( a->tor );
    1622         bf = tr_torrentIsPrivate( b->tor );
    1623         if( af != bf )
    1624             ret = af ? -1 : 1;
    1625     }
    1626 
     1457    /* primary key: larger stats come before smaller */
     1458    ret = compareTransfer( a->byteCounts[TR_ANN_UP], a->byteCounts[TR_ANN_DOWN],
     1459                           b->byteCounts[TR_ANN_UP], b->byteCounts[TR_ANN_DOWN] );
     1460
     1461    /* secondary key: announcements that have been waiting longer go first */
     1462    if( !ret && ( a->announceAt != b->announceAt ) )
     1463        ret = a->announceAt < b->announceAt ? -1 : 1;
     1464         
    16271465    return ret;
    16281466}
    1629 
    16301467
    16311468static void
     
    17861623
    17871624            st->id = tracker->id;
    1788             tr_strlcpy( st->host, tracker->host->name, sizeof( st->host ) );
     1625            tr_strlcpy( st->host, tracker->hostname, sizeof( st->host ) );
    17891626            tr_strlcpy( st->announce, tracker->announce, sizeof( st->announce ) );
    17901627            st->tier = i;
     
    19051742
    19061743void
    1907 tr_announcerResetTorrent( tr_announcer * announcer, tr_torrent * tor )
     1744tr_announcerResetTorrent( tr_announcer * announcer UNUSED, tr_torrent * tor )
    19081745{
    19091746    tr_ptrArray oldTiers = TR_PTR_ARRAY_INIT;
     
    19171754
    19181755    /* create the new tier/tracker structs */
    1919     addTorrentToTier( announcer, tor->tiers, tor );
     1756    addTorrentToTier( tor->tiers, tor );
    19201757
    19211758    /* if we had tiers already, merge their state into the new structs */
Note: See TracChangeset for help on using the changeset viewer.