Changeset 8307 in josm


Ignore:
Timestamp:
2015-05-02T00:38:57+02:00 (9 years ago)
Author:
bastiK
Message:

applied #10902 - TMS simultaneous connections (patch by wiktorn)

Location:
trunk/src/org/openstreetmap/josm
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoaderJob.java

    r8286 r8307  
    66import java.net.URL;
    77import java.util.Map;
     8import java.util.concurrent.ConcurrentHashMap;
    89import java.util.concurrent.Executor;
    910import java.util.concurrent.LinkedBlockingDeque;
     11import java.util.concurrent.Semaphore;
    1012import java.util.concurrent.ThreadPoolExecutor;
    1113import java.util.concurrent.TimeUnit;
     
    2022import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
    2123import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource;
     24import org.openstreetmap.josm.Main;
    2225import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
    2326import org.openstreetmap.josm.data.cache.CacheEntry;
     
    4245     */
    4346    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
     53
     54    private static class LIFOQueue extends LinkedBlockingDeque<Runnable> {
     55        public LIFOQueue(int capacity) {
     56            super(capacity);
     57        }
     58
     59        private final static Semaphore getSemaphore(Runnable r) {
     60            if (!(r instanceof TMSCachedTileLoaderJob))
     61                return null;
     62            TMSCachedTileLoaderJob cachedJob = (TMSCachedTileLoaderJob) r;
     63            Semaphore limit = HOST_LIMITS.get(cachedJob.getUrl().getHost());
     64            if (limit == null) {
     65                synchronized(HOST_LIMITS) {
     66                    limit = HOST_LIMITS.get(cachedJob.getUrl().getHost());
     67                    if (limit == null) {
     68                        limit = new Semaphore(HOST_LIMIT.get().intValue());
     69                        HOST_LIMITS.put(cachedJob.getUrl().getHost(), limit);
     70                    }
     71                }
     72            }
     73            return limit;
     74        }
     75
     76        private boolean acquireSemaphore(Runnable r) {
     77            boolean ret = true;
     78            Semaphore limit = getSemaphore(r);
     79            if (limit != null) {
     80                ret = limit.tryAcquire();
     81                if (!ret) {
     82                    Main.debug("rejecting job because of per host limit");
     83                }
     84            }
     85            return ret;
     86        }
     87
     88        @Override
     89        public boolean offer(Runnable t) {
     90            return acquireSemaphore(t) && super.offerFirst(t);
     91        }
     92
     93        private Runnable releaseSemaphore(Runnable r) {
     94            Semaphore limit = getSemaphore(r);
     95            if (limit != null)
     96                limit.release();
     97            return r;
     98        }
     99
     100        @Override
     101        public Runnable remove() {
     102            return releaseSemaphore(super.removeFirst());
     103        }
     104
     105        @Override
     106        public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException {
     107            return releaseSemaphore(super.poll(timeout, unit));
     108        }
     109
     110        @Override
     111        public Runnable take() throws InterruptedException {
     112            return releaseSemaphore(super.take());
     113        }
     114    }
     115
     116    private static Map<String, Semaphore> HOST_LIMITS = new ConcurrentHashMap<>();
     117
    44118    /**
    45119     * separate from JCS thread pool for TMS loader, so we can have different thread pools for default JCS
    46120     * and for TMS imagery
    47121     */
    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);
    60                 }
    61 
    62                 @Override
    63                 public Runnable remove() {
    64                     return super.removeFirst();
    65                 }
    66             }
    67             );
     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
    68145
    69146    /**
  • trunk/src/org/openstreetmap/josm/gui/preferences/imagery/TMSSettingsPanel.java

    r8168 r8307  
    3333    private final JSpinner maxElementsOnDisk;
    3434    private final JSpinner maxConcurrentDownloads;
     35    private final JSpinner maxDownloadsPerHost;
    3536
    3637
     
    4445        maxElementsOnDisk = new JSpinner(new SpinnerNumberModel(TMSCachedTileLoader.MAX_OBJECTS_ON_DISK.get().intValue(), 0, Integer.MAX_VALUE, 1));
    4546        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));
    4648
    4749        add(new JLabel(tr("Auto zoom by default: ")), GBC.std());
     
    7375        add(maxConcurrentDownloads, GBC.eol());
    7476
     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
    7582        add(new JLabel(tr("Maximum elements in disk cache: ")), GBC.std());
    7683        add(GBC.glue(5, 0), GBC.std());
     
    9198        this.maxElementsOnDisk.setValue(TMSCachedTileLoader.MAX_OBJECTS_ON_DISK.get());
    9299        this.maxConcurrentDownloads.setValue(TMSCachedTileLoaderJob.THREAD_LIMIT.get());
     100        this.maxDownloadsPerHost.setValue(TMSCachedTileLoaderJob.HOST_LIMIT.get());
    93101    }
    94102
     
    111119        TMSCachedTileLoader.MAX_OBJECTS_ON_DISK.put((Integer) this.maxElementsOnDisk.getValue());
    112120
    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();
    117124
    118125        if (!TMSLayer.PROP_TILECACHE_DIR.get().equals(this.tilecacheDir.getText())) {
Note: See TracChangeset for help on using the changeset viewer.