Changeset 13879


Ignore:
Timestamp:
Jan 26, 2013, 11:08:51 PM (8 years ago)
Author:
jordan
Message:

(libT) add package-visible API hook for when a block is downloaded. Add unit test to confirm that when the last file finishes downloading, its .part suffix is removed and it's moved from the incomplete to complete dir

Location:
trunk/libtransmission
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/Makefile.am

    r13868 r13879  
    135135  magnet-test \
    136136  metainfo-test \
     137  move-test \
    137138  peer-msgs-test \
    138139  quark-test \
     
    195196metainfo_test_LDFLAGS = ${apps_ldflags}
    196197
     198move_test_SOURCES = move-test.c $(TEST_SOURCES)
     199move_test_LDADD = ${apps_ldadd}
     200move_test_LDFLAGS = ${apps_ldflags}
     201
    197202peer_msgs_test_SOURCES = peer-msgs-test.c $(TEST_SOURCES)
    198203peer_msgs_test_LDADD = ${apps_ldadd}
  • trunk/libtransmission/libtransmission-test.c

    r13868 r13879  
    33
    44#include "transmission.h"
     5#include "torrent.h"
    56#include "libtransmission-test.h"
    67
     
    321322  return tor;
    322323}
     324
     325#define verify_and_block_until_done(tor) \
     326  do { \
     327    tr_torrentVerify (tor); \
     328    do { \
     329      tr_wait_msec (10); \
     330    } while (tor->verifyState != TR_VERIFY_NONE); \
     331  } while (0)
     332
     333
     334void
     335libtransmission_test_zero_torrent_populate (tr_torrent * tor, bool complete)
     336{
     337  tr_file_index_t i;
     338
     339  for (i=0; i<tor->info.fileCount; ++i)
     340    {
     341      int rv;
     342      uint64_t j;
     343      FILE * fp;
     344      char * path;
     345      char * dirname;
     346      const tr_file * file = &tor->info.files[i];
     347      struct stat sb;
     348
     349      path = tr_buildPath (tor->currentDir, file->name, NULL);
     350      dirname = tr_dirname (path);
     351      tr_mkdirp (dirname, 0700);
     352      fp = fopen (path, "wb+");
     353      for (j=0; j<file->length; ++j)
     354        fputc ('\0', fp);
     355      fclose (fp);
     356
     357      tr_free (dirname);
     358      tr_free (path);
     359
     360      path = tr_torrentFindFile (tor, i);
     361      assert (path != NULL);
     362      rv = stat (path, &sb);
     363      assert (rv == 0);
     364      tr_free (path);
     365    }
     366
     367  sync ();
     368
     369  if (!complete)
     370    {
     371      FILE * fp;
     372      char * oldpath = tr_torrentFindFile (tor, 0);
     373      char * newpath = tr_strdup_printf ("%s.part", oldpath);
     374
     375      rename (oldpath, newpath);
     376
     377      /* invalidate one piece */
     378      fp = fopen (newpath, "rb+");
     379      fputc ('\1', fp);
     380      fclose (fp);
     381
     382      tr_free (newpath);
     383      tr_free (oldpath);
     384
     385      sync ();
     386      verify_and_block_until_done (tor);
     387      assert (tr_torrentStat(tor)->leftUntilDone == tor->info.pieceSize);
     388    }
     389}
  • trunk/libtransmission/libtransmission-test.h

    r13825 r13879  
    7878
    7979void libtransmission_test_session_close (void);
     80
     81void         libtransmission_test_zero_torrent_populate (tr_torrent * tor, bool complete);
    8082tr_torrent * libtransmission_test_zero_torrent_init (void);
    8183
  • trunk/libtransmission/peer-mgr.c

    r13868 r13879  
    15591559
    15601560static void
    1561 gotBadPiece (Torrent * t, tr_piece_index_t pieceIndex)
    1562 {
    1563     tr_torrent *   tor = t->tor;
    1564     const uint32_t byteCount = tr_torPieceCountBytes (tor, pieceIndex);
    1565 
    1566     tor->corruptCur += byteCount;
    1567     tor->downloadedCur -= MIN (tor->downloadedCur, byteCount);
    1568 
    1569     tr_announcerAddBytes (tor, TR_ANN_CORRUPT, byteCount);
    1570 }
    1571 
    1572 static void
    15731561peerSuggestedPiece (Torrent            * t UNUSED,
    15741562                    tr_peer            * peer UNUSED,
     
    16451633}
    16461634
    1647 static void tr_peerMgrSetBlame (tr_torrent *, tr_piece_index_t, int);
     1635static void
     1636cancelAllRequestsForBlock (struct tr_torrent_peers * t,
     1637                           tr_block_index_t          block,
     1638                           tr_peer                 * no_notify)
     1639{
     1640  int i;
     1641  int peerCount;
     1642  tr_peer ** peers;
     1643  tr_ptrArray peerArr;
     1644
     1645  peerArr = TR_PTR_ARRAY_INIT;
     1646  getBlockRequestPeers (t, block, &peerArr);
     1647  peers = (tr_peer **) tr_ptrArrayPeek (&peerArr, &peerCount);
     1648  for (i=0; i<peerCount; ++i)
     1649    {
     1650      tr_peer * p = peers[i];
     1651
     1652      if ((p != no_notify) && (p->msgs != NULL))
     1653        {
     1654          tr_historyAdd (&p->cancelsSentToPeer, tr_time (), 1);
     1655          tr_peerMsgsCancel (p->msgs, block);
     1656        }
     1657
     1658      removeRequestFromTables (t, block, p);
     1659    }
     1660
     1661  tr_ptrArrayDestruct (&peerArr, NULL);
     1662}
     1663
     1664void
     1665tr_peerMgrPieceCompleted (tr_torrent * tor, tr_piece_index_t p)
     1666{
     1667  int i;
     1668  int peerCount;
     1669  tr_peer ** peers;
     1670  struct tr_torrent_peers * t = tor->torrentPeers;
     1671
     1672  /* notify the peers that we now have this piece */
     1673  peerCount = tr_ptrArraySize (&t->peers);
     1674  peers = (tr_peer**) tr_ptrArrayBase (&t->peers);
     1675  for (i=0; i<peerCount; ++i)
     1676    tr_peerMsgsHave (peers[i]->msgs, p);
     1677
     1678  /* bookkeeping */
     1679  pieceListRemovePiece (t, p);
     1680  t->needsCompletenessCheck = true;
     1681}
    16481682
    16491683static void
     
    17591793
    17601794        case TR_PEER_CLIENT_GOT_BLOCK:
    1761         {
    1762             tr_torrent * tor = t->tor;
    1763             tr_block_index_t block = _tr_block (tor, e->pieceIndex, e->offset);
    1764             int i, peerCount;
    1765             tr_peer ** peers;
    1766             tr_ptrArray peerArr = TR_PTR_ARRAY_INIT;
    1767 
    1768             removeRequestFromTables (t, block, peer);
    1769             getBlockRequestPeers (t, block, &peerArr);
    1770             peers = (tr_peer **) tr_ptrArrayPeek (&peerArr, &peerCount);
    1771 
    1772             /* remove additional block requests and send cancel to peers */
    1773             for (i=0; i<peerCount; i++) {
    1774                 tr_peer * p = peers[i];
    1775                 assert (p != peer);
    1776                 if (p->msgs) {
    1777                     tr_historyAdd (&p->cancelsSentToPeer, tr_time (), 1);
    1778                     tr_peerMsgsCancel (p->msgs, block);
    1779                 }
    1780                 removeRequestFromTables (t, block, p);
    1781             }
    1782 
    1783             tr_ptrArrayDestruct (&peerArr, false);
    1784 
    1785             tr_historyAdd (&peer->blocksSentToClient, tr_time (), 1);
    1786 
    1787             if (tr_cpBlockIsComplete (&tor->completion, block))
    1788             {
    1789                 /* we already have this block... */
    1790                 const uint32_t n = tr_torBlockCountBytes (tor, block);
    1791                 tor->downloadedCur -= MIN (tor->downloadedCur, n);
    1792                 tordbg (t, "we have this block already...");
    1793             }
    1794             else
    1795             {
    1796                 tr_cpBlockAdd (&tor->completion, block);
    1797                 pieceListResortPiece (t, pieceListLookup (t, e->pieceIndex));
    1798                 tr_torrentSetDirty (tor);
    1799 
    1800                 if (tr_cpPieceIsComplete (&tor->completion, e->pieceIndex))
    1801                 {
    1802                     const tr_piece_index_t p = e->pieceIndex;
    1803                     const bool ok = tr_torrentCheckPiece (tor, p);
    1804 
    1805                     tordbg (t, "[LAZY] checked just-completed piece %zu", (size_t)p);
    1806 
    1807                     if (!ok)
    1808                     {
    1809                         tr_logAddTorErr (tor, _("Piece %lu, which was just downloaded, failed its checksum test"),
    1810                                  (unsigned long)p);
    1811                     }
    1812 
    1813                     tr_peerMgrSetBlame (tor, p, ok);
    1814 
    1815                     if (!ok)
    1816                     {
    1817                         gotBadPiece (t, p);
    1818                     }
    1819                     else
    1820                     {
    1821                         int i;
    1822                         int peerCount;
    1823                         tr_peer ** peers;
    1824                         tr_file_index_t fileIndex;
    1825 
    1826                         /* only add this to downloadedCur if we got it from a peer --
    1827                          * webseeds shouldn't count against our ratio. As one tracker
    1828                          * admin put it, "Those pieces are downloaded directly from the
    1829                          * content distributor, not the peers, it is the tracker's job
    1830                          * to manage the swarms, not the web server and does not fit
    1831                          * into the jurisdiction of the tracker." */
    1832                         if (peer->msgs != NULL) {
    1833                             const uint32_t n = tr_torPieceCountBytes (tor, p);
    1834                             tr_announcerAddBytes (tor, TR_ANN_DOWN, n);
    1835                         }
    1836 
    1837                         peerCount = tr_ptrArraySize (&t->peers);
    1838                         peers = (tr_peer**) tr_ptrArrayBase (&t->peers);
    1839                         for (i=0; i<peerCount; ++i)
    1840                             tr_peerMsgsHave (peers[i]->msgs, p);
    1841 
    1842                         for (fileIndex=0; fileIndex<tor->info.fileCount; ++fileIndex) {
    1843                             const tr_file * file = &tor->info.files[fileIndex];
    1844                             if ((file->firstPiece <= p) && (p <= file->lastPiece)) {
    1845                                 if (tr_cpFileIsComplete (&tor->completion, fileIndex)) {
    1846                                     tr_cacheFlushFile (tor->session->cache, tor, fileIndex);
    1847                                     tr_torrentFileCompleted (tor, fileIndex);
    1848                                 }
    1849                             }
    1850                         }
    1851 
    1852                         pieceListRemovePiece (t, p);
    1853                     }
    1854                 }
    1855 
    1856                 t->needsCompletenessCheck = true;
    1857             }
     1795          {
     1796            const tr_block_index_t block = _tr_block (t->tor, e->pieceIndex, e->offset);
     1797            cancelAllRequestsForBlock (t, block, peer);
     1798            tr_historyAdd (&peer->blocksSentToClient, tr_time(), 1);
     1799            pieceListResortPiece (t, pieceListLookup (t, e->pieceIndex));
     1800            tr_torrentGotBlock (t->tor, block);
    18581801            break;
    1859         }
     1802          }
    18601803
    18611804        case TR_PEER_ERROR:
     
    22322175**/
    22332176
    2234 static void
    2235 tr_peerMgrSetBlame (tr_torrent     * tor,
    2236                     tr_piece_index_t pieceIndex,
    2237                     int              success)
    2238 {
    2239     if (!success)
    2240     {
    2241         int        peerCount, i;
    2242         Torrent *  t = tor->torrentPeers;
    2243         tr_peer ** peers;
    2244 
    2245         assert (torrentIsLocked (t));
    2246 
    2247         peers = (tr_peer **) tr_ptrArrayPeek (&t->peers, &peerCount);
    2248         for (i = 0; i < peerCount; ++i)
     2177void
     2178tr_peerMgrGotBadPiece (tr_torrent * tor, tr_piece_index_t pieceIndex)
     2179{
     2180  int i;
     2181  int n;
     2182  Torrent * t = tor->torrentPeers;
     2183  const uint32_t byteCount = tr_torPieceCountBytes (tor, pieceIndex);
     2184
     2185  for (i=0, n=tr_ptrArraySize(&t->peers); i!=n; ++i)
     2186    {
     2187      tr_peer * peer = tr_ptrArrayNth (&t->peers, i);
     2188
     2189      if (tr_bitfieldHas (&peer->blame, pieceIndex))
    22492190        {
    2250             tr_peer * peer = peers[i];
    2251             if (tr_bitfieldHas (&peer->blame, pieceIndex))
    2252             {
    2253                 tordbg (t, "peer %s contributed to corrupt piece (%d); now has %d strikes",
    2254                         tr_atomAddrStr (peer->atom),
    2255                         pieceIndex, (int)peer->strikes + 1);
    2256                 addStrike (t, peer);
    2257             }
     2191          tordbg (t, "peer %s contributed to corrupt piece (%d); now has %d strikes",
     2192                  tr_atomAddrStr(peer->atom), pieceIndex, (int)peer->strikes + 1);
     2193          addStrike (t, peer);
    22582194        }
    22592195    }
     2196
     2197
     2198  tr_announcerAddBytes (tor, TR_ANN_CORRUPT, byteCount);
    22602199}
    22612200
  • trunk/libtransmission/peer-mgr.h

    r13683 r13879  
    256256void tr_peerMgrClearInterest (tr_torrent * tor);
    257257
     258void tr_peerMgrGotBadPiece (tr_torrent * tor, tr_piece_index_t pieceIndex);
     259
     260void tr_peerMgrPieceCompleted (tr_torrent * tor, tr_piece_index_t pieceIndex);
     261 
     262
     263
    258264/* @} */
    259265
  • trunk/libtransmission/rename-test.c

    r13857 r13879  
    188188  check_have_none (tor, totalSize);
    189189
    190   create_single_file_torrent_contents (tor->downloadDir);
     190  create_single_file_torrent_contents (tor->currentDir);
    191191
    192192  /* sanity check the stats again, now that we've added the file */
     
    215215  ***/
    216216
    217   tmpstr = tr_buildPath (tor->downloadDir, "hello-world.txt", NULL);
     217  tmpstr = tr_buildPath (tor->currentDir, "hello-world.txt", NULL);
    218218  check (tr_fileExists (tmpstr, NULL));
    219219  check_streq ("hello-world.txt", tr_torrentName(tor));
     
    238238  ***/
    239239
    240   tmpstr = tr_buildPath (tor->downloadDir, "foobar", NULL);
     240  tmpstr = tr_buildPath (tor->currentDir, "foobar", NULL);
    241241  check (tr_fileExists (tmpstr, NULL));
    242242  check_int_eq (0, torrentRenameAndWait (tor, "foobar", "hello-world.txt"));
     
    334334
    335335  /* build the local data */
    336   create_multifile_torrent_contents (tor->downloadDir);
     336  create_multifile_torrent_contents (tor->currentDir);
    337337
    338338  /* sanity check the (full) stats */
     
    396396
    397397  /* remove the directory Felidae/Felinae/Felis/catus */
    398   str = tr_buildPath (tor->downloadDir, files[1].name, NULL);
     398  str = tr_buildPath (tor->currentDir, files[1].name, NULL);
    399399  remove (str);
    400400  tr_free (str);
    401   str = tr_buildPath (tor->downloadDir, files[2].name, NULL);
     401  str = tr_buildPath (tor->currentDir, files[2].name, NULL);
    402402  remove (str);
    403403  tmp = tr_dirname (str);
     
    462462***/
    463463
    464 static void
    465 create_zero_torrent_partial_contents (tr_torrent * tor, bool incomplete)
    466 {
    467   tr_file_index_t i;
    468 
    469   for (i=0; i<tor->info.fileCount; ++i)
    470     {
    471       int rv;
    472       uint64_t j;
    473       FILE * fp;
    474       char * path;
    475       char * dirname;
    476       const tr_file * file = &tor->info.files[i];
    477       struct stat sb;
    478 
    479       path = tr_buildPath (tor->downloadDir, file->name, NULL);
    480       dirname = tr_dirname (path);
    481       tr_mkdirp (dirname, 0700);
    482       fp = fopen (path, "wb+");
    483       for (j=0; j<file->length; ++j)
    484         fputc ('\0', fp);
    485       fclose (fp);
    486 
    487       tr_free (dirname);
    488       tr_free (path);
    489 
    490       path = tr_torrentFindFile (tor, i);
    491       assert (path != NULL);
    492       rv = stat (path, &sb);
    493       assert (rv == 0);
    494       tr_free (path);
    495     }
    496 
    497   sync ();
    498   verify_and_block_until_done (tor);
    499   assert (tr_torrentStat(tor)->leftUntilDone == 0);
    500 
    501   if (incomplete)
    502     {
    503       FILE * fp;
    504       char * oldpath = tr_torrentFindFile (tor, 0);
    505       char * newpath = tr_strdup_printf ("%s.part", oldpath);
    506 
    507       rename (oldpath, newpath);
    508 
    509       /* invalidate one piece */
    510       fp = fopen (newpath, "rb+");
    511       fputc ('\1', fp);
    512       fclose (fp);
    513 
    514       tr_free (newpath);
    515       tr_free (oldpath);
    516 
    517       sync ();
    518       verify_and_block_until_done (tor);
    519       assert (tr_torrentStat(tor)->leftUntilDone == tor->info.pieceSize);
    520     }
    521 }
    522 
    523464static int
    524465test_partial_file (void)
     
    546487  check_streq ("files-filled-with-zeroes/512",     tor->info.files[2].name);
    547488
    548   create_zero_torrent_partial_contents (tor, true);
     489  libtransmission_test_zero_torrent_populate (tor, false);
    549490  fst = tr_torrentFiles (tor, NULL);
    550491  check_int_eq (length[0] - pieceSize, fst[0].bytesCompleted);
     
    573514  for (i=0; i<3; ++i)
    574515    {
    575       char * expected = tr_buildPath (tor->downloadDir, strings[i], NULL);
     516      char * expected = tr_buildPath (tor->currentDir, strings[i], NULL);
    576517      char * path = tr_torrentFindFile (tor, i);
    577518      check_streq (expected, path);
  • trunk/libtransmission/torrent.c

    r13868 r13879  
    13291329
    13301330static uint64_t
    1331 fileBytesCompleted (const tr_torrent * tor, tr_file_index_t index)
     1331countFileBytesCompleted (const tr_torrent * tor, tr_file_index_t index)
    13321332{
    13331333    uint64_t total = 0;
     
    13801380
    13811381    for (i=0; i<n; ++i, ++walk) {
    1382         const uint64_t b = isSeed ? tor->info.files[i].length : fileBytesCompleted (tor, i);
     1382        const uint64_t b = isSeed ? tor->info.files[i].length : countFileBytesCompleted (tor, i);
    13831383        walk->bytesCompleted = b;
    13841384        walk->progress = tor->info.files[i].length > 0 ? ((float)b / tor->info.files[i].length) : 1.0f;
     
    30013001***/
    30023002
    3003 void
    3004 tr_torrentFileCompleted (tr_torrent * tor, tr_file_index_t fileNum)
     3003static void
     3004tr_torrentFileCompleted (tr_torrent * tor, tr_file_index_t fileIndex)
    30053005{
    30063006    char * sub;
    30073007    const char * base;
    30083008    const tr_info * inf = &tor->info;
    3009     const tr_file * f = &inf->files[fileNum];
     3009    const tr_file * f = &inf->files[fileIndex];
    30103010    tr_piece * p;
    30113011    const tr_piece * pend;
     
    30133013
    30143014    /* close the file so that we can reopen in read-only mode as needed */
    3015     tr_fdFileClose (tor->session, tor, fileNum);
     3015    tr_cacheFlushFile (tor->session->cache, tor, fileIndex);
     3016    tr_fdFileClose (tor->session, tor, fileIndex);
    30163017
    30173018    /* now that the file is complete and closed, we can start watching its
     
    30233024     * metadata -- for example, if it had the ".part" suffix appended to
    30243025     * it until now -- then rename it to match the one in the metadata */
    3025     if (tr_torrentFindFile2 (tor, fileNum, &base, &sub, NULL))
     3026    if (tr_torrentFindFile2 (tor, fileIndex, &base, &sub, NULL))
    30263027    {
    30273028        if (strcmp (sub, f->name))
     
    30383039
    30393040        tr_free (sub);
     3041    }
     3042}
     3043
     3044static void
     3045tr_torrentPieceCompleted (tr_torrent * tor, tr_piece_index_t pieceIndex)
     3046{
     3047  tr_file_index_t i;
     3048
     3049  tr_peerMgrPieceCompleted (tor, pieceIndex);
     3050
     3051  /* if this piece completes any file, invoke the fileCompleted func for it */
     3052  for (i=0; i<tor->info.fileCount; ++i)
     3053    {
     3054      const tr_file * file = &tor->info.files[i];
     3055
     3056      if ((file->firstPiece <= pieceIndex) && (pieceIndex <= file->lastPiece))
     3057        if (tr_cpFileIsComplete (&tor->completion, i))
     3058          tr_torrentFileCompleted (tor, i);
     3059    }
     3060}
     3061
     3062void
     3063tr_torrentGotBlock (tr_torrent * tor, tr_block_index_t block)
     3064{
     3065  const bool block_is_new = !tr_cpBlockIsComplete (&tor->completion, block);
     3066
     3067  if (block_is_new)
     3068    {
     3069      tr_piece_index_t p;
     3070
     3071      tr_cpBlockAdd (&tor->completion, block);
     3072      tr_torrentSetDirty (tor);
     3073
     3074      p = tr_torBlockPiece (tor, block);
     3075      if (tr_cpPieceIsComplete (&tor->completion, p))
     3076        {
     3077          tr_logAddTorDbg (tor, "[LAZY] checking just-completed piece %zu", (size_t)p);
     3078
     3079          if (tr_torrentCheckPiece (tor, p))
     3080            {
     3081              tr_torrentPieceCompleted (tor, p);
     3082            }
     3083          else
     3084            {
     3085              const uint32_t n = tr_torPieceCountBytes (tor, p);
     3086              tr_logAddTorErr (tor, _("Piece %"PRIu32", which was just downloaded, failed its checksum test"), p);
     3087              tor->corruptCur += n;
     3088              tor->downloadedCur -= MIN (tor->downloadedCur, n);
     3089              tr_peerMgrGotBadPiece (tor, p);
     3090            }
     3091        }
     3092    }
     3093  else
     3094    {
     3095      const uint32_t n = tr_torBlockCountBytes (tor, block);
     3096      tor->downloadedCur -= MIN (tor->downloadedCur, n);
     3097      tr_logAddTorDbg (tor, "we have this block already...");
    30403098    }
    30413099}
  • trunk/libtransmission/torrent.h

    r13780 r13879  
    383383
    384384/**
    385  * Tell the tr_torrent that one of its files has become complete
     385 * Tell the tr_torrent that it's gotten a block
    386386 */
    387 void tr_torrentFileCompleted (tr_torrent * tor, tr_file_index_t fileNo);
     387void tr_torrentGotBlock (tr_torrent * tor, tr_block_index_t blockIndex);
     388
    388389
    389390
Note: See TracChangeset for help on using the changeset viewer.