The MinGW.org Installation Manager Tool
Revision | 8c77cf991cd3599c28525bf973e3f88bcf99231c (tree) |
---|---|
Time | 2013-08-26 16:35:01 |
Author | Keith Marshall <keithmarshall@user...> |
Commiter | Keith Marshall |
Implement retry throttling for failed internet connections.
@@ -1,3 +1,19 @@ | ||
1 | +2013-08-26 Keith Marshall <keithmarshall@users.sourceforge.net> | |
2 | + | |
3 | + Implement retry throttling for failed internet connections. | |
4 | + | |
5 | + * src/pkginet.h (INTERNET_RETRY_ATTEMPTS): New macro; define it. | |
6 | + (INTERNET_RETRY_INTERVAL, INTERNET_DELAY_FACTOR): Likewise. | |
7 | + | |
8 | + * src/pkginet.cpp (INTERNET_RETRY_REQUESTER): New typedef. | |
9 | + (pkgInternetAgent::connection_delay, pkgInternetAgent::delay_factor): | |
10 | + (pkgInternetAgent::retries, pkgInternetAgent::retry_interval): New | |
11 | + private member variables; declare them. | |
12 | + (pkgInternetAgent::OpenURL): Use them; they must be initialised by... | |
13 | + (pkgInternetAgent::SetRetryOptions): ...this new method; implement it. | |
14 | + (pkgActionItem::DownloadSingleArchive): Invoke it. | |
15 | + (pkgXmlDocument::SyncRepository): Likewise. | |
16 | + | |
1 | 17 | 2013-08-24 Keith Marshall <keithmarshall@users.sourceforge.net> |
2 | 18 | |
3 | 19 | Reassign default URL for download of setup tool components. |
@@ -244,6 +244,23 @@ int pkgDownloadMeter::SizeFormat( char *buf, unsigned long filesize ) | ||
244 | 244 | return retval; |
245 | 245 | } |
246 | 246 | |
247 | +/* To facilitate the implementation of the pkgInternetAgent class, which | |
248 | + * is declared below: | |
249 | + */ | |
250 | +#if IMPLEMENTATION_LEVEL == SETUP_TOOL_COMPONENT | |
251 | + | |
252 | +/* Within the setup tool, the pkgInternetAgent::SetRetryOptions() method | |
253 | + * requires a pointer to a pkgSetupAction... | |
254 | + */ | |
255 | + typedef pkgSetupAction *INTERNET_RETRY_REQUESTER; | |
256 | + | |
257 | +#else | |
258 | +/* ...whereas, in the general case, it requires a pointer to a pkgXmlNode. | |
259 | + */ | |
260 | + typedef pkgXmlNode *INTERNET_RETRY_REQUESTER; | |
261 | + | |
262 | +#endif | |
263 | + | |
247 | 264 | class pkgInternetAgent |
248 | 265 | { |
249 | 266 | /* A minimal, locally implemented class, instantiated ONCE as a |
@@ -252,6 +269,7 @@ class pkgInternetAgent | ||
252 | 269 | */ |
253 | 270 | private: |
254 | 271 | HINTERNET SessionHandle; |
272 | + int connection_delay, delay_factor, retries, retry_interval; | |
255 | 273 | |
256 | 274 | public: |
257 | 275 | inline pkgInternetAgent():SessionHandle( NULL ) |
@@ -272,6 +290,7 @@ class pkgInternetAgent | ||
272 | 290 | if( SessionHandle != NULL ) |
273 | 291 | Close( SessionHandle ); |
274 | 292 | } |
293 | + void SetRetryOptions( INTERNET_RETRY_REQUESTER, const char* ); | |
275 | 294 | HINTERNET OpenURL( const char* ); |
276 | 295 | |
277 | 296 | /* Remaining methods are simple inline wrappers for the |
@@ -353,6 +372,32 @@ pkgInternetStreamingAgent::~pkgInternetStreamingAgent() | ||
353 | 372 | free( (void *)(dest_file) ); |
354 | 373 | } |
355 | 374 | |
375 | +void pkgInternetAgent::SetRetryOptions | |
376 | +( INTERNET_RETRY_REQUESTER referrer, const char *url_template ) | |
377 | +{ | |
378 | + /* Initialisation method, invoked immediately prior to the start | |
379 | + * of each archive download request, to establish the options for | |
380 | + * retrying any failed host connection request. | |
381 | + * | |
382 | + * The first of any sequence of connection attempts may always be | |
383 | + * initiated immediately. | |
384 | + */ | |
385 | + connection_delay = 0; | |
386 | + | |
387 | + /* If any further attempts are necessary, we will delay them | |
388 | + * at progressively increasing intervals, to give us the best | |
389 | + * possible chance to circumvent throttling of excess frequency | |
390 | + * connection requests, by the download server. | |
391 | + * | |
392 | + * FIXME: for each change of host domain, we should establish | |
393 | + * settings by consulting the configuration profile; for the | |
394 | + * time being, we simply assign fixed defaults. | |
395 | + */ | |
396 | + delay_factor = INTERNET_DELAY_FACTOR; | |
397 | + retry_interval = INTERNET_RETRY_INTERVAL; | |
398 | + retries = INTERNET_RETRY_ATTEMPTS; | |
399 | +} | |
400 | + | |
356 | 401 | HINTERNET pkgInternetAgent::OpenURL( const char *URL ) |
357 | 402 | { |
358 | 403 | /* Open an internet data stream. |
@@ -378,8 +423,24 @@ HINTERNET pkgInternetAgent::OpenURL( const char *URL ) | ||
378 | 423 | /* Aggressively attempt to acquire a resource handle, which we may use |
379 | 424 | * to access the specified URL; (schedule a maximum of five attempts). |
380 | 425 | */ |
381 | - int retries = 5; | |
382 | 426 | do { pkgDownloadMeter::SpinWait( 1, URL ); |
427 | + | |
428 | + /* Distribute retries at geometrically incrementing intervals. | |
429 | + */ | |
430 | + if( connection_delay > 0 ) | |
431 | + /* This is not the first time we've tried to open this URL; | |
432 | + * compute the appropriate retry interval, and wait between | |
433 | + * successive attempts to establish the connection. | |
434 | + */ | |
435 | + Sleep( connection_delay = delay_factor * connection_delay ); | |
436 | + else | |
437 | + /* This is the first attempt to open this URL; don't wait, | |
438 | + * but set up the baseline, in milliseconds, for interval | |
439 | + * computation, in the event that further attempts may be | |
440 | + * required. | |
441 | + */ | |
442 | + connection_delay = retry_interval; | |
443 | + | |
383 | 444 | ResourceHandle = InternetOpenUrl |
384 | 445 | ( |
385 | 446 | /* Here, we attempt to assign a URL specific resource handle, |
@@ -405,14 +466,18 @@ HINTERNET pkgInternetAgent::OpenURL( const char *URL ) | ||
405 | 466 | * unless we have exhausted the specified retry limit... |
406 | 467 | */ |
407 | 468 | if( --retries < 1 ) |
408 | - /* | |
409 | - * ...in which case, we diagnose failure to open the URL. | |
469 | + { | |
470 | + /* ...in which case, we diagnose failure to open the URL. | |
410 | 471 | */ |
472 | + DEBUG_INVOKE_IF( DEBUG_REQUEST( DEBUG_TRACE_INTERNET_REQUESTS ), | |
473 | + dmh_printf( "%s\nConnection failed(status=%u); abandoned.\n", | |
474 | + URL, GetLastError() ) | |
475 | + ); | |
411 | 476 | dmh_notify( DMH_ERROR, "%s:cannot open URL\n", URL ); |
412 | - | |
477 | + } | |
413 | 478 | else DEBUG_INVOKE_IF( DEBUG_REQUEST( DEBUG_TRACE_INTERNET_REQUESTS ), |
414 | - dmh_printf( "%s\nConnecting ... failed(status=%u); retrying...\n", | |
415 | - URL, GetLastError() ) | |
479 | + dmh_printf( "%s\nConnecting ... failed(status=%u); retrying in %ds...\n", | |
480 | + URL, GetLastError(), delay_factor * connection_delay / 1000 ) | |
416 | 481 | ); |
417 | 482 | } |
418 | 483 | else |
@@ -771,11 +836,18 @@ void pkgActionItem::DownloadSingleArchive | ||
771 | 836 | if( url_template != NULL ) |
772 | 837 | { |
773 | 838 | /* ...from the URL constructed from the template specified in |
774 | - * the package repository catalogue (configuration database)... | |
839 | + * the package repository catalogue (configuration database). | |
775 | 840 | */ |
776 | 841 | const char *mirror = get_host_info( Selection(), mirror_key ); |
777 | 842 | char package_url[mkpath( NULL, url_template, package_name, mirror )]; |
778 | 843 | mkpath( package_url, url_template, package_name, mirror ); |
844 | + | |
845 | + /* Enable retrying of failed connection attempts, according to the | |
846 | + * preferences, if any, which have been configured for the repository | |
847 | + * associated with the current URL template, or with default settings | |
848 | + * otherwise, then initiate the package download process. | |
849 | + */ | |
850 | + pkgDownloadAgent.SetRetryOptions( Selection(), url_template ); | |
779 | 851 | if( download.Get( package_url ) > 0 ) |
780 | 852 | /* |
781 | 853 | * Download was successful; clear the pending and failure flags. |
@@ -992,12 +1064,17 @@ void pkgXmlDocument::SyncRepository( const char *name, pkgXmlNode *repository ) | ||
992 | 1064 | const char *mirror = repository->GetPropVal( mirror_key, NULL ); |
993 | 1065 | char catalogue_url[mkpath( NULL, url_template, name, mirror )]; |
994 | 1066 | mkpath( catalogue_url, url_template, name, mirror ); |
995 | -//dmh_printf( "SyncRepository: get %s ...\n", catalogue_url ); | |
1067 | + | |
1068 | + /* Enable retries according to the preferences, if any, as | |
1069 | + * configured for the repository, or adopt default settings | |
1070 | + * otherwise, then initiate the download process for the | |
1071 | + * catalogue file. | |
1072 | + */ | |
1073 | + pkgDownloadAgent.SetRetryOptions( repository, url_template ); | |
996 | 1074 | if( download.Get( catalogue_url ) <= 0 ) |
997 | 1075 | dmh_notify( DMH_ERROR, |
998 | 1076 | "Sync Repository: %s: download failed\n", catalogue_url |
999 | 1077 | ); |
1000 | -//dmh_printf( "SyncRepository: get %s completed\n", catalogue_url ); | |
1001 | 1078 | } |
1002 | 1079 | |
1003 | 1080 | /* We will only replace our current working copy of this catalogue, |
@@ -28,6 +28,28 @@ | ||
28 | 28 | */ |
29 | 29 | #define PKGINET_H 1 |
30 | 30 | |
31 | +/* profile.xml may specify the maximum number of retries which will | |
32 | + * be permitted, for each configured repository, when any attempt to | |
33 | + * establish a download connection fails. In the event that this is | |
34 | + * not specified in profile.xml, the following default will apply: | |
35 | + */ | |
36 | +#define INTERNET_RETRY_ATTEMPTS 5 | |
37 | + | |
38 | +/* In the default case, when profile.xml doesn't stipulate options, | |
39 | + * specify the interval, in milliseconds, to wait between successive | |
40 | + * retries to open any one URL. The first attempt for each individual | |
41 | + * URL is immediate; if it fails, the first retry is scheduled after | |
42 | + * | |
43 | + * INTERNET_RETRY_INTERVAL * INTERNET_DELAY_FACTOR milliseconds | |
44 | + * | |
45 | + * In the event that further retries are necessary, they are scheduled | |
46 | + * at geometrically incrementing intervals, by multiplying the interval | |
47 | + * from the preceding attempt by INTERNET_DELAY_FACTOR, prior to each | |
48 | + * successive connection attempt. | |
49 | + */ | |
50 | +#define INTERNET_DELAY_FACTOR 2 | |
51 | +#define INTERNET_RETRY_INTERVAL 1000 | |
52 | + | |
31 | 53 | class pkgDownloadMeter |
32 | 54 | { |
33 | 55 | /* Abstract base class, from which facilities for monitoring the |