⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 btcontent.cpp

📁 最经典的bittorrent协议的实现的源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
  return retval;}void btContent::CacheClean(size_t need){  BTCACHE *p, *pnext;  int f_flush = 0;  if( m_flush_failed ) FlushCache();  // try again  again:  for( p=m_cache_oldest; p && m_cache_size < m_cache_used + need; p=pnext ){    pnext = p->age_next;    if( f_flush ) FlushEntry(p);    if( !p->bc_f_flush ){      if( p->age_prev ) p->age_prev->age_next = p->age_next;      else m_cache_oldest = p->age_next;      if( p->age_next ) p->age_next->age_prev = p->age_prev;      else m_cache_newest = p->age_prev;      if( p->bc_prev ) p->bc_prev->bc_next = p->bc_next;      if( p->bc_next ) p->bc_next->bc_prev = p->bc_prev;      size_t idx = p->bc_off / m_piece_length;      if( p->bc_next && p->bc_next->bc_off / m_piece_length == idx )        m_cache[idx] = p->bc_next;      else m_cache[idx] = (BTCACHE *)0;      m_cache_used -= p->bc_len;      delete []p->bc_buf;      delete p;    }  }  if( m_cache_size < m_cache_used + need ){  // still not enough    if( m_cache_size < cfg_cache_size*1024*1024 ){  // can alloc more      m_cache_size = (m_cache_used + need > cfg_cache_size*1024*1024) ?        cfg_cache_size*1024*1024 : (m_cache_used + need);    }    if( m_cache_size < m_cache_used + need && m_cache_used && !f_flush ){      if(arg_verbose) CONSOLE.Debug("CacheClean flushing to obtain space");      f_flush = 1;      goto again;    }  // else we tried...  }}// Don't call this function if cfg_cache_size==0 !void btContent::CacheEval(){  BTCACHE *p = m_cache_oldest;  size_t interval;  size_t unflushed = 0, dlnext, upadd = 0, upmax = 0, upmin = 0, total;  size_t rateup = Self.RateUL();  size_t ratedn = Self.RateDL();  size_t unchoked = WORLD.GetUnchoked();  // Time until next cache size eval: unchoke interval or time to dl a piece.  if( ratedn ){    interval = m_piece_length / ratedn;    if( interval > WORLD.GetUnchokeInterval() )      interval = WORLD.GetUnchokeInterval();    else if( 0==interval ) interval = 1;  }else interval = WORLD.GetUnchokeInterval();  // Download: total unflushed data + data to dl before next eval  // Hold the first piece a bit to let uploading begin.  if( pBF->IsFull() ) dlnext = 0;  else{    if( pBF->Count() < 2 ) unflushed = m_cache_used;    else for( ; p; p = p->age_next )      if( p->bc_f_flush ) unflushed += p->bc_len;    // Make sure we can read back and check a completed piece.    dlnext = ratedn * interval + m_piece_length;    // Set a shorter interval if DL cache need is very high.    if( ratedn ){      size_t max =        (cfg_cache_size*1024*1024 - unflushed - m_piece_length) / ratedn;      if( interval > max ) interval = max;    }  }  // Upload: need enough to hold read/dl'd data until it can be sent  upmin = DEFAULT_SLICE_SIZE * unchoked;  upmax = cfg_cache_size*1024*1024;  if( pBF->IsFull() ){    // Seed mode.  All cache data is prefetched, and we don't normally need to    // keep prefetched data longer than 2.5 unchoke intervals.    if( rateup && unchoked ){      // A very slow peer can't possibly benefit from cache--don't grow for it.      size_t slowest = (size_t)( 1 + DEFAULT_SLICE_SIZE /                                 ((double)cfg_cache_size*1024*1024 / rateup) );      // Lead cache: data we need to cache to keep the slowest up's data cached      // Add a slice per up for timing uncertainty      if( slowest = WORLD.GetSlowestUp(slowest) )        upadd = DEFAULT_SLICE_SIZE * ( rateup / slowest + unchoked-1 );      else upadd = DEFAULT_SLICE_SIZE * unchoked;      upmin = DEFAULT_SLICE_SIZE * unchoked;      upmax = (size_t)( DEFAULT_SLICE_SIZE * (unchoked-1) +        rateup * 2.5 * WORLD.GetUnchokeInterval() );    }  }else{    if( rateup > ratedn ){      size_t slowest = (size_t)( 1 +        cfg_req_slice_size * ((double)ratedn / cfg_cache_size*1024*1024) +        DEFAULT_SLICE_SIZE * ((double)rateup / cfg_cache_size*1024*1024) );      if( slowest = WORLD.GetSlowestUp(slowest) )        // lead cache is how much we'll use while uploading a slice to slowest        // (default_slice_size / slowest) * (ratedn + rateup)        upadd = (size_t)( ((double)DEFAULT_SLICE_SIZE / slowest) *                          (ratedn + rateup + 1) );      else upadd = m_piece_length * unchoked;    }    else if( rateup ){      // same as m_piece_length / (cfg_cache_size*1024*1024 / (double)ratedn)      size_t slowest = (size_t)( 1 +        ratedn * ((double)m_piece_length / (cfg_cache_size*1024*1024)) );      if( slowest = WORLD.GetSlowestUp(slowest) ){        // m_piece_length / (double)slowest * ratedn        // optimize, then round up a piece and add a piece        upadd = m_piece_length * (ratedn / slowest + 2);      }else{  // gimme 10 seconds worth (unchoke interval)        // Can't keep pieces in cache long enough to upload them.        // Rely on prefetching slices from disk instead.        upadd = ratedn * WORLD.GetUnchokeInterval() +                DEFAULT_SLICE_SIZE * unchoked;      }    }  }  if( upadd < upmin ) upadd = upmin;  // Add a slice to round up  total = unflushed + dlnext + upadd + cfg_req_slice_size;  // Limit to max configured size  if( total > cfg_cache_size*1024*1024 ) total = cfg_cache_size*1024*1024;  // Don't decrease cache size if flush failed.  if( !m_flush_failed || total > m_cache_size ) m_cache_size = total;  if(arg_verbose)    CONSOLE.Debug("DL need: %dK  UL need: %dK  Cache: %dK  Used: %dK",    (int)((unflushed+dlnext)/1024), (int)(upadd/1024),    (int)(m_cache_size/1024), (int)(m_cache_used/1024));  m_cache_eval_time = now + interval;}void btContent::CacheConfigure(){  if( cfg_cache_size ){    if( cfg_cache_size > GetTotalFilesLength()/1024/1024 )      cfg_cache_size = (GetTotalFilesLength()+1024*1024-1)/1024/1024;    CacheEval();  }else m_cache_size = 0;  if( m_cache_size < m_cache_used && !m_flush_failed ) CacheClean(0);}int btContent::NeedFlush() const{  if( m_flush_failed ){    if( now > m_flush_tried ) return 1;  }else return m_flushq ? 1 : 0;}void btContent::FlushCache(size_t idx){  BTCACHE *p, *pnext;  if( idx >= m_npieces ){    if(arg_verbose) CONSOLE.Debug("Flushing all cache");    if( m_flushq) do{      FlushQueue();    }while( m_flushq && !m_flush_failed );    p = m_cache_oldest;  } else p = m_cache[idx];  for( ; p; p = pnext ){    pnext = (idx < m_npieces) ? p->bc_next : p->age_next;    if( idx == p->bc_off / m_piece_length ||        (p->bc_f_flush && idx == m_npieces) ||        idx == (p->bc_off+p->bc_len-1) / m_piece_length ){      // update the age--flushing the entry or its piece      if( m_cache_newest != p ){        if( p->age_prev ) p->age_prev->age_next = p->age_next;        else if( p->age_next ) m_cache_oldest = p->age_next;        if( p->age_next ) p->age_next->age_prev = p->age_prev;        m_cache_newest->age_next = p;        p->age_next = (BTCACHE *)0;        p->age_prev = m_cache_newest;        m_cache_newest = p;      }      if( p->bc_f_flush ) FlushEntry(p);    }  }}void btContent::FlushEntry(BTCACHE *p){  if( p->bc_f_flush ){    if( m_btfiles.IO(p->bc_buf, p->bc_off, p->bc_len, 1) < 0 ){      m_flush_tried = now;      if( now >= m_flush_failed + 300 ){        if( !m_flush_failed )          m_cache_size += cfg_req_slice_size * WORLD.GetDownloads() * 2;        CONSOLE.Warning(1, "warn, write file failed while flushing cache.");        CONSOLE.Warning(1,          "You need to have at least %llu bytes free on this filesystem!",          (unsigned long long)(m_left_bytes + m_cache_used));        CONSOLE.Warning(1,          "This could also be caused by a conflict or disk error.");        if( !IsFull() ||            (!m_flush_failed && m_cache_size > cfg_cache_size*1024*1024) ){          CONSOLE.Warning(1, "Temporarily %s%s...",            IsFull() ? "" : "suspending download",            (!m_flush_failed && m_cache_size > cfg_cache_size*1024*1024) ?              (IsFull() ? " and increasing cache" : "increasing cache") : "");        }        m_flush_failed = now;        WORLD.StopDownload();      }    }else{      p->bc_f_flush = 0;      if( Seeding() ){        for( size_t n=1; n <= m_btfiles.GetNFiles(); n++ )          m_btfiles.CloseFile(n);  // files will reopen read-only      }      if(m_flush_failed){        m_flush_failed = 0;        CONSOLE.Warning(3, "Flushing cache succeeded%s.",          Seeding() ? "" : "; resuming download");        CacheConfigure();        WORLD.CheckInterest();      }    }  }}void btContent::Uncache(size_t idx){  BTCACHE *p, *pnext;  p = m_cache[idx];  for( ; p; p = pnext ){    pnext = p->bc_next;    if( idx == p->bc_off / m_piece_length ){      if( p->age_prev ) p->age_prev->age_next = p->age_next;      else m_cache_oldest = p->age_next;      if( p->age_next ) p->age_next->age_prev = p->age_prev;      else m_cache_newest = p->age_prev;      if( p->bc_prev ) p->bc_prev->bc_next = p->bc_next;      if( p->bc_next ) p->bc_next->bc_prev = p->bc_prev;      m_cache_used -= p->bc_len;      delete []p->bc_buf;      delete p;    }else break;  }  m_cache[idx] = (BTCACHE *)0;}void btContent::FlushQueue(){  if( !m_flushq ) return;  if(arg_verbose)    CONSOLE.Debug("Writing piece #%d to disk", (int)(m_flushq->idx));  FlushCache(m_flushq->idx);  if( !m_flush_failed ){    BTFLUSH *goner = m_flushq;    m_flushq = m_flushq->next;    delete goner;  }}ssize_t btContent::WriteSlice(char *buf,size_t idx,size_t off,size_t len){  uint64_t offset = (uint64_t)idx * (uint64_t)m_piece_length + off;  //CONSOLE.Debug("Offset-write: %llu - Piece:%lu",  //  (unsigned long long)offset, (unsigned long)idx);  if( !m_cache_size ) return m_btfiles.IO(buf, offset, len, 1);  else{    size_t len2;    int flg_rescan;    BTCACHE *p;    p = m_cache[idx];    for( ; p && (offset + len) > p->bc_off && !CACHE_FIT(p,offset,len);        p = p->bc_next );    for( ; len && p && CACHE_FIT(p, offset, len); ){      flg_rescan = 0;      if( offset < p->bc_off ){        len2 = p->bc_off - offset;        if( CacheIO(buf, offset, len2, 1) < 0 ) return -1;        flg_rescan = 1;      }else{        if( offset > p->bc_off ){          len2 = p->bc_off + p->bc_len - offset;          if( len2 > len ) len2 = len;          memcpy(p->bc_buf + offset - p->bc_off, buf, len2);          p->bc_f_flush = 1;        }else{          len2 = (len > p->bc_len) ? p->bc_len : len;          memcpy(p->bc_buf, buf, len2);          p->bc_f_flush = 1;        }        // re-received this data, make it new again        if( m_cache_newest != p ){          if( p->age_prev ) p->age_prev->age_next = p->age_next;          else if( p->age_next ) m_cache_oldest = p->age_next;          if( p->age_next ) p->age_next->age_prev = p->age_prev;          m_cache_newest->age_next = p;          p->age_next = (BTCACHE *)0;          p->age_prev = m_cache_newest;          m_cache_newest = p;        }      }      buf += len2;      offset += len2;      len -= len2;      if( len ){        if( flg_rescan ){          for( p = m_cache[idx];               p && (offset + len) > p->bc_off && !CACHE_FIT(p,offset,len);               p = p->bc_next );        }else{          p = p->bc_next;        }      }    }// end for;      if( len ) return CacheIO(buf, offset, len, 1);  }  return 0;}ssize_t btContent::CacheIO(char *buf, uint64_t off, size_t len, int method){  BTCACHE *p;  BTCACHE *pp = (BTCACHE*) 0;  BTCACHE *pnew = (BTCACHE*) 0;  if(arg_verbose && 0==method)    CONSOLE.Debug("Read to %s %d/%d/%d", buf?"buffer":"cache",      (int)(off / m_piece_length), (int)(off % m_piece_length), (int)len);  if( m_cache_size < m_cache_used + len ) CacheClean(len);  // Note, there is no failure code from CacheClean().  If nothing can be done  // to increase the cache size, we allocate what we need anyway.    if( 0==method && buf && m_btfiles.IO(buf, off, len, method) < 0 ) return -1;    pnew = new BTCACHE;#ifndef WINDOWS  if( !pnew )    return (method && buf) ? m_btfiles.IO(buf, off, len, method) : 0;#endif  pnew->bc_buf = new char[len];#ifndef WINDOWS  if( !(pnew->bc_buf) ){     delete pnew;     return (method && buf) ? m_btfiles.IO(buf, off, len, method) : 0;  }#endif  if( buf ) memcpy(pnew->bc_buf, buf, len);  else if( 0==method && m_btfiles.IO(pnew->bc_buf, off, len, method) < 0 )    return -1;  pnew->bc_off = off;  pnew->bc_len = len;  pnew->bc_f_flush = method;  m_cache_used += len;  pnew->age_next = (BTCACHE *)0;  if( m_cache_newest ){    pnew->age_prev = m_cache_newest;    m_cache_newest->age_next = pnew;  }else{    pnew->age_prev = (BTCACHE *)0;    m_cache_oldest = pnew;  }  m_cache_newest = pnew;  // find insert point: after pp, before p.  size_t idx = off / m_piece_length;  p = m_cache[idx];  if( p ) pp = p->bc_prev;  for( ; p && off > p->bc_off; pp = p, p = pp->bc_next );  pnew->bc_next = p;  pnew->bc_prev = pp;  if( pp ) pp->bc_next = pnew;  if( p ) p->bc_prev = pnew;  if( !m_cache[idx] || off < m_cache[idx]->bc_off )    m_cache[idx] = pnew;  return 0;}ssize_t btContent::ReadPiece(char *buf,size_t idx){  return ReadSlice(buf, idx, 0, GetPieceLength(idx));}size_t btContent::GetPieceLength(size_t idx){  return (idx == m_btfiles.GetTotalLength() / m_piece_length) ?    (size_t)(m_btfiles.GetTotalLength() % m_piece_length)     :m_piece_length;}int btContent::CheckExist(){  size_t idx = 0;  size_t percent = GetNPieces() / 100;  unsigned char md[20];  if( !percent ) percent = 1;  CONSOLE.Interact_n("");  for( ; idx < m_npieces; idx++ ){    if( GetHashValue(idx, md) < 0 ){      CONSOLE.Warning(1, "Error while checking piece %d of %d",        (int)idx+1, (int)m_npieces);      return -1;    }    if( memcmp(md, m_hash_table + idx * 20, 20) == 0 ){       m_left_bytes -= GetPieceLength(idx);       pBF->Set(idx);    }    if( idx % percent == 0 || idx == m_npieces-1 )      CONSOLE.InteractU("Check exist: %d/%d", idx+1, m_npieces);  }  m_check_piece = m_npieces;  pBChecked->SetAll();  delete pBRefer;  return 0;}int btContent::CheckNextPiece(){  size_t idx = m_check_piece;  unsigned char md[20];  int f_checkint = 0;  if( idx >= m_npieces ) return 0;  if( !pBRefer->IsSet(idx) ){    while( idx < m_npieces && !pBRefer->IsSet(idx) ){      pBChecked->Set(idx);      ++idx;    }    f_checkint = 1;    m_check_piece = idx;  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -