diff --git a/panda/src/downloader/config_downloader.cxx b/panda/src/downloader/config_downloader.cxx index 5ef3a602c2..d06d010973 100644 --- a/panda/src/downloader/config_downloader.cxx +++ b/panda/src/downloader/config_downloader.cxx @@ -11,21 +11,22 @@ Configure(config_downloader); NotifyCategoryDef(downloader, ""); +// How often we write to disk is determined by this ratio which is +// relative to the downloader-byte-rate (e.g. if disk-write-ratio is 4, +// we will write every 4 seconds if the frequency is 0.2) +const int downloader_disk_write_frequency = + config_downloader.GetInt("downloader-disk-write-frequency", 4); + // We'd like this to be about 1 second worth of download assuming a // 28.8Kb connection (28.8Kb / 8 = 3600 bytes per second). -const int downloader_buffer_size = - config_downloader.GetInt("downloader-buffer-size", 3600); +const int downloader_byte_rate = + config_downloader.GetInt("downloader-byte-rate", 3600); // Frequency of download chunk requests in seconds (or fractions of) // (Estimated 200 msec round-trip to server). const float downloader_frequency = config_downloader.GetFloat("downloader-frequency", 0.2); -// Estimated available bandwidth (assume a 28.8Kb connection, so again -// we have 3600 bytes per second). -const float downloader_bandwidth = - config_downloader.GetFloat("downloader-bandwidth", 3600.0); - const int downloader_timeout = config_downloader.GetInt("downloader-timeout", 15); diff --git a/panda/src/downloader/config_downloader.h b/panda/src/downloader/config_downloader.h index 89849daebd..e4b2d51258 100644 --- a/panda/src/downloader/config_downloader.h +++ b/panda/src/downloader/config_downloader.h @@ -11,9 +11,9 @@ NotifyCategoryDecl(downloader, EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS); -extern const int downloader_buffer_size; +extern const int downloader_disk_write_frequency; +extern const int downloader_byte_rate; extern const float downloader_frequency; -extern const float downloader_bandwidth; extern const int downloader_timeout; extern const int downloader_timeout_retries; diff --git a/panda/src/downloader/downloader.I b/panda/src/downloader/downloader.I index 3d2daeee10..a78940a595 100644 --- a/panda/src/downloader/downloader.I +++ b/panda/src/downloader/downloader.I @@ -6,27 +6,27 @@ #include "config_downloader.h" //////////////////////////////////////////////////////////////////// -// Function: Downloader::set_bandwidth +// Function: Downloader::set_byte_rate // Access: Public // Description: Note: modem speeds are reported in bits, so you // need to convert! //////////////////////////////////////////////////////////////////// INLINE void Downloader:: -set_bandwidth(float bytes) { +set_byte_rate(float bytes) { #ifdef HAVE_IPC mutex_lock lock(_bandwidth_frequency_lock); #endif - _bandwidth = bytes; + _byte_rate = bytes; } //////////////////////////////////////////////////////////////////// -// Function: Downloader::get_bandwidth +// Function: Downloader::get_byte_rate // Access: Public -// Description: Returns bandwidth in bytes. +// Description: Returns byte rate in bytes. //////////////////////////////////////////////////////////////////// INLINE float Downloader:: -get_bandwidth(void) const { - return _bandwidth; +get_byte_rate(void) const { + return _byte_rate; } //////////////////////////////////////////////////////////////////// @@ -50,14 +50,17 @@ is_download_enabled(void) const { } //////////////////////////////////////////////////////////////////// -// Function: Downloader::change_buffer_size +// Function: Downloader::set_disk_write_frequency // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE bool Downloader:: -change_buffer_size(int size) { +set_disk_write_frequency(int frequency) { + nassertr(frequency > 0, false); + _disk_write_frequency = frequency; + int size = _disk_write_frequency * (_byte_rate * _frequency); if (size == _buffer_size) - return true; + return false; nassertr(size > 0, false); #ifdef HAVE_IPC _buffer_lock.lock(); @@ -68,3 +71,23 @@ change_buffer_size(int size) { #endif return true; } + +//////////////////////////////////////////////////////////////////// +// Function: Downloader::get_disk_write_frequency +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE int Downloader:: +get_disk_write_frequency(void) const { + return _disk_write_frequency; +} + +//////////////////////////////////////////////////////////////////// +// Function: Downloader::get_last_attempt_stalled +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE bool Downloader:: +get_last_attempt_stalled(void) const { + return _last_attempt_stalled; +} diff --git a/panda/src/downloader/downloader.cxx b/panda/src/downloader/downloader.cxx index d08bc3d69e..01bd402463 100644 --- a/panda/src/downloader/downloader.cxx +++ b/panda/src/downloader/downloader.cxx @@ -57,12 +57,13 @@ public: INLINE DownloaderToken(uint id, const string &file_name, const Filename &file_dest, const string &event_name, int first_byte, int last_byte, int total_bytes, - bool partial_content) : _id(id), _first_byte(first_byte), + bool partial_content, bool sync) : _id(id), _first_byte(first_byte), _last_byte(last_byte), _total_bytes(total_bytes) { _file_name = file_name; _event_name = event_name; _file_dest = file_dest; _partial_content = partial_content; + _sync = sync; } uint _id; string _file_name; @@ -72,6 +73,7 @@ public: int _last_byte; int _total_bytes; bool _partial_content; + bool _sync; }; //////////////////////////////////////////////////////////////////// @@ -81,10 +83,10 @@ public: //////////////////////////////////////////////////////////////////// Downloader:: Downloader(void) : AsyncUtility() { - PT(Buffer) buffer = new Buffer(downloader_buffer_size); - init(buffer); + init(); } +#if 0 //////////////////////////////////////////////////////////////////// // Function: Downloader::Constructor // Access: Public @@ -94,6 +96,7 @@ Downloader:: Downloader(PT(Buffer) buffer) : AsyncUtility() { init(buffer); } +#endif //////////////////////////////////////////////////////////////////// // Function: Downloader::init @@ -101,18 +104,23 @@ Downloader(PT(Buffer) buffer) : AsyncUtility() { // Description: //////////////////////////////////////////////////////////////////// void Downloader:: -init(PT(Buffer) buffer) { - nassertv(!buffer.is_null()); +init(void) { + _disk_write_frequency = downloader_disk_write_frequency; + _byte_rate = downloader_byte_rate; _frequency = downloader_frequency; - _bandwidth = downloader_bandwidth; + nassertv(_frequency > 0); + if (_frequency == 0) + _buffer_size = _disk_write_frequency * _byte_rate; + else + _buffer_size = _disk_write_frequency * (_byte_rate * _frequency); + _buffer = new Buffer(_buffer_size); + _new_buffer_size = 0; _connected = false; _token_board = new DownloaderTokenBoard; - _buffer = buffer; _download_enabled = true; + _last_attempt_stalled = true; // We need to flush after every write in case we're interrupted _dest_stream.setf(ios::unitbuf, 0); - _buffer_size = _buffer->get_length(); - _new_buffer_size = 0; #if defined(WIN32) WSAData mydata; @@ -227,6 +235,30 @@ disconnect_from_server(void) { _connected = false; } +//////////////////////////////////////////////////////////////////// +// Function: Downloader::request_sync_download +// Access: Public +// Description: Requests the synchronous download of a complete file. +//////////////////////////////////////////////////////////////////// +int Downloader:: +request_sync_download(const string &file_name, const Filename &file_dest, + const string &event_name) { + return request_download(file_name, file_dest, event_name, true); +} + +//////////////////////////////////////////////////////////////////// +// Function: Downloader::request_sync_download +// Access: Public +// Description: Requests the synchronous download of a complete file. +//////////////////////////////////////////////////////////////////// +int Downloader:: +request_sync_download(const string &file_name, const Filename &file_dest, + const string &event_name, int first_byte, + int last_byte, int total_bytes, bool partial_content) { + return request_download(file_name, file_dest, event_name, first_byte, + last_byte, total_bytes, partial_content, true); +} + //////////////////////////////////////////////////////////////////// // Function: Downloader::request_download // Access: Public @@ -234,9 +266,9 @@ disconnect_from_server(void) { //////////////////////////////////////////////////////////////////// int Downloader:: request_download(const string &file_name, const Filename &file_dest, - const string &event_name) { + const string &event_name, bool sync) { return request_download(file_name, file_dest, event_name, 0, 0, 0, - false); + false, sync); } //////////////////////////////////////////////////////////////////// @@ -258,7 +290,7 @@ int Downloader:: request_download(const string &file_name, const Filename &file_dest, const string &event_name, int first_byte, int last_byte, int total_bytes, - bool partial_content) { + bool partial_content, bool sync) { nassertr(first_byte <= last_byte && last_byte <= total_bytes, 0); @@ -291,7 +323,7 @@ request_download(const string &file_name, const Filename &file_dest, tok = new DownloaderToken(_next_token++, file_name, file_dest, event_name, first_byte, last_byte, total_bytes, - partial_content); + partial_content, sync); _token_board->_waiting.insert(tok); #ifdef HAVE_IPC @@ -314,7 +346,7 @@ request_download(const string &file_name, const Filename &file_dest, tok = new DownloaderToken(_next_token++, file_name, file_dest, event_name, first_byte, last_byte, total_bytes, - partial_content); + partial_content, sync); _token_board->_waiting.insert(tok); process_request(); } @@ -342,7 +374,7 @@ process_request() { PT(DownloaderToken) tok = _token_board->_waiting.extract(); int ret = download(tok->_file_name, tok->_file_dest, tok->_event_name, tok->_first_byte, tok->_last_byte, tok->_total_bytes, - tok->_partial_content, tok->_id); + tok->_partial_content, tok->_sync, tok->_id); if (ret == D_success) { _token_board->_done.insert(tok); @@ -420,8 +452,9 @@ safe_send(int socket, const char *data, int length, long timeout) { //////////////////////////////////////////////////////////////////// int Downloader:: safe_receive(int socket, DownloadStatus &status, int length, - long timeout, int &bytes) { + long timeout, int &bytes, bool &stalled) { bytes = 0; + stalled = true; if (length == 0) { downloader_cat.error() << "Downloader::safe_receive() - requested 0 length receive!" << endl; @@ -454,6 +487,8 @@ safe_receive(int socket, DownloadStatus &status, int length, bytes += ret; status._next_in += ret; status._bytes_in_buffer += ret; + if (bytes == length) + stalled = false; } else if (ret == 0) { if (downloader_cat.is_debug()) downloader_cat.debug() @@ -475,7 +510,8 @@ safe_receive(int socket, DownloadStatus &status, int length, // Description: //////////////////////////////////////////////////////////////////// int Downloader:: -attempt_read(int length, DownloadStatus &status, int &bytes_read) { +attempt_read(int length, DownloadStatus &status, int &bytes_read, + bool &stalled) { bytes_read = 0; for (int i = 0; i < downloader_timeout_retries; i++) { @@ -494,7 +530,7 @@ attempt_read(int length, DownloadStatus &status, int &bytes_read) { // Make the request for length bytes int bytes; int ans = safe_receive(_socket, status, length, - (long)downloader_timeout, bytes); + (long)downloader_timeout, bytes, stalled); bytes_read += bytes; switch (ans) { @@ -528,7 +564,7 @@ attempt_read(int length, DownloadStatus &status, int &bytes_read) { int Downloader:: download(const string &file_name, Filename file_dest, const string &event_name, int first_byte, int last_byte, - int total_bytes, bool partial_content, uint id) { + int total_bytes, bool partial_content, bool sync, uint id) { if (_download_enabled == false) { if (downloader_cat.is_debug()) @@ -611,16 +647,21 @@ download(const string &file_name, Filename file_dest, _bandwidth_frequency_lock.lock(); #endif // read_size is the length of the buffer requested via safe_receive() - int read_size = (int)_bandwidth; - if (_frequency > 0) - read_size = (int)(_bandwidth * _frequency); + int read_size; + nassertr(_frequency > 0, D_error); + if (sync == true || _frequency == 0) + read_size = (int)_byte_rate; + else + read_size = (int)(_byte_rate * _frequency); #ifdef HAVE_IPC _bandwidth_frequency_lock.unlock(); #endif // Attempt to read int bytes_read; - int ret = attempt_read(read_size, status, bytes_read); + bool stalled; + int ret = attempt_read(read_size, status, bytes_read, stalled); + _last_attempt_stalled = stalled; if (bytes_read > 0) got_any_data = true; diff --git a/panda/src/downloader/downloader.h b/panda/src/downloader/downloader.h index d731134c32..56e46f88a9 100644 --- a/panda/src/downloader/downloader.h +++ b/panda/src/downloader/downloader.h @@ -33,24 +33,32 @@ class DownloaderToken; class EXPCL_PANDAEXPRESS Downloader : public AsyncUtility { PUBLISHED: Downloader(void); - Downloader(PT(Buffer) buffer); + //Downloader(PT(Buffer) buffer); virtual ~Downloader(void); bool connect_to_server(const string &name, uint port=80); void disconnect_from_server(void); - int request_download(const string &file_name, const Filename &file_dest, + int request_sync_download(const string &file_name, const Filename &file_dest, const string &event_name); + int request_sync_download(const string &file_name, const Filename &file_dest, + const string &event_name, int first_byte, + int last_byte, int total_bytes, + bool partial_content = true); + int request_download(const string &file_name, const Filename &file_dest, + const string &event_name, bool sync = false); int request_download(const string &file_name, const Filename &file_dest, const string &event_name, int first_byte, int last_byte, int total_bytes, - bool partial_content = true); + bool partial_content = true, bool sync = false); - INLINE void set_bandwidth(float bytes); - INLINE float get_bandwidth(void) const; + INLINE void set_byte_rate(float bytes); + INLINE float get_byte_rate(void) const; + INLINE bool set_disk_write_frequency(int frequency); + INLINE int get_disk_write_frequency(void) const; INLINE void enable_download(bool val); INLINE bool is_download_enabled(void) const; - INLINE bool change_buffer_size(int size); + INLINE bool get_last_attempt_stalled(void) const; private: class DownloadStatus { @@ -79,20 +87,21 @@ private: char *_buffer; }; - void init(PT(Buffer) buffer); + void init(); int download(const string &file_name, Filename file_dest, const string &event_name, int first_byte, int last_byte, int total_bytes, bool partial_content, - uint id); + bool sync, uint id); virtual bool process_request(void); bool parse_header(DownloadStatus &status); bool write_to_disk(DownloadStatus &status); bool connect_to_server(void); int safe_send(int socket, const char *data, int length, long timeout); int safe_receive(int socket, DownloadStatus &status, int length, - long timeout, int &bytes); + long timeout, int &bytes, bool &stalled); bool parse_http_response(const string &resp); - int attempt_read(int length, DownloadStatus &status, int &bytes_read); + int attempt_read(int length, DownloadStatus &status, int &bytes_read, + bool &stalled); typedef TokenBoard DownloaderTokenBoard; DownloaderTokenBoard *_token_board; @@ -106,11 +115,13 @@ private: int _socket; PT(Buffer) _buffer; - float _bandwidth; + int _disk_write_frequency; + float _byte_rate; bool _download_enabled; ofstream _dest_stream; int _new_buffer_size; int _buffer_size; + bool _last_attempt_stalled; string _server_name; struct sockaddr_in _sin;