altoslib: Limit simultanous map tile downloads to 128
authorKeith Packard <keithp@keithp.com>
Sun, 12 Jul 2015 02:11:48 +0000 (19:11 -0700)
committerKeith Packard <keithp@keithp.com>
Sun, 12 Jul 2015 02:11:48 +0000 (19:11 -0700)
Before this change, every tile requested would get downloaded at the
same time. With moving to distance-based offline map loading radius
values, the number of tiles at closer zooms was in the thousands,
overwhelming the network.

Signed-off-by: Keith Packard <keithp@keithp.com>
altoslib/AltosMapStore.java

index 8841259..a10a166 100644 (file)
@@ -118,49 +118,85 @@ public class AltosMapStore {
        static final long       forbidden_interval = 60l * 1000l * 1000l * 1000l;
        static final long       google_maps_ratelimit_ms = 1200;
 
+       static Object   loader_lock = new Object();
+
+       static LinkedList<AltosMapStore> waiting = new LinkedList<AltosMapStore>();
+       static LinkedList<AltosMapStore> running = new LinkedList<AltosMapStore>();
+
+       static final int concurrent_loaders = 128;
+
+       static void start_loaders() {
+               while (!waiting.isEmpty() && running.size() < concurrent_loaders) {
+                       AltosMapStore   s = waiting.remove();
+                       running.add(s);
+                       Thread lt = s.make_loader_thread();
+                       lt.start();
+               }
+       }
+
+       void finish_loader() {
+               synchronized(loader_lock) {
+                       running.remove(this);
+                       start_loaders();
+               }
+       }
+
+       void add_loader() {
+               synchronized(loader_lock) {
+                       waiting.add(this);
+                       start_loaders();
+               }
+       }
+
        class loader implements Runnable {
 
                public void run() {
-                       if (file.exists()) {
-                               notify_listeners(AltosMapTile.success);
-                               return;
-                       }
-
-                       synchronized(forbidden_lock) {
-                               if (forbidden_set && (System.nanoTime() - forbidden_time) < forbidden_interval) {
-                                       notify_listeners(AltosMapTile.forbidden);
+                       try {
+                               if (file.exists()) {
+                                       notify_listeners(AltosMapTile.success);
                                        return;
                                }
-                       }
 
-                       int new_status;
+                               synchronized(forbidden_lock) {
+                                       if (forbidden_set && (System.nanoTime() - forbidden_time) < forbidden_interval) {
+                                               notify_listeners(AltosMapTile.forbidden);
+                                               return;
+                                       }
+                               }
 
-                       if (!AltosVersion.has_google_maps_api_key()) {
-                               synchronized (fetch_lock) {
-                                       long startTime = System.nanoTime();
-                                       new_status = fetch_url();
-                                       if (new_status == AltosMapTile.success) {
-                                               long duration_ms = (System.nanoTime() - startTime) / 1000000;
-                                               if (duration_ms < google_maps_ratelimit_ms) {
-                                                       try {
-                                                               Thread.sleep(google_maps_ratelimit_ms - duration_ms);
-                                                       } catch (InterruptedException e) {
-                                                               Thread.currentThread().interrupt();
+                               int new_status;
+
+                               if (!AltosVersion.has_google_maps_api_key()) {
+                                       synchronized (fetch_lock) {
+                                               long startTime = System.nanoTime();
+                                               new_status = fetch_url();
+                                               if (new_status == AltosMapTile.success) {
+                                                       long duration_ms = (System.nanoTime() - startTime) / 1000000;
+                                                       if (duration_ms < google_maps_ratelimit_ms) {
+                                                               try {
+                                                                       Thread.sleep(google_maps_ratelimit_ms - duration_ms);
+                                                               } catch (InterruptedException e) {
+                                                                       Thread.currentThread().interrupt();
+                                                               }
                                                        }
                                                }
                                        }
+                               } else {
+                                       new_status = fetch_url();
                                }
-                       } else {
-                               new_status = fetch_url();
+                               notify_listeners(new_status);
+                       } finally {
+                               finish_loader();
                        }
-                       notify_listeners(new_status);
                }
        }
 
+       private Thread make_loader_thread() {
+               return new Thread(new loader());
+       }
+
        private void load() {
-               loader  l = new loader();
-               Thread  lt = new Thread(l);
-               lt.start();
+               add_loader();
        }
 
        private AltosMapStore (String url, File file) {