Pārlūkot izejas kodu

2007-06-05 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	Make download size shown in MB, KB.
	* src/ConsoleDownloadEngine.h (sendStatistics)
	* src/Util.h, srcUtil.cc (abbrevSize): New function.
Tatsuhiro Tsujikawa 18 gadi atpakaļ
vecāks
revīzija
2722c0591f

+ 6 - 0
ChangeLog

@@ -1,3 +1,9 @@
+2007-06-05  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	Make download size shown in MB, KB.
+	* src/ConsoleDownloadEngine.h (sendStatistics)
+	* src/Util.h, srcUtil.cc (abbrevSize): New function.
+
 2007-06-04  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 	
 	Accept incoming connections if download rate is low.

+ 2 - 5
TODO

@@ -23,13 +23,10 @@
 * Add seed mode.
 
 * Rewrite ByteArrayDiskWriter, TrackerUpdateCommand with stringstream
-* Make trakcerwatchercommand and trackerUploadCommand poses requestGroup 
+* Make trakcerwatchercommand and trackerUploadCommand posses requestGroup 
 * consider life cycle of requestGroup and segmentMan
 
 
-* Add fancy console read out. like this:
-100K/300M(10%)(3cn)(3more) 100KB/s [FileAlloc:35MB/40MB(90%)][Checksum:10MB/20MB(50%)]
 * exit status: all downloads have been successful-> EXIT_SUCCESS,
 		some of downloads have been failed -> EXIT_FAILURE
-* Create download command directly when 1connection download.
-Consider timeout when file allocation/check integrity is enabled.
+

+ 20 - 20
src/CheckIntegrityCommand.cc

@@ -37,40 +37,40 @@
 #include "InitiateConnectionCommandFactory.h"
 #include "DlAbortEx.h"
 #include "message.h"
+#include "DownloadCommand.h"
+#include "prefs.h"
 
