Changeset 15675 in josm for trunk/src


Ignore:
Timestamp:
2020-01-10T00:32:14+01:00 (5 years ago)
Author:
Don-vip
Message:

fix #18534 - better synchronization of image cache (patch by taylor.smock)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/tools/ImageProvider.java

    r15590 r15675  
    4545import java.util.TreeSet;
    4646import java.util.concurrent.CompletableFuture;
     47import java.util.concurrent.ConcurrentHashMap;
    4748import java.util.concurrent.ExecutorService;
    4849import java.util.concurrent.Executors;
     
    296297     * The icon cache
    297298     */
    298     private static final Map<String, ImageResource> cache = new HashMap<>();
     299    private static final Map<String, ImageResource> cache = new ConcurrentHashMap<>();
    299300
    300301    /**
     
    836837     */
    837838    public static void clearCache() {
    838         synchronized (cache) {
    839             cache.clear();
    840         }
     839        cache.clear();
    841840        synchronized (ROTATE_CACHE) {
    842841            ROTATE_CACHE.clear();
     
    856855     */
    857856    private ImageResource getIfAvailableImpl() {
    858         synchronized (cache) {
    859             // This method is called from different thread and modifying HashMap concurrently can result
    860             // for example in loops in map entries (ie freeze when such entry is retrieved)
    861 
    862             String prefix = isDisabled ? "dis:" : "";
    863             if (name.startsWith("data:")) {
    864                 String url = name;
    865                 ImageResource ir = cache.get(prefix+url);
    866                 if (ir != null) return ir;
    867                 ir = getIfAvailableDataUrl(url);
    868                 if (ir != null) {
    869                     cache.put(prefix+url, ir);
    870                 }
    871                 return ir;
    872             }
    873 
    874             ImageType type = Utils.hasExtension(name, "svg") ? ImageType.SVG : ImageType.OTHER;
    875 
    876             if (name.startsWith(HTTP_PROTOCOL) || name.startsWith(HTTPS_PROTOCOL)) {
    877                 String url = name;
    878                 ImageResource ir = cache.get(prefix+url);
    879                 if (ir != null) return ir;
    880                 ir = getIfAvailableHttp(url, type);
    881                 if (ir != null) {
    882                     cache.put(prefix+url, ir);
    883                 }
    884                 return ir;
    885             } else if (name.startsWith(WIKI_PROTOCOL)) {
    886                 ImageResource ir = cache.get(prefix+name);
    887                 if (ir != null) return ir;
    888                 ir = getIfAvailableWiki(name, type);
    889                 if (ir != null) {
    890                     cache.put(prefix+name, ir);
    891                 }
    892                 return ir;
    893             }
    894 
    895             if (subdir == null) {
    896                 subdir = "";
    897             } else if (!subdir.isEmpty() && !subdir.endsWith("/")) {
    898                 subdir += '/';
    899             }
    900             String[] extensions;
    901             if (name.indexOf('.') != -1) {
    902                 extensions = new String[] {""};
    903             } else {
    904                 extensions = new String[] {".png", ".svg"};
    905             }
    906             final int typeArchive = 0;
    907             final int typeLocal = 1;
    908             for (int place : new Integer[] {typeArchive, typeLocal}) {
    909                 for (String ext : extensions) {
    910 
    911                     if (".svg".equals(ext)) {
    912                         type = ImageType.SVG;
    913                     } else if (".png".equals(ext)) {
    914                         type = ImageType.OTHER;
     857        // This method is called from different thread and modifying HashMap concurrently can result
     858        // for example in loops in map entries (ie freeze when such entry is retrieved)
     859
     860        String prefix = isDisabled ? "dis:" : "";
     861        if (name.startsWith("data:")) {
     862            String url = name;
     863            ImageResource ir = cache.get(prefix + url);
     864            if (ir != null) return ir;
     865            ir = getIfAvailableDataUrl(url);
     866            if (ir != null) {
     867                cache.put(prefix + url, ir);
     868            }
     869            return ir;
     870        }
     871
     872        ImageType type = Utils.hasExtension(name, "svg") ? ImageType.SVG : ImageType.OTHER;
     873
     874        if (name.startsWith(HTTP_PROTOCOL) || name.startsWith(HTTPS_PROTOCOL)) {
     875            String url = name;
     876            ImageResource ir = cache.get(prefix + url);
     877            if (ir != null) return ir;
     878            ir = getIfAvailableHttp(url, type);
     879            if (ir != null) {
     880                cache.put(prefix + url, ir);
     881            }
     882            return ir;
     883        } else if (name.startsWith(WIKI_PROTOCOL)) {
     884            ImageResource ir = cache.get(prefix + name);
     885            if (ir != null) return ir;
     886            ir = getIfAvailableWiki(name, type);
     887            if (ir != null) {
     888                cache.put(prefix + name, ir);
     889            }
     890            return ir;
     891        }
     892
     893        if (subdir == null) {
     894            subdir = "";
     895        } else if (!subdir.isEmpty() && !subdir.endsWith("/")) {
     896            subdir += '/';
     897        }
     898        String[] extensions;
     899        if (name.indexOf('.') != -1) {
     900            extensions = new String[] {""};
     901        } else {
     902            extensions = new String[] {".png", ".svg"};
     903        }
     904        final int typeArchive = 0;
     905        final int typeLocal = 1;
     906        for (int place : new Integer[] {typeArchive, typeLocal}) {
     907            for (String ext : extensions) {
     908
     909                if (".svg".equals(ext)) {
     910                    type = ImageType.SVG;
     911                } else if (".png".equals(ext)) {
     912                    type = ImageType.OTHER;
     913                }
     914
     915                String fullName = subdir + name + ext;
     916                String cacheName = prefix + fullName;
     917                /* cache separately */
     918                if (dirs != null && !dirs.isEmpty()) {
     919                    cacheName = "id:" + id + ':' + fullName;
     920                    if (archive != null) {
     921                        cacheName += ':' + archive.getName();
    915922                    }
    916 
    917                     String fullName = subdir + name + ext;
    918                     String cacheName = prefix + fullName;
    919                     /* cache separately */
    920                     if (dirs != null && !dirs.isEmpty()) {
    921                         cacheName = "id:" + id + ':' + fullName;
    922                         if (archive != null) {
    923                             cacheName += ':' + archive.getName();
    924                         }
    925                     }
    926 
    927                     switch (place) {
    928                     case typeArchive:
    929                         if (archive != null) {
    930                             cacheName = "zip:"+archive.hashCode()+':'+cacheName;
    931                             ImageResource ir = cache.get(cacheName);
    932                             if (ir != null) return ir;
    933 
    934                             ir = getIfAvailableZip(fullName, archive, inArchiveDir, type);
    935                             if (ir != null) {
    936                                 cache.put(cacheName, ir);
    937                                 return ir;
    938                             }
    939                         }
    940                         break;
    941                     case typeLocal:
     923                }
     924
     925                switch (place) {
     926                case typeArchive:
     927                    if (archive != null) {
     928                        cacheName = "zip:" + archive.hashCode() + ':' + cacheName;
    942929                        ImageResource ir = cache.get(cacheName);
    943930                        if (ir != null) return ir;
    944931
    945                         // getImageUrl() does a ton of "stat()" calls and gets expensive
    946                         // and redundant when you have a whole ton of objects. So,
    947                         // index the cache by the name of the icon we're looking for
    948                         // and don't bother to create a URL unless we're actually creating the image.
    949                         URL path = getImageUrl(fullName);
    950                         if (path == null) {
    951                             continue;
    952                         }
    953                         ir = getIfAvailableLocalURL(path, type);
     932                        ir = getIfAvailableZip(fullName, archive, inArchiveDir, type);
    954933                        if (ir != null) {
    955934                            cache.put(cacheName, ir);
    956935                            return ir;
    957936                        }
    958                         break;
    959937                    }
    960                 }
    961             }
    962             return null;
    963         }
     938                    break;
     939                case typeLocal:
     940                    ImageResource ir = cache.get(cacheName);
     941                    if (ir != null) return ir;
     942
     943                    // getImageUrl() does a ton of "stat()" calls and gets expensive
     944                    // and redundant when you have a whole ton of objects. So,
     945                    // index the cache by the name of the icon we're looking for
     946                    // and don't bother to create a URL unless we're actually creating the image.
     947                    URL path = getImageUrl(fullName);
     948                    if (path == null) {
     949                        continue;
     950                    }
     951                    ir = getIfAvailableLocalURL(path, type);
     952                    if (ir != null) {
     953                        cache.put(cacheName, ir);
     954                        return ir;
     955                    }
     956                    break;
     957                }
     958            }
     959        }
     960        return null;
    964961    }
    965962
Note: See TracChangeset for help on using the changeset viewer.