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

📄 btcontent.cpp

📁 最新的enhanced ctorrent源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
  }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);}void btContent::FlushCache(size_t idx){  BTCACHE *p;  p = m_cache[idx];  if( idx == m_npieces ) p = m_cache_oldest;  for( ; p; p = (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 ){        if( m_btfiles.IO(p->bc_buf, p->bc_off, p->bc_len, 1) < 0 ){          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 can also be caused by a disk error.");            CONSOLE.Warning(1, "Temporarily%s suspending download...",              (!m_flush_failed && m_cache_size > cfg_cache_size*1024*1024) ?              " increasing cache size and" : "");            m_flush_failed = now;            WORLD.SeedOnly(1);          }          return;        }else{          p->bc_f_flush = 0;          if(m_flush_failed){            CONSOLE.Warning(3, "Flushing cache succeeded, resuming download");            m_flush_failed = 0;            CacheConfigure();            WORLD.SeedOnly(0);          }        }      }    }else if( idx < p->bc_off / m_piece_length ) break;  }}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;}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 &&         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;  }  if( idx < m_npieces ){    // Don't use the cache for this (looks a bit ugly but helps performance).    size_t tmp_cache_size = m_cache_size;    m_cache_size = 0;    int r = GetHashValue(idx, md);    m_cache_size = tmp_cache_size;    if( r < 0 ) return -1;    pBChecked->Set(idx);  // need to set before CheckInterest below    if( memcmp(md, m_hash_table + idx * 20, 20) == 0 ){      m_left_bytes -= GetPieceLength(idx);      pBF->Set(idx);      WORLD.Tell_World_I_Have(idx);      if( pBF->IsFull() ){        WORLD.CloseAllConnectionToSeed();      }    } else f_checkint = 1;    m_check_piece = idx + 1;  }  if( f_checkint ) WORLD.CheckInterest();  if( m_check_piece >= m_npieces ){    CONSOLE.Print("Checking completed.");    m_btfiles.PrintOut();  // show file completion    delete pBRefer;  }  return 0;}char* btContent::_file2mem(const char *fname, size_t *psiz){  char *b = (char*) 0;  struct stat sb;  FILE* fp;  fp = fopen(fname,"r");  if( !fp ){    CONSOLE.Warning(1, "error, open %s failed. %s",fname,strerror(errno));    return (char*) 0;  }  if(stat(fname,&sb) < 0){    CONSOLE.Warning(1, "error, stat %s failed, %s",fname,strerror(errno));    return (char*) 0;  }  if( sb.st_size > MAX_METAINFO_FILESIZ ){    CONSOLE.Warning(1, "error, %s is really a metainfo file???",fname);    return (char*) 0;  }  b = new char[sb.st_size];#ifndef WINDOWS  if( !b ) return (char*) 0;#endif  if(fread(b, sb.st_size, 1, fp) != 1){    if( ferror(fp) ){      delete []b;      return (char*) 0;    }  }  fclose(fp);  if(psiz) *psiz = sb.st_size;  return b;}int btContent::APieceComplete(size_t idx){  unsigned char md[20];  if(pBF->IsSet(idx)) return 1;  if( GetHashValue(idx, md) < 0 ){    Uncache(idx);    return -1;  }  if( memcmp(md,(m_hash_table + idx * 20), 20) != 0 ){    CONSOLE.Warning(3, "warn, piece %d hash check failed.", idx);    return 0;  }  pBF->Set(idx);  m_left_bytes -= GetPieceLength(idx);  FlushCache(idx);  return 1;}int btContent::GetHashValue(size_t idx,unsigned char *md){  if( ReadPiece(global_piece_buffer,idx) < 0 ) return -1;  Sha1(global_piece_buffer,GetPieceLength(idx),md);  return 0;}// This is btcontent's "IntervalCheck()"int btContent::SeedTimeout(){  uint64_t dl;  if( pBF->IsFull() ){    if( !m_seed_timestamp ){      Tracker.Reset(1);      Self.ResetDLTimer();  // set/report dl rate = 0      ReleaseHashTable();      m_seed_timestamp = now;      FlushCache();      if( Self.TotalDL() > 0 ){        CONSOLE.Print("Download complete.");        CONSOLE.Print("Total time used: %ld minutes.",          (long)((now - m_start_timestamp) / 60));      }      CONSOLE.Print_n("Seed for others %lu hours",        (unsigned long)cfg_seed_hours);      if( cfg_seed_ratio )        CONSOLE.Print_n(" or to ratio of %.2f", cfg_seed_ratio);      CONSOLE.Print("");    }else if( now < m_seed_timestamp ) m_seed_timestamp = now;    dl = (Self.TotalDL() > 0) ? Self.TotalDL() : GetTotalFilesLength();    if( (cfg_seed_ratio == 0 && cfg_seed_hours == 0) ||        (cfg_seed_hours > 0 &&          (now - m_seed_timestamp) >= (cfg_seed_hours * 60 * 60)) ||        (cfg_seed_ratio > 0 &&          cfg_seed_ratio <= (double) Self.TotalUL() / dl) ) return 1;  }  if( cfg_cache_size && now >= m_cache_eval_time ) CacheEval();  return 0;}size_t btContent::getFilePieces(size_t nfile){   return m_btfiles.getFilePieces(nfile);}void btContent::SetFilter(){  FlushCache();  m_btfiles.SetFilter(arg_file_to_download,pBFilter,m_piece_length, 1);  WORLD.CheckInterest();}// Note, this functions assumes the program is exiting.void btContent::SaveBitfield(){  if( arg_bitfield_file ){    if( m_check_piece < m_npieces ){  // still checking      pBChecked->Invert();      pBRefer->And(*pBChecked);      pBF->Comb(*pBRefer);    }    if( !pBF->IsFull() ) pBF->WriteToFile(arg_bitfield_file);  }}void btContent::DumpCache(){  BTCACHE *p = m_cache_oldest;  CONSOLE.Debug("CACHE CONTENTS:");  for( ; p; p = p->age_next ){    CONSOLE.Debug("  0x%llx: %d bytes %sflushed",      p->bc_off, (int)(p->bc_len), p->bc_f_flush ? "un" : "");  }}

⌨️ 快捷键说明

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