-void CheckIntegrityCommand::initValidator()
+CheckIntegrityCommand::CheckIntegrityCommand(int cuid, RequestGroup* requestGroup, DownloadEngine* e, const CheckIntegrityEntryHandle& entry):
+  RealtimeCommand(cuid, requestGroup, e),
+  _entry(entry)
 {
-  _validator = new IteratableChunkChecksumValidator();
-  _validator->setChunkChecksum(_requestGroup->getChunkChecksum());
-  _validator->setDiskWriter(_requestGroup->getSegmentMan()->diskWriter);
-  _validator->setBitfield(_requestGroup->getSegmentMan()->getBitfield());
-  if(!_validator->canValidate()) {
-    // insufficient checksums.
-    throw new DlAbortEx("Insufficient checksums.");
-  }
-  _validator->init();
+  _e->_checkIntegrityMan->addCheckIntegrityEntry(_entry);
+}
+
+CheckIntegrityCommand::~CheckIntegrityCommand()
+{
+  _e->_checkIntegrityMan->removeCheckIntegrityEntry(_entry);
 }
 
 bool CheckIntegrityCommand::executeInternal()
 {
-  _validator->validateChunk();
-  if(_validator->finished()) {
+  _entry->validateChunk();
+  if(_entry->finished()) {
     if(_requestGroup->downloadFinished()) {
       logger->notice(MSG_DOWNLOAD_ALREADY_COMPLETED, cuid, _requestGroup->getFilePath().c_str());
       return true;
     }
     if(_requestGroup->needsFileAllocation()) {
-      FileAllocationEntryHandle entry = new FileAllocationEntry(cuid, _req, _requestGroup);
-      entry->setNextDownloadCommand(_nextDownloadCommand);
-      _nextDownloadCommand = 0;
+      FileAllocationEntryHandle entry = new FileAllocationEntry(cuid, _entry->getCurrentRequest(), _requestGroup, _requestGroup->getExistingFileLength());
+      entry->setNextDownloadCommand(_entry->popNextDownloadCommand());
       _e->_fileAllocationMan->pushFileAllocationEntry(entry); 
     } else {
-      if(_nextDownloadCommand) {
-	_e->commands.push_back(_nextDownloadCommand);
-	_nextDownloadCommand = 0;
+      if(_timer.difference() <= _e->option->getAsInt(PREF_DIRECT_DOWNLOAD_TIMEOUT) &&
+	 _entry->getNextDownloadCommand()) {
+	_e->commands.push_back(_entry->popNextDownloadCommand());
       } else {
 	Commands commands = _requestGroup->createNextCommand(_e);
-	Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, _req, _requestGroup, _e);
+	Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, _entry->getCurrentRequest(), _requestGroup, _e);
 	commands.push_front(command);
 	_e->addCommand(commands);
       }
@@ -91,6 +91,6 @@ bool CheckIntegrityCommand::handleException(Exception* e)
   // exception. Fix this.
   // The one of the solution is having a copy of bitfield before settting its
   // all bit to 1. If exception is thrown, then assign the copy to the bitfield.
-  _requestGroup->markPieceDone(_validator->getCurrentOffset());
+  _requestGroup->markPieceDone(_entry->getCurrentLength());
   return true;
 }

+ 6 - 25
src/CheckIntegrityCommand.h

@@ -36,41 +36,22 @@
 #define _D_CHECK_INTEGRITY_COMMAND_H_
 
 #include "RealtimeCommand.h"
-#include "Request.h"
 #include "IteratableChunkChecksumValidator.h"
-#include "DownloadCommand.h"
+#include "CheckIntegrityEntry.h"
+#include "TimeA2.h"
 
 class CheckIntegrityCommand : public RealtimeCommand {
 private:
-  RequestHandle _req;
-  IteratableChunkChecksumValidatorHandle _validator;
-  DownloadCommand* _nextDownloadCommand;
+  CheckIntegrityEntryHandle _entry;
+  Time _timer;
 public:
-  CheckIntegrityCommand(int cuid, const RequestHandle& req, RequestGroup* requestGroup, DownloadEngine* e):
-    RealtimeCommand(cuid, requestGroup, e),
-    _req(req),
-    _validator(0),
-    _nextDownloadCommand(0)
-  {
-    ++_requestGroup->numConnection;
-  }
+  CheckIntegrityCommand(int cuid, RequestGroup* requestGroup, DownloadEngine* e, const CheckIntegrityEntryHandle& entry);
 
-  virtual ~CheckIntegrityCommand()
-  {
-    --_requestGroup->numConnection;
-    delete _nextDownloadCommand;
-  }
-
-  void initValidator();
+  virtual ~CheckIntegrityCommand();
 
   virtual bool executeInternal();
 
   virtual bool handleException(Exception* e);
-
-  void setNextDownloadCommand(DownloadCommand* command)
-  {
-    _nextDownloadCommand = command;
-  }
 };
 
 #endif // _D_CHECK_INTEGRITY_COMMAND_H_

+ 66 - 0
src/CheckIntegrityEntry.cc

@@ -0,0 +1,66 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "CheckIntegrityEntry.h"
+#include "DlAbortEx.h"
+
+void CheckIntegrityEntry::validateChunk()
+{
+  _validator->validateChunk();
+}
+
+bool CheckIntegrityEntry::finished() const
+{
+  return _validator->finished();
+}
+
+int64_t CheckIntegrityEntry::getCurrentLength() const
+{
+  return _validator->getCurrentOffset();
+}
+
+void CheckIntegrityEntry::initValidator()
+{
+  IteratableChunkChecksumValidatorHandle validator =
+    new IteratableChunkChecksumValidator();
+  validator->setChunkChecksum(_requestGroup->getChunkChecksum());
+  validator->setDiskWriter(_requestGroup->getSegmentMan()->diskWriter);
+  validator->setBitfield(_requestGroup->getSegmentMan()->getBitfield());
+  if(!validator->canValidate()) {
+    // insufficient checksums.
+    throw new DlAbortEx("Insufficient checksums.");
+  }
+  validator->init();
+  _validator = validator;
+}

+ 65 - 0
src/CheckIntegrityEntry.h

@@ -0,0 +1,65 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_CHECK_INTEGRITY_ENTRY_H_
+#define _D_CHECK_INTEGRITY_ENTRY_H_
+
+#include "RequestGroupEntry.h"
+#include "IteratableChunkChecksumValidator.h"
+
+class CheckIntegrityEntry : public RequestGroupEntry {
+private:
+  IteratableChunkChecksumValidatorHandle _validator;
+public:
+  CheckIntegrityEntry(int cuid,
+		      const RequestHandle& currentRequest,
+		      RequestGroup* requestGroup):
+    RequestGroupEntry(cuid, currentRequest, requestGroup),
+    _validator(0)
+  {}
+
+  virtual ~CheckIntegrityEntry() {}
+
+  virtual int64_t getCurrentLength() const;
+
+  virtual bool finished() const;
+
+  void initValidator();
+
+  void validateChunk();
+};
+
+typedef SharedHandle<CheckIntegrityEntry> CheckIntegrityEntryHandle;
+typedef deque<CheckIntegrityEntryHandle> CheckIntegrityEntries;
+#endif // _D_CHECK_INTEGRITY_ENTRY_H_

+ 80 - 0
src/CheckIntegrityMan.h

@@ -0,0 +1,80 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_CHECK_INTEGRITY_MAN_H_
+#define _D_CHECK_INTEGRITY_MAN_H_
+
+#include "common.h"
+#include "CheckIntegrityEntry.h"
+
+class CheckIntegrityMan {
+private:
+  CheckIntegrityEntries _checkIntegrityEntries;
+public:
+  void addCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry)
+  {
+    _checkIntegrityEntries.push_back(entry);
+  }
+
+  bool removeCheckIntegrityEntry(const CheckIntegrityEntryHandle& entry)
+  {
+    CheckIntegrityEntries::iterator itr = find(_checkIntegrityEntries.begin(),
+					       _checkIntegrityEntries.end(),
+					       entry);
+    if(itr == _checkIntegrityEntries.end()) {
+      return false;
+    } else {
+      _checkIntegrityEntries.erase(itr);
+      return true;
+    }
+  }
+
+  CheckIntegrityEntryHandle getFirstCheckIntegrityEntry() const
+  {
+    if(_checkIntegrityEntries.empty()) {
+      return 0;
+    } else {
+      return _checkIntegrityEntries.front();
+    }
+  }
+
+  int32_t countCheckIntegrityEntry() const
+  {
+    return _checkIntegrityEntries.size();
+  }
+};
+
+typedef SharedHandle<CheckIntegrityMan> CheckIntegrityManHandle;
+
+#endif // _D_CHECK_INTEGRITY_MAN_H_

+ 37 - 12
src/ConsoleDownloadEngine.cc

@@ -61,9 +61,9 @@ void ConsoleDownloadEngine::sendStatistics(long long int currentSize, long long
   if(_requestGroupMan->countRequestGroup() > 0) {
     RequestGroupHandle firstRequestGroup = _requestGroupMan->getRequestGroup(0);
     cout << "[";
-    cout << Util::llitos(firstRequestGroup->getDownloadLength(), true)
+    cout << Util::abbrevSize(firstRequestGroup->getDownloadLength())
 	 << "/"
-	 << Util::llitos(firstRequestGroup->getTotalLength(), true);
+	 << Util::abbrevSize(firstRequestGroup->getTotalLength());
     if(firstRequestGroup->getTotalLength() > 0) {
       cout << "("
 	   << 100*firstRequestGroup->getDownloadLength()/firstRequestGroup->getTotalLength()
@@ -81,16 +81,41 @@ void ConsoleDownloadEngine::sendStatistics(long long int currentSize, long long
   }
   cout << "[" << speed/1024.0 << "KB/s" << "]";
 
-  FileAllocationEntryHandle entry = _fileAllocationMan->getCurrentFileAllocationEntry();
-  if(!entry.isNull()) {
-    cout << "[FileAlloc:"
-	 << entry->getOffset()
-	 << "/"
-	 << entry->getRequestGroup()->getTotalLength()
-	 << "("
-	 << entry->getOffset()/(entry->getRequestGroup()->getTotalLength()/100)
-	 << "%)"
-	 << "]";
+  {
+    FileAllocationEntryHandle entry = _fileAllocationMan->getCurrentFileAllocationEntry();
+    if(!entry.isNull()) {
+      cout << "[FileAlloc:"
+	   << Util::abbrevSize(entry->getCurrentLength())
+	   << "/"
+	   << Util::abbrevSize(entry->getTotalLength())
+	   << "("
+	   << 100*entry->getCurrentLength()/entry->getTotalLength()
+	   << "%)";
+      if(_fileAllocationMan->countFileAllocationEntryInQueue() > 0) {
+	cout << "("
+	     << _fileAllocationMan->countFileAllocationEntryInQueue()
+	     << "waiting...)";
+      }
+      cout << "]";
+    }
+  }
+  {
+    CheckIntegrityEntryHandle entry = _checkIntegrityMan->getFirstCheckIntegrityEntry();
+    if(!entry.isNull()) {
+      cout << "[Checksum:"
+	   << Util::abbrevSize(entry->getCurrentLength())
+	   << "/"
+	   << Util::abbrevSize(entry->getTotalLength())
+	   << "("
+	   << 100*entry->getCurrentLength()/entry->getTotalLength()
+	   << "%)";
+      if(_checkIntegrityMan->countCheckIntegrityEntry() > 1) {
+	cout << "("
+	     << _checkIntegrityMan->countCheckIntegrityEntry()-1
+	     << "more...)";
+      }
+      cout << "]";
+    }
   }
   cout << flush;
 }

+ 2 - 1
src/DownloadEngine.cc

@@ -48,7 +48,8 @@ using namespace std;
 DownloadEngine::DownloadEngine():logger(LogFactory::getInstance()),
 				 noWait(false),
 				 _requestGroupMan(0),
-				 _fileAllocationMan(0) {}
+				 _fileAllocationMan(0),
+				 _checkIntegrityMan(0) {}
 
 DownloadEngine::~DownloadEngine() {
   cleanQueue();

+ 2 - 0
src/DownloadEngine.h

@@ -44,6 +44,7 @@
 #include "NameResolver.h"
 #include "RequestGroupMan.h"
 #include "FileAllocationMan.h"
+#include "CheckIntegrityMan.h"
 
 typedef deque<SocketHandle> Sockets;
 
@@ -120,6 +121,7 @@ public:
   Commands commands;
   RequestGroupManHandle _requestGroupMan;
   FileAllocationManHandle _fileAllocationMan;
+  CheckIntegrityManHandle _checkIntegrityMan;
   const Option* option;
   
   DownloadEngine();

+ 2 - 0
src/DownloadEngineFactory.cc

@@ -43,6 +43,7 @@
 #include "CUIDCounter.h"
 #include "FileAllocationDispatcherCommand.h"
 #include "FileAllocationMan.h"
+#include "CheckIntegrityMan.h"
 #ifdef ENABLE_BITTORRENT
 # include "PeerListenCommand.h"
 # include "TrackerWatcherCommand.h"
@@ -86,6 +87,7 @@ DownloadEngineFactory::newConsoleEngine(const Option* op,
   requestGroupMan->addReservedGroup(reservedSet);
   e->_requestGroupMan = requestGroupMan;
   e->_fileAllocationMan = new FileAllocationMan();
+  e->_checkIntegrityMan = new CheckIntegrityMan();
 
   e->commands.push_back(new FillRequestGroupCommand(CUIDCounterSingletonHolder::instance()->newID(), e, 1));
   e->commands.push_back(new FileAllocationDispatcherCommand(CUIDCounterSingletonHolder::instance()->newID(), e));

+ 7 - 7
src/FileAllocationCommand.cc

@@ -36,24 +36,24 @@
 #include "InitiateConnectionCommandFactory.h"
 #include "message.h"
 #include "DownloadCommand.h"
+#include "prefs.h"
 
 bool FileAllocationCommand::executeInternal()
 {
   _fileAllocationEntry->allocateChunk();
   
-  if(_fileAllocationEntry->allocationFinished()) {
-    int64_t totalLength = _requestGroup->getSegmentMan()->totalSize;
+  if(_fileAllocationEntry->finished()) {
     logger->debug("%d seconds to allocate %lld byte(s)",
-		  _timer.difference(), totalLength);
+		  _timer.difference(), _requestGroup->getTotalLength());
     
     _e->_fileAllocationMan->markCurrentFileAllocationEntryDone();
     
-    if(_fileAllocationEntry->getNextDownloadCommand()) {
-      _e->commands.push_back(_fileAllocationEntry->getNextDownloadCommand());
-      _fileAllocationEntry->setNextDownloadCommand(0);
+    if(_timer.difference() <= _e->option->getAsInt(PREF_DIRECT_DOWNLOAD_TIMEOUT) &&
+       _fileAllocationEntry->getNextDownloadCommand()) {
+      _e->commands.push_back(_fileAllocationEntry->popNextDownloadCommand());
     } else {
       Commands commands = _requestGroup->createNextCommand(_e);
-      Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, _req, _requestGroup, _e);
+      Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, _fileAllocationEntry->getCurrentRequest(), _requestGroup, _e);
       
       commands.push_front(command);
     

+ 1 - 4
src/FileAllocationCommand.h

@@ -36,19 +36,16 @@
 #define _D_FILE_ALLOCATION_COMMAND_H_
 
 #include "RealtimeCommand.h"
-#include "Request.h"
 #include "TimeA2.h"
 #include "FileAllocationEntry.h"
 
 class FileAllocationCommand : public RealtimeCommand {
 private:
-  RequestHandle _req;
   FileAllocationEntryHandle _fileAllocationEntry;
   Time _timer;
 public:
-  FileAllocationCommand(int cuid, const RequestHandle& req, RequestGroup* requestGroup, DownloadEngine* e, const FileAllocationEntryHandle& fileAllocationEntry):
+  FileAllocationCommand(int cuid, RequestGroup* requestGroup, DownloadEngine* e, const FileAllocationEntryHandle& fileAllocationEntry):
     RealtimeCommand(cuid, requestGroup, e),
-    _req(req),
     _fileAllocationEntry(fileAllocationEntry) {}
 
   virtual bool executeInternal();

+ 1 - 2
src/FileAllocationDispatcherCommand.cc

@@ -48,10 +48,9 @@ bool FileAllocationDispatcherCommand::execute()
 		 entry->getCUID());
     FileAllocationCommand* command =
       new FileAllocationCommand(entry->getCUID(),
-				entry->getCurrentRequest(),
 				entry->getRequestGroup(),
 				_e,
-				_e->_fileAllocationMan->getCurrentFileAllocationEntry());
+				entry);
     _e->commands.push_back(command);
     _e->noWait = true;
   }

+ 0 - 7
src/FileAllocationEntry.cc

@@ -33,16 +33,9 @@
  */
 /* copyright --> */
 #include "FileAllocationEntry.h"
-#include "DownloadCommand.h"
 
 #define BUFSIZE 16*1024
 
-FileAllocationEntry::~FileAllocationEntry()
-{
-  --_requestGroup->numConnection;
-  delete _nextDownloadCommand;
-}
-
 void FileAllocationEntry::allocateChunk()
 {
   int32_t bufSize = BUFSIZE;

+ 10 - 53
src/FileAllocationEntry.h

@@ -35,76 +35,33 @@
 #ifndef _D_FILE_ALLOCATION_ENTRY_H_
 #define _D_FILE_ALLOCATION_ENTRY_H_
 
-#include "common.h"
-#include "Request.h"
-#include "RequestGroup.h"
+#include "RequestGroupEntry.h"
 
-class DownloadCommand;
-
-class FileAllocationEntry {
+class FileAllocationEntry : public RequestGroupEntry {
 private:
-  int _cuid;
-  RequestHandle _currentRequest;
-  RequestGroup* _requestGroup;
   int64_t _offset;
-  DownloadCommand* _nextDownloadCommand;
 public:
   FileAllocationEntry(int cuid,
 		      const RequestHandle& currentRequest,
 		      RequestGroup* requestGroup,
 		      int64_t offset = 0):
-    _cuid(cuid),
-    _currentRequest(currentRequest),
-    _requestGroup(requestGroup),
-    _offset(offset),
-    _nextDownloadCommand(0)
-  {
-    ++_requestGroup->numConnection;
-  }
-
-  ~FileAllocationEntry();
-
-  int getCUID() const
-  {
-    return _cuid;
-  }
-
-  RequestHandle getCurrentRequest() const
-  {
-    return _currentRequest;
-  }
+    RequestGroupEntry(cuid, currentRequest, requestGroup),
+    _offset(offset)
+  {}
 
-  RequestGroup* getRequestGroup() const
-  {
-    return _requestGroup;
-  }
+  virtual ~FileAllocationEntry() {}
 
-  void setOffset(int64_t offset)
-  {
-    _offset = offset;
-  }
-
-  int64_t getOffset() const
+  virtual int64_t getCurrentLength() const
   {
     return _offset;
   }
 
-  void allocateChunk();
-
-  bool allocationFinished() const
+  virtual bool finished() const
   {
-    return _requestGroup->getSegmentMan()->totalSize <= _offset;
+    return _requestGroup->getTotalLength() <= _offset;
   }
 
-  void setNextDownloadCommand(DownloadCommand* command)
-  {
-    _nextDownloadCommand = command;
-  }
-
-  DownloadCommand* getNextDownloadCommand() const
-  {
-    return _nextDownloadCommand;
-  }
+  void allocateChunk();
 };
 
 typedef SharedHandle<FileAllocationEntry> FileAllocationEntryHandle;

+ 5 - 0
src/FileAllocationMan.h

@@ -82,6 +82,11 @@ public:
   {
     _fileAllocationEntries.push_back(entry);
   }
+
+  int32_t countFileAllocationEntryInQueue() const
+  {
+    return _fileAllocationEntries.size();
+  }
 };
 
 typedef SharedHandle<FileAllocationMan> FileAllocationManHandle;

+ 5 - 0
src/IteratableChunkChecksumValidator.h

@@ -84,6 +84,11 @@ public:
   {
     return ((int64_t)_currentIndex)*_chunkChecksum->getChecksumLength();
   }
+
+  int64_t getTotalLength() const
+  {
+    return _bitfield->getTotalLength();
+  }
 };
 
 typedef SharedHandle<IteratableChunkChecksumValidator> IteratableChunkChecksumValidatorHandle;

+ 5 - 1
src/Makefile.am

@@ -98,7 +98,11 @@ SRCS =  Socket.h\
 	DefaultSegmentManFactory.cc DefaultSegmentManFactory.h\
 	RealtimeCommand.cc RealtimeCommand.h\
 	IteratableChecksumValidator.cc IteratableChecksumValidator.h\
-	ChecksumCommand.cc ChecksumCommand.h
+	ChecksumCommand.cc ChecksumCommand.h\
+	CheckIntegrityEntry.cc CheckIntegrityEntry.h\
+	CheckIntegrityMan.h\
+	ProgressAwareEntry.h\
+	RequestGroupEntry.cc RequestGroupEntry.h
 #	debug_new.cpp
 
 if ENABLE_BITTORRENT

+ 10 - 3
src/Makefile.in

@@ -239,7 +239,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	DefaultSegmentManFactory.cc DefaultSegmentManFactory.h \
 	RealtimeCommand.cc RealtimeCommand.h \
 	IteratableChecksumValidator.cc IteratableChecksumValidator.h \
-	ChecksumCommand.cc ChecksumCommand.h MetaEntry.h Data.cc \
+	ChecksumCommand.cc ChecksumCommand.h CheckIntegrityEntry.cc \
+	CheckIntegrityEntry.h CheckIntegrityMan.h ProgressAwareEntry.h \
+	RequestGroupEntry.cc RequestGroupEntry.h MetaEntry.h Data.cc \
 	Data.h Dictionary.cc Dictionary.h List.cc List.h \
 	MetaFileUtil.cc MetaFileUtil.h MetaEntryVisitor.h \
 	ShaVisitor.cc ShaVisitor.h PeerConnection.cc PeerConnection.h \
@@ -424,7 +426,8 @@ am__objects_3 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
 	MultiUrlRequestInfo.$(OBJEXT) UriFileListParser.$(OBJEXT) \
 	DefaultSegmentManFactory.$(OBJEXT) RealtimeCommand.$(OBJEXT) \
 	IteratableChecksumValidator.$(OBJEXT) \
-	ChecksumCommand.$(OBJEXT) $(am__objects_1) $(am__objects_2)
+	ChecksumCommand.$(OBJEXT) CheckIntegrityEntry.$(OBJEXT) \
+	RequestGroupEntry.$(OBJEXT) $(am__objects_1) $(am__objects_2)
 am_libaria2c_a_OBJECTS = $(am__objects_3)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(bindir)"
@@ -655,7 +658,9 @@ SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \
 	DefaultSegmentManFactory.cc DefaultSegmentManFactory.h \
 	RealtimeCommand.cc RealtimeCommand.h \
 	IteratableChecksumValidator.cc IteratableChecksumValidator.h \
-	ChecksumCommand.cc ChecksumCommand.h $(am__append_1) \
+	ChecksumCommand.cc ChecksumCommand.h CheckIntegrityEntry.cc \
+	CheckIntegrityEntry.h CheckIntegrityMan.h ProgressAwareEntry.h \
+	RequestGroupEntry.cc RequestGroupEntry.h $(am__append_1) \
 	$(am__append_2)
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
@@ -776,6 +781,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtUnchokeMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ByteArrayDiskWriter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CheckIntegrityCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CheckIntegrityEntry.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChecksumCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkChecksumValidator.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedEncoding.Po@am__quote@
@@ -866,6 +872,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Request.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestFactory.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupEntry.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestGroupMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestSlot.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SeedCheckCommand.Po@am__quote@

+ 53 - 0
src/ProgressAwareEntry.h

@@ -0,0 +1,53 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_PROGRESS_AWARE_ENTRY_H_
+#define _D_PROGRESS_AWARE_ENTRY_H_
+
+#include "common.h"
+
+class ProgressAwareEntry {
+public:
+  virtual ~ProgressAwareEntry() {}
+
+  virtual int64_t getCurrentLength() const = 0;
+
+  virtual int64_t getTotalLength() const = 0;
+
+  virtual bool finished() const = 0;
+};
+
+typedef SharedHandle<ProgressAwareEntry> ProgressAwareEntryHandle;
+
+#endif // _D_PROGRESS_AWARE_ENTRY_H_

+ 16 - 7
src/RequestGroup.cc

@@ -46,10 +46,13 @@
 #include "Util.h"
 #include "CheckIntegrityCommand.h"
 #include "FatalException.h"
+#include "CheckIntegrityEntry.h"
+#include "DownloadCommand.h"
 
 SegmentManHandle RequestGroup::initSegmentMan()
 {
   _segmentMan = _segmentManFactory->createNewInstance();
+  _segmentMan->ufilename = _ufilename;
   return _segmentMan;
 }
 
@@ -193,9 +196,13 @@ void RequestGroup::prepareForNextAction(int cuid, const RequestHandle& req, Down
 {
   File existingFile(getFilePath());
   if(existingFile.size() > 0 && _option->get(PREF_CHECK_INTEGRITY) == V_TRUE) {
-    CheckIntegrityCommand* command = new CheckIntegrityCommand(cuid, req, this, e);
-    command->setNextDownloadCommand(downloadCommand);
-    command->initValidator();
+    // purge SegmentEntries
+    _segmentMan->purgeSegmentEntry();
+
+    CheckIntegrityEntryHandle entry = new CheckIntegrityEntry(cuid, req, this);
+    entry->setNextDownloadCommand(downloadCommand);
+    entry->initValidator();
+    CheckIntegrityCommand* command = new CheckIntegrityCommand(cuid, this, e, entry);
     e->commands.push_back(command);
   } else if(needsFileAllocation()) {
     FileAllocationEntryHandle entry = new FileAllocationEntry(cuid, req, this);
@@ -261,8 +268,10 @@ void RequestGroup::validateTotalLengthByHint(int64_t actualTotalLength) const
 
 void RequestGroup::setUserDefinedFilename(const string& filename)
 {
-  if(_segmentMan.isNull()) {
-    throw new FatalException("SegmentMan is not initialized yet. Call initSegmentMan() before calling this function.");
-  }
-  _segmentMan->ufilename = filename;
+  _ufilename = filename;
+}
+
+int64_t RequestGroup::getExistingFileLength() const
+{
+  return File(getFilePath()).size();
 }

+ 3 - 0
src/RequestGroup.h

@@ -52,6 +52,7 @@ class RequestGroup {
 private:
   int64_t _hintTotalLength;
   string _hintFilename;
+  string _ufilename;
   Strings _uris;
   Strings _spentUris;
   SegmentManHandle _segmentMan;
@@ -182,6 +183,8 @@ public:
 
   string getFilePath() const;
 
+  int64_t getExistingFileLength() const;
+
   int64_t getTotalLength() const
   {
     return _segmentMan->totalSize;

+ 42 - 0
src/RequestGroupEntry.cc

@@ -0,0 +1,42 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "RequestGroupEntry.h"
+#include "DownloadCommand.h"
+
+RequestGroupEntry::~RequestGroupEntry()
+{
+  --_requestGroup->numConnection;
+  delete _nextDownloadCommand;
+}

+ 108 - 0
src/RequestGroupEntry.h

@@ -0,0 +1,108 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_REQUEST_GROUP_ENTRY_H_
+#define _D_REQUEST_GROUP_ENTRY_H_
+
+#include "ProgressAwareEntry.h"
+#include "Request.h"
+#include "RequestGroup.h"
+
+class DownloadCommand;
+
+class RequestGroupEntry : public ProgressAwareEntry {
+protected:
+  int _cuid;
+  RequestHandle _currentRequest;
+  RequestGroup* _requestGroup;
+  DownloadCommand* _nextDownloadCommand;
+public:
+  RequestGroupEntry(int cuid,
+		    const RequestHandle& currentRequest,
+		    RequestGroup* requestGroup):
+    _cuid(cuid),
+    _currentRequest(currentRequest),
+    _requestGroup(requestGroup),
+    _nextDownloadCommand(0)
+  {
+    ++_requestGroup->numConnection;
+  }
+
+  virtual ~RequestGroupEntry();
+
+  virtual int64_t getTotalLength() const
+  {
+    return _requestGroup->getTotalLength();
+  }
+
+  int getCUID() const
+  {
+    return _cuid;
+  }
+
+  RequestHandle getCurrentRequest() const
+  {
+    return _currentRequest;
+  }
+
+  RequestGroup* getRequestGroup() const
+  {
+    return _requestGroup;
+  }
+
+  void setNextDownloadCommand(DownloadCommand* command)
+  {
+    _nextDownloadCommand = command;
+  }
+
+  DownloadCommand* getNextDownloadCommand() const
+  {
+    return _nextDownloadCommand;
+  }
+
+  DownloadCommand* popNextDownloadCommand()
+  {
+    DownloadCommand* temp = _nextDownloadCommand;
+    _nextDownloadCommand = 0;
+    return temp;
+  }
+  
+  bool operator==(const RequestGroupEntry& entry) const
+  {
+    return this == &entry;
+  }
+};
+
+typedef SharedHandle<RequestGroupEntry> RequestGroupEntryHandle;
+#endif // _D_REQUEST_GROUP_ENTRY_H_

+ 8 - 0
src/SegmentMan.h

@@ -291,6 +291,14 @@ public:
 
   void markPieceDone(int64_t length);
 
+  /**
+   * This function must be called when none of segment entries is used.
+   */
+  void purgeSegmentEntry()
+  {
+    usedSegmentEntries.clear();
+  }
+
 #ifdef ENABLE_MESSAGE_DIGEST
   void checkIntegrity();
 

+ 15 - 0
src/Util.cc

@@ -691,3 +691,18 @@ int64_t Util::getRealSize(const string& sizeWithUnit)
   }
   return strtoll(size.c_str(), 0, 10)*mult;
 }
+
+string Util::abbrevSize(int64_t size)
+{
+  if(size < 1024) {
+    return Util::llitos(size, true);
+  }
+  size >>= 10;
+  char units[] = { 'K', 'M' };
+  int32_t numUnit = sizeof(units)/sizeof(char);
+  int32_t i = 0;
+  for(; i < numUnit-1 && size >= 1024; ++i) {
+    size >>= 10;
+  } 
+  return Util::llitos(size, true)+units[i];
+}

+ 2 - 0
src/Util.h

@@ -148,6 +148,8 @@ public:
   static string getHomeDir();
 
   static int64_t getRealSize(const string& sizeWithUnit);
+
+  static string abbrevSize(int64_t size);
 };
 
 #endif // _D_UTIL_H_

+ 1 - 0
src/main.cc

@@ -361,6 +361,7 @@ int main(int argc, char* argv[]) {
   op->put(PREF_USER_AGENT, "aria2");
   op->put(PREF_NO_NETRC, V_FALSE);
   op->put(PREF_MAX_SIMULTANEOUS_DOWNLOADS, "5");
+  op->put(PREF_DIRECT_DOWNLOAD_TIMEOUT, "15");
   while(1) {
     int optIndex = 0;
     int lopt;

+ 2 - 0
src/prefs.h

@@ -102,6 +102,8 @@
 #define PREF_INPUT_FILE "input-file"
 // value: 1*digit
 #define PREF_MAX_SIMULTANEOUS_DOWNLOADS "max-simultaneous-downloads"
+// value: 1*digit
+#define PREF_DIRECT_DOWNLOAD_TIMEOUT "direct-download-timeout"
 
 /**
  * FTP related preferences

+ 10 - 0
test/UtilTest.cc

@@ -23,6 +23,7 @@ class UtilTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testUrldecode);
   CPPUNIT_TEST(testCountBit);
   CPPUNIT_TEST(testGetRealSize);
+  CPPUNIT_TEST(testAbbrevSize);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -46,6 +47,7 @@ public:
   void testUrldecode();
   void testCountBit();
   void testGetRealSize();
+  void testAbbrevSize();
 };
 
 
@@ -299,3 +301,11 @@ void UtilTest::testGetRealSize()
   CPPUNIT_ASSERT_EQUAL((int64_t)0, Util::getRealSize(""));
   CPPUNIT_ASSERT_EQUAL((int64_t)0, Util::getRealSize("foo"));
 }
+
+void UtilTest::testAbbrevSize()
+{
+  CPPUNIT_ASSERT_EQUAL(string("4,096M"), Util::abbrevSize(4294967296LL));
+  CPPUNIT_ASSERT_EQUAL(string("1K"), Util::abbrevSize(1024));
+  CPPUNIT_ASSERT_EQUAL(string("1,023"), Util::abbrevSize(1023));
+  CPPUNIT_ASSERT_EQUAL(string("0"), Util::abbrevSize(0));
+}