Ticket #10902: TMS_simultaneus_connections.patch
File TMS_simultaneus_connections.patch, 9.2 KB (added by , 9 years ago) |
---|
-
src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java
diff --git src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java index c6a22a2..ad837ca 100644
import java.io.ByteArrayInputStream; 5 5 import java.io.IOException; 6 6 import java.net.URL; 7 7 import java.util.Map; 8 import java.util.concurrent.ConcurrentHashMap; 8 9 import java.util.concurrent.Executor; 9 10 import java.util.concurrent.LinkedBlockingDeque; 11 import java.util.concurrent.Semaphore; 10 12 import java.util.concurrent.ThreadPoolExecutor; 11 13 import java.util.concurrent.TimeUnit; 12 14 import java.util.logging.Level; … … import org.openstreetmap.gui.jmapviewer.interfaces.TileJob; 19 21 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; 20 22 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; 21 23 import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource; 24 import org.openstreetmap.josm.Main; 22 25 import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry; 23 26 import org.openstreetmap.josm.data.cache.CacheEntry; 24 27 import org.openstreetmap.josm.data.cache.ICachedLoaderListener; … … public class TMSCachedTileLoaderJob extends JCSCachedTileLoaderJob<String, Buffe 41 44 * overrides the THREAD_LIMIT in superclass, as we want to have separate limit and pool for TMS 42 45 */ 43 46 public static final IntegerProperty THREAD_LIMIT = new IntegerProperty("imagery.tms.tmsloader.maxjobs", 25); 47 48 /** 49 * Limit definition for per host concurrent connections 50 */ 51 public static final IntegerProperty HOST_LIMIT = new IntegerProperty("imagery.tms.tmsloader.maxjobsperhost", 6); 52 44 53 /** 45 54 * separate from JCS thread pool for TMS loader, so we can have different thread pools for default JCS 46 55 * and for TMS imagery 47 56 */ 48 private static ThreadPoolExecutor DOWNLOAD_JOB_DISPATCHER = new ThreadPoolExecutor( 49 THREAD_LIMIT.get().intValue(), // keep the thread number constant 50 THREAD_LIMIT.get().intValue(), // do not this number of threads 51 30, // keepalive for thread 52 TimeUnit.SECONDS, 53 // make queue of LIFO type - so recently requested tiles will be loaded first (assuming that these are which user is waiting to see) 54 new LinkedBlockingDeque<Runnable>(5) { 55 /* keep the queue size fairly small, we do not want to 56 download a lot of tiles, that user is not seeing anyway */ 57 @Override 58 public boolean offer(Runnable t) { 59 return super.offerFirst(t); 57 58 private static class LIFOQueue extends LinkedBlockingDeque<Runnable> { 59 public LIFOQueue(int capacity) { 60 super(capacity); 61 } 62 63 private final static Semaphore getSemaphore(Runnable r) { 64 if (!(r instanceof TMSCachedTileLoaderJob)) 65 return null; 66 TMSCachedTileLoaderJob cachedJob = (TMSCachedTileLoaderJob) r; 67 Semaphore limit = HOST_LIMITS.get(cachedJob.getUrl().getHost()); 68 if (limit == null) { 69 synchronized(HOST_LIMITS) { 70 limit = HOST_LIMITS.get(cachedJob.getUrl().getHost()); 71 if (limit == null) { 72 limit = new Semaphore(HOST_LIMIT.get().intValue()); 73 HOST_LIMITS.put(cachedJob.getUrl().getHost(), limit); 74 } 60 75 } 76 } 77 return limit; 78 } 61 79 62 @Override 63 public Runnable remove() { 64 return super.removeFirst(); 80 private boolean acquireSemaphore(Runnable r) { 81 boolean ret = true; 82 Semaphore limit = getSemaphore(r); 83 if (limit != null) { 84 ret = limit.tryAcquire(); 85 if (!ret) { 86 Main.debug("rejecting job because of per host limit"); 65 87 } 66 88 } 67 ); 89 return ret; 90 91 } 92 @Override 93 public boolean offer(Runnable t) { 94 return acquireSemaphore(t) && super.offerFirst(t); 95 } 96 97 private Runnable releaseSemaphore(Runnable r) { 98 Semaphore limit = getSemaphore(r); 99 if (limit != null) 100 limit.release(); 101 return r; 102 } 103 104 @Override 105 public Runnable remove() { 106 return releaseSemaphore(super.removeFirst()); 107 } 108 109 @Override 110 public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException { 111 return releaseSemaphore(super.poll(timeout, unit)); 112 } 113 114 @Override 115 public Runnable take() throws InterruptedException { 116 return releaseSemaphore(super.take()); 117 } 118 } 119 120 private static Map<String, Semaphore> HOST_LIMITS = new ConcurrentHashMap<>(); 121 122 private static ThreadPoolExecutor DOWNLOAD_JOB_DISPATCHER = getThreadPoolExecutor(); 123 124 private static ThreadPoolExecutor getThreadPoolExecutor() { 125 return new ThreadPoolExecutor( 126 THREAD_LIMIT.get().intValue(), // keep the thread number constant 127 THREAD_LIMIT.get().intValue(), // do not this number of threads 128 30, // keepalive for thread 129 TimeUnit.SECONDS, 130 // make queue of LIFO type - so recently requested tiles will be loaded first (assuming that these are which user is waiting to see) 131 new LIFOQueue(5) 132 /* keep the queue size fairly small, we do not want to 133 download a lot of tiles, that user is not seeing anyway */ 134 ); 135 } 136 137 /** 138 * Reconfigures download dispatcher using current values of THREAD_LIMIT and HOST_LIMIT 139 */ 140 public static final void reconfigureDownloadDispatcher() { 141 HOST_LIMITS = new ConcurrentHashMap<>(); 142 DOWNLOAD_JOB_DISPATCHER = getThreadPoolExecutor(); 143 } 144 68 145 69 146 /** 70 147 * Constructor for creating a job, to get a specific tile from cache -
src/org/openstreetmap/josm/gui/preferences/imagery/TMSSettingsPanel.java
diff --git src/org/openstreetmap/josm/gui/preferences/imagery/TMSSettingsPanel.java src/org/openstreetmap/josm/gui/preferences/imagery/TMSSettingsPanel.java index 75ce084..0a7b89d 100644
public class TMSSettingsPanel extends JPanel { 32 32 private final JosmTextField tilecacheDir = new JosmTextField(); 33 33 private final JSpinner maxElementsOnDisk; 34 34 private final JSpinner maxConcurrentDownloads; 35 private final JSpinner maxDownloadsPerHost; 35 36 36 37 37 38 /** … … public class TMSSettingsPanel extends JPanel { 43 44 maxZoomLvl = new JSpinner(new SpinnerNumberModel(TMSLayer.DEFAULT_MAX_ZOOM, TMSLayer.MIN_ZOOM, TMSLayer.MAX_ZOOM, 1)); 44 45 maxElementsOnDisk = new JSpinner(new SpinnerNumberModel(TMSCachedTileLoader.MAX_OBJECTS_ON_DISK.get().intValue(), 0, Integer.MAX_VALUE, 1)); 45 46 maxConcurrentDownloads = new JSpinner(new SpinnerNumberModel(TMSCachedTileLoaderJob.THREAD_LIMIT.get().intValue(), 0, Integer.MAX_VALUE, 1)); 47 maxDownloadsPerHost = new JSpinner(new SpinnerNumberModel(TMSCachedTileLoaderJob.HOST_LIMIT.get().intValue(), 0, Integer.MAX_VALUE, 1)); 46 48 47 49 add(new JLabel(tr("Auto zoom by default: ")), GBC.std()); 48 50 add(GBC.glue(5, 0), GBC.std()); … … public class TMSSettingsPanel extends JPanel { 72 74 add(GBC.glue(5, 0), GBC.std()); 73 75 add(maxConcurrentDownloads, GBC.eol()); 74 76 77 add(new JLabel(tr("Maximum concurrent downloads per host: ")), GBC.std()); 78 add(GBC.glue(5, 0), GBC.std()); 79 add(maxDownloadsPerHost, GBC.eol()); 80 81 75 82 add(new JLabel(tr("Maximum elements in disk cache: ")), GBC.std()); 76 83 add(GBC.glue(5, 0), GBC.std()); 77 84 add(this.maxElementsOnDisk, GBC.eol()); … … public class TMSSettingsPanel extends JPanel { 90 97 this.tilecacheDir.setText(TMSLayer.PROP_TILECACHE_DIR.get()); 91 98 this.maxElementsOnDisk.setValue(TMSCachedTileLoader.MAX_OBJECTS_ON_DISK.get()); 92 99 this.maxConcurrentDownloads.setValue(TMSCachedTileLoaderJob.THREAD_LIMIT.get()); 100 this.maxDownloadsPerHost.setValue(TMSCachedTileLoaderJob.HOST_LIMIT.get()); 93 101 } 94 102 95 103 /** … … public class TMSSettingsPanel extends JPanel { 110 118 111 119 TMSCachedTileLoader.MAX_OBJECTS_ON_DISK.put((Integer) this.maxElementsOnDisk.getValue()); 112 120 113 if (!TMSCachedTileLoaderJob.THREAD_LIMIT.get().equals(this.maxConcurrentDownloads.getValue())) { 114 restartRequired = true; 115 TMSCachedTileLoaderJob.THREAD_LIMIT.put((Integer) this.maxConcurrentDownloads.getValue()); 116 } 121 TMSCachedTileLoaderJob.THREAD_LIMIT.put((Integer) this.maxConcurrentDownloads.getValue()); 122 TMSCachedTileLoaderJob.HOST_LIMIT.put((Integer) this.maxDownloadsPerHost.getValue()); 123 TMSCachedTileLoaderJob.reconfigureDownloadDispatcher(); 117 124 118 125 if (!TMSLayer.PROP_TILECACHE_DIR.get().equals(this.tilecacheDir.getText())) { 119 126 restartRequired = true;