private void doHttpMaxFailover() { long maxTimeAgo = clock.now() - silentPeriodForMaxHttpRequest; if (!httpRequestControl.requestQueued(HttpRequestControl.RequestReason.MAX) && UpdateSettings.LAST_SIMPP_FAILOVER.getValue() < maxTimeAgo) { int rndDelay = RANDOM.nextInt(maxMaxHttpRequestDelay) + minMaxHttpRequestDelay; final String rndUri = maxedUpdateList.get(RANDOM.nextInt(maxedUpdateList.size())); LOG.debug("Scheduling http max failover in: " + rndDelay + ", to: " + rndUri); backgroundExecutor.schedule( new Runnable() { public void run() { String url = rndUri; try { launchHTTPUpdate(url); } catch (URISyntaxException e) { httpRequestControl.requestFinished(); httpRequestControl.cancelRequest(); LOG.warn("uri failure", e); } } }, rndDelay, TimeUnit.MILLISECONDS); } else { LOG.debug("Ignoring http max failover."); } }
/** Determines if we're far enough past the timestamp to start a new in network download. */ private boolean canStartDownload() { long now = clock.now(); if (LOG.isDebugEnabled()) LOG.debug("now is " + now + " next time is " + _nextDownloadTime); return now > _nextDownloadTime; }
/** begins an http failover. */ private void checkForStaleUpdateAndMaybeDoHttpFailover() { LOG.debug("checking for timeout http failover"); long monthAgo = clock.now() - ONE_MONTH; if (UpdateSettings.LAST_UPDATE_TIMESTAMP.getValue() < monthAgo && // more than a month ago UpdateSettings.LAST_HTTP_FAILOVER.getValue() < monthAgo && // and last failover too !httpRequestControl.requestQueued( HttpRequestControl.RequestReason.TIMEOUT)) { // and we're not already doing a failover long when = (connectionServices.isConnected() ? 1 : 5) * 60 * 1000; if (LOG.isDebugEnabled()) LOG.debug("scheduling http failover in " + when); backgroundExecutor.schedule( new Runnable() { public void run() { try { launchHTTPUpdate(timeoutUpdateLocation); } catch (URISyntaxException e) { httpRequestControl.requestFinished(); httpRequestControl.cancelRequest(); LOG.warn(e.toString(), e); } } }, when, TimeUnit.MILLISECONDS); } }
/** @return whether we killed any hopeless update downloads */ private void killHopelessUpdates(List<? extends DownloadInformation> updates) { if (updates == null) return; if (!downloadManager.get().hasInNetworkDownload()) return; long now = clock.now(); for (DownloadInformation info : updates) { Downloader downloader = downloadManager.get().getDownloaderForURN(info.getUpdateURN()); if (downloader != null && downloader instanceof InNetworkDownloader) { InNetworkDownloader iDownloader = (InNetworkDownloader) downloader; if (isHopeless(iDownloader, now)) iDownloader.stop(false); } } }
@Override public void initialize() { // Increment the session counter int sessions = ApplicationSettings.SESSIONS.getValue(); ApplicationSettings.SESSIONS.setValue(sessions + 1); // Record the time between sessions long lastShutdown = ApplicationSettings.LAST_SHUTDOWN_TIME.getValue(); long downtime; if (lastShutdown == 0) downtime = DEFAULT_DOWNTIME; else downtime = Math.max(0, (clock.now() - lastShutdown) / 1000); // If the number of downtimes is greater that the number of uptimes, // the last session must have ended without recording the uptime or // shutdown time. To avoid double-counting the downtime we should // overwrite the last downtime instead of appending. String[] downtimes = ApplicationSettings.DOWNTIME_HISTORY.get(); String[] uptimes = ApplicationSettings.UPTIME_HISTORY.get(); if (downtimes.length > uptimes.length) downtimes = updateHistory(downtimes, Long.toString(downtime)); else downtimes = appendToHistory(downtimes, Long.toString(downtime)); ApplicationSettings.DOWNTIME_HISTORY.set(downtimes); // Measure the time between refreshes lastUpdateTime = clock.now(); }
/** Refreshes the uptime statistics. Package access for testing. */ void refreshStats() { long now = clock.now(); long elapsed = (now - lastUpdateTime) / 1000; if (elapsed > 0) { currentUptime += elapsed; updateUptimeHistory(currentUptime); long totalUptime = ApplicationSettings.TOTAL_UPTIME.getValue() + elapsed; ApplicationSettings.TOTAL_UPTIME.setValue(totalUptime); int sessions = ApplicationSettings.SESSIONS.getValue(); if (sessions > 0) { ApplicationSettings.AVERAGE_UPTIME.setValue(totalUptime / sessions); } ApplicationSettings.FRACTIONAL_UPTIME.setValue(stats.calculateFractionalUptime()); ApplicationSettings.LAST_SHUTDOWN_TIME.setValue(now); // Pessimistic } lastUpdateTime = now; }
/** * Tries to download updates. * * @return whether we had any non-hopeless updates. */ private void downloadUpdates( List<? extends DownloadInformation> toDownload, ReplyHandler source) { if (toDownload == null) toDownload = Collections.emptyList(); killObsoleteUpdates(toDownload); for (DownloadInformation next : toDownload) { if (isHopeless(next)) continue; if (downloadManager.get().isSavedDownloadsLoaded() && fileManager.get().getManagedFileList().isLoadFinished()) { // TODO: remove the cast ManagedDownloader md = (ManagedDownloader) downloadManager.get().getDownloaderForURN(next.getUpdateURN()); // Skip to the next one since we already have a complete file. if (hasCompleteFile(next.getUpdateURN())) { if (md != null) { md.stop(false); } continue; } // If we don't have an existing download ... // and there's no existing InNetwork downloads & // no existing Store downloads & // we're allowed to start a new one. if (md == null && !downloadManager.get().hasInNetworkDownload() && canStartDownload()) { LOG.debug("Starting a new InNetwork Download"); try { md = (ManagedDownloader) downloadManager.get().download(next, clock.now()); } catch (SaveLocationException sle) { LOG.error("Unable to construct download", sle); } } if (md != null) { if (source != null) md.addDownload(rfd(source, next), false); else addCurrentDownloadSources(md, next); } } } }
/** * Stores the given data to disk & posts an update to neighboring connections. Starts the download * of any updates */ private void storeAndUpdate(byte[] data, UpdateCollection uc, UpdateType updateType) { if (LOG.isTraceEnabled()) LOG.trace("Retrieved new data from: " + updateType + ", storing & updating."); if (uc.getId() == IGNORE_ID && updateType == UpdateType.FROM_NETWORK) throw new IllegalStateException("shouldn't be here!"); // If an http max request is pending, don't even bother with this stuff. // We want to get it straight from the source... if (updateType == UpdateType.FROM_NETWORK && httpRequestControl.isRequestPending() && httpRequestControl.getRequestReason() == HttpRequestControl.RequestReason.MAX) return; _lastId = uc.getId(); _lastTimestamp = uc.getTimestamp(); UpdateSettings.LAST_UPDATE_TIMESTAMP.setValue(_lastTimestamp); long delay = UpdateSettings.UPDATE_DOWNLOAD_DELAY.getValue(); long random = Math.abs(RANDOM.nextLong() % delay); _nextDownloadTime = _lastTimestamp + random; _lastBytes = data; if (updateType != UpdateType.FROM_DISK) { // cancel any http and pretend we just updated. if (httpRequestControl.getRequestReason() == HttpRequestControl.RequestReason.TIMEOUT) httpRequestControl.cancelRequest(); UpdateSettings.LAST_HTTP_FAILOVER.setValue(clock.now()); FileUtils.verySafeSave(CommonUtils.getUserSettingsDir(), FILENAME, data); capabilitiesVMFactory.updateCapabilities(); connectionManager.get().sendUpdatedCapabilities(); } Version limeV; try { limeV = new Version(LimeWireUtils.getLimeWireVersion()); } catch (VersionFormatException vfe) { LOG.warn("Invalid LimeWire version", vfe); return; } Version javaV = null; try { javaV = new Version(VersionUtils.getJavaVersion()); } catch (VersionFormatException vfe) { LOG.warn("Invalid java version", vfe); } // don't allow someone to set the style to be above major. int style = Math.min(UpdateStyle.STYLE_MAJOR, UpdateSettings.UPDATE_STYLE.getValue()); UpdateData updateInfo = uc.getUpdateDataFor( limeV, ApplicationSettings.getLanguage(), LimeWireUtils.isPro(), style, javaV); List<DownloadInformation> updatesToDownload = uc.getUpdatesWithDownloadInformation(); _killingObsoleteNecessary = true; // if we have an update for our machine, prepare the command line // and move our update to the front of the list of updates if (updateInfo != null && updateInfo.getUpdateURN() != null) { prepareUpdateCommand(updateInfo); updatesToDownload = new LinkedList<DownloadInformation>(updatesToDownload); updatesToDownload.add(0, updateInfo); } _updateInfo = updateInfo; _updatesToDownload = updatesToDownload; downloadUpdates(updatesToDownload, null); if (updateInfo == null) { LOG.warn("No relevant update info to notify about."); return; } else if (updateInfo.getUpdateURN() == null || isHopeless(updateInfo)) { if (LOG.isDebugEnabled()) LOG.debug( "we have an update, but it doesn't need a download. " + "or all our updates are hopeles. Scheduling URL notification..."); updateInfo.setUpdateCommand(null); backgroundExecutor.schedule( new NotificationFailover(_lastId), delay(clock.now(), uc.getTimestamp()), TimeUnit.MILLISECONDS); } else if (isMyUpdateDownloaded(updateInfo)) { LOG.debug("there is an update for me, but I happen to have it on disk"); fireUpdate(updateInfo); } else LOG.debug("we have an update, it needs a download. Rely on callbacks"); }