This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new e2fb98c  Prevent having many threads requesting the same tile.
e2fb98c is described below

commit e2fb98caff0f4ff79fbce8e26fd21bc431284f27
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Jan 25 19:10:04 2020 +0100

    Prevent having many threads requesting the same tile.
---
 .../java/org/apache/sis/gui/coverage/GridTile.java | 62 ++++++++++++++--------
 .../java/org/apache/sis/gui/coverage/GridView.java |  4 +-
 .../sis/internal/coverage/j2d/ImageUtilities.java  |  7 +++
 .../internal/coverage/j2d/ImageUtilitiesTest.java  |  8 +++
 4 files changed, 57 insertions(+), 24 deletions(-)

diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridTile.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridTile.java
index e9224d6..e9e2a4e 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridTile.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridTile.java
@@ -47,9 +47,15 @@ final class GridTile {
     Raster tile;
 
     /**
-     * Whether an error occurred while reading the tile.
+     * Non-null if an error occurred while reading the tile.
      */
-    boolean error;
+    Throwable error;
+
+    /**
+     * Whether a tile loading is in progress. Used for avoiding to create many 
threads requesting the same tile.
+     * If loading is in progress, other requests for that tile will return 
{@code null} immediately.
+     */
+    private boolean loading;
 
     /**
      * Creates a new tile for the given tile coordinates.
@@ -67,27 +73,41 @@ final class GridTile {
      * @param  view  the view for which to load a tile.
      */
     final void load(final GridView view) {
-        final RenderedImage image = view.getImage();
-        BackgroundThreads.execute(new Task<Raster>() {
-            /** Invoked in background thread for fetching the tile. */
-            @Override protected Raster call() {
-                return image.getTile(tileX, tileY);
-            }
+        if (!loading && error == null) {
+            loading = true;
+            final RenderedImage image = view.getImage();
+            BackgroundThreads.execute(new Task<Raster>() {
+                /** Invoked in background thread for fetching the tile. */
+                @Override protected Raster call() {
+                    return image.getTile(tileX, tileY);
+                }
 
-            /** Invoked in JavaFX thread on success. */
-            @Override protected void succeeded() {
-                super.succeeded();
-                tile = getValue();
-                error = false;
-                view.contentChanged(false);
-            }
+                /** Invoked in JavaFX thread on success. */
+                @Override protected void succeeded() {
+                    super.succeeded();
+                    tile    = getValue();
+                    error   = null;
+                    loading = false;
+                    view.contentChanged(false);
+                }
 
-            /** Invoked in JavaFX thread on failure. */
-            @Override protected void failed() {
-                super.failed();
-                error = true;
-            }
-        });
+                /** Invoked in JavaFX thread on failure. */
+                @Override protected void failed() {
+                    super.failed();
+                    tile    = null;
+                    error   = getException();
+                    loading = false;
+                }
+
+                /** Invoked in JavaFX thread on cancellation. */
+                @Override protected void cancelled() {
+                    super.cancelled();
+                    tile    = null;
+                    error   = null;
+                    loading = false;
+                }
+            });
+        }
     }
 
     /**
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
index 47e7c3b..ee5c8ca 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/gui/coverage/GridView.java
@@ -17,7 +17,6 @@
 package org.apache.sis.gui.coverage;
 
 import java.util.Map;
-import java.util.Arrays;
 import java.text.NumberFormat;
 import java.text.FieldPosition;
 import java.awt.image.Raster;
@@ -98,8 +97,7 @@ public class GridView extends Control {
      * since "real" caching is done by {@link 
org.apache.sis.image.ComputedImage}. The purpose of this cache is
      * to remember that a tile is immediately available and that we do not 
need to start a background thread.
      */
-    private final Map<GridTile,GridTile> tiles = new BoundedHashMap<>(10 * 
(1024 * 1024) /
-            (ImageUtilities.DEFAULT_TILE_SIZE * 
ImageUtilities.DEFAULT_TILE_SIZE));
+    private final Map<GridTile,GridTile> tiles = new 
BoundedHashMap<>(ImageUtilities.SUGGESTED_TILE_CACHE_SIZE);
 
     /**
      * The most recently used tile. Cached separately because it will be the 
desired tile in the vast majority
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
 
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
index 6afdb3d..67f397b 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageUtilities.java
@@ -53,6 +53,13 @@ public final class ImageUtilities extends Static {
     public static final int DEFAULT_TILE_SIZE = 256;
 
     /**
+     * Suggested size for a tile cache in number of tiles. This value can be 
used for very simple caching mechanism,
+     * keeping the most recently used tiles up to 10 Mb of memory. This is not 
for sophisticated caching mechanism;
+     * instead the "real" caching should be done by {@link 
org.apache.sis.image.ComputedImage}.
+     */
+    public static final int SUGGESTED_TILE_CACHE_SIZE = 10 * (1024 * 1024) / 
(DEFAULT_TILE_SIZE * DEFAULT_TILE_SIZE);
+
+    /**
      * Approximate size of the buffer to use for copying data from/to a 
raster, in bits.
      * The actual buffer size may be smaller or larger, depending on the 
actual tile size.
      * This value does not need to be very large. The current value is 8 kb.
diff --git 
a/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/j2d/ImageUtilitiesTest.java
 
b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/j2d/ImageUtilitiesTest.java
index 456d57f..cc90055 100644
--- 
a/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/j2d/ImageUtilitiesTest.java
+++ 
b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/j2d/ImageUtilitiesTest.java
@@ -40,6 +40,14 @@ import static org.junit.Assert.*;
  */
 public final strictfp class ImageUtilitiesTest extends TestCase {
     /**
+     * Verifies that {@link ImageUtilities#SUGGESTED_TILE_CACHE_SIZE} is 
strictly positive.
+     */
+    @Test
+    public void verifySuggestedTileCacheSize() {
+        assertTrue(ImageUtilities.SUGGESTED_TILE_CACHE_SIZE >= 1);
+    }
+
+    /**
      * Tests {@link ImageUtilities#getBounds(RenderedImage)} and {@link 
ImageUtilities#clipBounds(RenderedImage, Rectangle)}.
      */
     @Test

Reply via email to