From b83cf459c80b1fab61df562f3ed63b846a24a7f1 Mon Sep 17 00:00:00 2001 From: Jon Atkins Date: Fri, 6 Sep 2013 22:32:57 +0100 Subject: [PATCH] more tweaks to the request code - delay briefly before retrying a timeout, and a bit longer before other errors - also delay briefly before running the queue after a request, to give a chance of more than one request's requeued entries being handled atr once - add a min tiles per request, to avoid sending multiple requests when only a few queued items remain these are attempts to be nicer to the niantic servers, particularly in error cases, with some based on my best guess of the stock site behaviour, and others based on what seems reasonable to me --- code/map_data_debug.js | 7 ++- code/map_data_request.js | 96 +++++++++++++++++++++++++++++++--------- 2 files changed, 80 insertions(+), 23 deletions(-) diff --git a/code/map_data_debug.js b/code/map_data_debug.js index eb2ddcc7..4ecc27a8 100644 --- a/code/map_data_debug.js +++ b/code/map_data_debug.js @@ -34,8 +34,8 @@ window.RenderDebugTiles.prototype.setColour = function(id,bordercol,fillcol) { } window.RenderDebugTiles.prototype.setState = function(id,state) { - var col = '#666'; - var fill = '#666'; + var col = '#f0f'; + var fill = '#f0f'; switch(state) { case 'ok': col='#0f0'; fill='#0f0'; break; case 'error': col='#f00'; fill='#f00'; break; @@ -43,6 +43,9 @@ window.RenderDebugTiles.prototype.setState = function(id,state) { case 'cache-stale': col='#f00'; fill='#ff0'; break; case 'requested': col='#66f'; fill='#66f'; break; case 'retrying': col='#666'; fill='#666'; break; + case 'request-fail': col='#a00'; fill='#666'; break; + case 'tile-fail': col='#f00'; fill='#666'; break; + case 'tile-timeout': col='#ff0'; fill='#666'; break; } this.setColour (id, col, fill); } diff --git a/code/map_data_request.js b/code/map_data_request.js index d276d31e..701fbb23 100644 --- a/code/map_data_request.js +++ b/code/map_data_request.js @@ -20,8 +20,11 @@ window.MapDataRequest = function() { // (the stock site seems to have no limit - i've seen ~100 for L3+ portals and a maximised browser window) this.MAX_TILES_PER_REQUEST = 32; + // try to maintain at least this may tiles in each request, by reducing the number of requests as needed + this.MIN_TILES_PER_REQUEST = 4; + // number of times to retty a tile after a 'bad' error (i.e. not a timeout) - this.MAX_TILE_RETRIES = 1; + this.MAX_TILE_RETRIES = 3; // refresh timers this.MOVE_REFRESH = 0.5; //refresh time to use after a move @@ -32,6 +35,16 @@ window.MapDataRequest = function() { // processing cache, etc) and actually sending the first network requests this.DOWNLOAD_DELAY = 3; //delay after preparing the data download before tile requests are sent + // a short delay between one request finishing and the queue being run for the next request + this.RUN_QUEUE_DELAY = 0.5; + + // delay before re-queueing tiles + this.TILE_TIMEOUT_REQUEUE_DELAY = 0.5; // short delay before retrying a 'error==TIMEOUT' tile - as this is very common + this.BAD_REQUEST_REQUEUE_DELAY = 4; // longer delay before retrying a completely failed request - as in this case the servers are struggling + + // additionally, a delay before processing the queue after requeueing tiles + // (this way, if multiple requeue delays finish within a short time of each other, they're all processed in one queue run) + this.RERUN_QUEUE_DELAY = 2; this.REFRESH_CLOSE = 120; // refresh time to use for close views z>12 when not idle and not moving this.REFRESH_FAR = 600; // refresh time for far views z <= 12 @@ -125,11 +138,6 @@ window.MapDataRequest.prototype.refreshOnTimeout = function(seconds) { } -//window.MapDataRequest.prototype.clearQueue = function() { -// this.tileBounds = {}; -//} - - window.MapDataRequest.prototype.setStatus = function(short,long,progress) { this.status = { short: short, long: long, progress: progress }; window.renderUpdateStatus(); @@ -247,11 +255,16 @@ window.MapDataRequest.prototype.refresh = function() { console.log ('done request preperation (cleared out-of-bounds and invalid for zoom, and rendered cached data)'); // don't start processing the download queue immediately - start it after a short delay - var savedContext = this; - this.timer = setTimeout ( function() { savedContext.timer = undefined; savedContext.processRequestQueue(true); }, this.DOWNLOAD_DELAY*1000 ); + this.delayProcessRequestQueue (this.DOWNLOAD_DELAY,true); } +window.MapDataRequest.prototype.delayProcessRequestQueue = function(seconds,isFirst) { + if (this.timer === undefined) { + var savedContext = this; + this.timer = setTimeout ( function() { savedContext.timer = undefined; savedContext.processRequestQueue(isFirst); }, seconds*1000 ); + } +} window.MapDataRequest.prototype.processRequestQueue = function(isFirstPass) { @@ -259,10 +272,6 @@ window.MapDataRequest.prototype.processRequestQueue = function(isFirstPass) { // if nothing left in the queue, end the render. otherwise, send network requests if (Object.keys(this.tileBounds).length == 0) { -// // if map is being dragged, just return without any end of map processing -// if (this.moving) -// return; - this.render.endRenderPass(); var endTime = new Date().getTime(); @@ -286,6 +295,7 @@ window.MapDataRequest.prototype.processRequestQueue = function(isFirstPass) { return; } + // create a list of tiles that aren't requested over the network var pendingTiles = []; for (var id in this.tileBounds) { @@ -300,6 +310,11 @@ window.MapDataRequest.prototype.processRequestQueue = function(isFirstPass) { var requestBuckets = this.MAX_REQUESTS - this.activeRequestCount; if (pendingTiles.length > 0 && requestBuckets > 0) { + // the stock site calculates bucket grouping with the simplistic <8 tiles: 1 bucket, otherwise 4 buckets + var maxBuckets = Math.ceil(pendingTiles.length/this.MIN_TILES_PER_REQUEST); + + requestBuckets = Math.min (maxBuckets, requestBuckets); + var lastTileIndex = Math.min(requestBuckets*this.MAX_TILES_PER_REQUEST, pendingTiles.length); for (var bucket=0; bucket 0) { + setTimeout (function() { + for (var i in timeoutTiles) { + var id = timeoutTiles[i]; + delete savedContext.requestedTiles[id]; + savedContext.requeueTile(id, false); + } + savedContext.delayProcessRequestQueue(this.RERUN_QUEUE_DELAY); + }, this.TILE_TIMEOUT_REQUEUE_DELAY*1000); + } + + if (errorTiles.length > 0) { + setTimeout (function() { + for (var i in errorTiles) { + var id = errorTiles[i]; + delete savedContext.requestedTiles[id]; + savedContext.requeueTile(id, true); + } + savedContext.delayProcessRequestQueue(this.RERUN_QUEUE_DELAY); + }, this.BAD_REQUEST_REQUEUE_DELAY*1000); + } + + + for (var i in successTiles) { + var id = successTiles[i]; + delete this.requestedTiles[id]; + } + + //.. should this also be delayed a small amount? + this.delayProcessRequestQueue(this.RUN_QUEUE_DELAY); }