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 825bb78 Add synchronization on netCDF reader for multi-threading.
825bb78 is described below
commit 825bb78f00575c8b2b71d557f6855f45f66c8fe3
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Mar 21 11:15:47 2019 +0100
Add synchronization on netCDF reader for multi-threading.
---
.../apache/sis/internal/netcdf/RasterResource.java | 73 +++++++++++++---------
.../org/apache/sis/storage/netcdf/NetcdfStore.java | 2 +-
2 files changed, 45 insertions(+), 30 deletions(-)
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/RasterResource.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/RasterResource.java
index b176279..0b3e6b8 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/RasterResource.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/RasterResource.java
@@ -129,15 +129,22 @@ public final class RasterResource extends
AbstractGridResource implements Resour
private final Path location;
/**
+ * The object to use for synchronization. For now we use a {@code
synchronized} statement,
+ * but it may be changed to {@link java.util.concurrent.locks.Lock} in a
future version.
+ */
+ private final Object lock;
+
+ /**
* Creates a new resource. All variables in the {@code data} list shall
have the same domain and the same grid geometry.
*
* @param decoder the implementation used for decoding the netCDF file.
* @param name the name for the resource.
* @param grid the grid geometry (size, CRS…) of the {@linkplain
#data} cube.
* @param bands the variables providing actual data. Shall contain at
least one variable.
+ * @param lock the lock to use in {@code synchronized(lock)}
statements.
*/
- private RasterResource(final Decoder decoder, final String name, final
GridGeometry grid, final List<Variable> bands)
- throws IOException, DataStoreException
+ private RasterResource(final Decoder decoder, final String name, final
GridGeometry grid, final List<Variable> bands,
+ final Object lock) throws IOException, DataStoreException
{
super(decoder.listeners);
data = bands.toArray(new Variable[bands.size()]);
@@ -145,6 +152,7 @@ public final class RasterResource extends
AbstractGridResource implements Resour
identifier = decoder.nameFactory.createLocalName(decoder.namespace,
name);
location = decoder.location;
gridGeometry = grid;
+ this.lock = lock;
switch (data[0].getDimension() - grid.getDimension()) {
case 0: {
// All dimensions are in the CRS. This is the usual case.
@@ -165,13 +173,16 @@ public final class RasterResource extends
AbstractGridResource implements Resour
/**
* Creates all grid coverage resources from the given decoder.
+ * This method shall be invoked in a method synchronized on {@link #lock}.
*
* @param decoder the implementation used for decoding the netCDF file.
+ * @param lock the lock to use in {@code synchronized(lock)}
statements.
* @return all grid coverage resources.
* @throws IOException if an I/O operation was required and failed.
* @throws DataStoreException if a logical error occurred.
*/
- public static List<Resource> create(final Decoder decoder) throws
IOException, DataStoreException {
+ public static List<Resource> create(final Decoder decoder, final Object
lock) throws IOException, DataStoreException {
+ assert Thread.holdsLock(lock);
final Variable[] variables = decoder.getVariables().clone();
// Needs a clone because may be modified.
final List<Variable> siblings = new ArrayList<>(4);
final List<Resource> resources = new ArrayList<>();
@@ -244,7 +255,7 @@ public final class RasterResource extends
AbstractGridResource implements Resour
}
}
}
- resources.add(new RasterResource(decoder, name.trim(), grid,
siblings));
+ resources.add(new RasterResource(decoder, name.trim(), grid,
siblings, lock));
siblings.clear();
}
return resources;
@@ -279,11 +290,13 @@ public final class RasterResource extends
AbstractGridResource implements Resour
public List<SampleDimension> getSampleDimensions() throws
DataStoreException {
SampleDimension.Builder builder = null;
try {
- for (int i=0; i<ranges.length; i++) {
- if (ranges[i] == null) {
- if (builder == null) builder = new
SampleDimension.Builder();
- ranges[i] = createSampleDimension(builder, data[i]);
- builder.clear();
+ synchronized (lock) {
+ for (int i=0; i<ranges.length; i++) {
+ if (ranges[i] == null) {
+ if (builder == null) builder = new
SampleDimension.Builder();
+ ranges[i] = createSampleDimension(builder, data[i]);
+ builder.clear();
+ }
}
}
} catch (TransformException e) {
@@ -439,27 +452,29 @@ public final class RasterResource extends
AbstractGridResource implements Resour
* seeking backward.
*/
Buffer values = null;
- for (int i=0; i<bands.length; i++) {
- final int r = rangeIndices.getSourceIndex(i);
// In strictly increasing order.
- final Variable variable = data[bandDimension >= 0 ? 0 : r];
// Only one variable if bandDimension ≧ 0.
- SampleDimension sd = ranges[r];
- if (sd == null) {
- ranges[r] = sd =
createSampleDimension(rangeIndices.builder(), variable);
- }
- if (bandDimension > 0) {
- // TODO: adjust 'areaOfInterest'.
- throw new UnsupportedOperationException();
- }
- if (bandDimension != 0 || values == null) {
- // Optional.orElseThrow() below should never fail since
Variable.read(…) wraps primitive array.
- values = variable.read(areaOfInterest,
subsamplings).buffer().get();
- }
- if (bandDimension == 0) {
- values.position(r);
+ synchronized (lock) {
+ for (int i=0; i<bands.length; i++) {
+ final int r = rangeIndices.getSourceIndex(i);
// In strictly increasing order.
+ final Variable variable = data[bandDimension >= 0 ? 0 :
r]; // Only one variable if bandDimension ≧ 0.
+ SampleDimension sd = ranges[r];
+ if (sd == null) {
+ ranges[r] = sd =
createSampleDimension(rangeIndices.builder(), variable);
+ }
+ if (bandDimension > 0) {
+ // TODO: adjust 'areaOfInterest'.
+ throw new UnsupportedOperationException();
+ }
+ if (bandDimension != 0 || values == null) {
+ // Optional.orElseThrow() below should never fail
since Variable.read(…) wraps primitive array.
+ values = variable.read(areaOfInterest,
subsamplings).buffer().get();
+ }
+ if (bandDimension == 0) {
+ values.position(r);
+ }
+ final int p = rangeIndices.getTargetIndex(i);
+ sampleValues[p] = values;
+ bands[p] = sd;
}
- final int p = rangeIndices.getTargetIndex(i);
- sampleValues[p] = values;
- bands[p] = sd;
}
domain = targetGeometry.subsample(scales).build();
imageBuffer = RasterFactory.wrap(dataType.rasterDataType,
sampleValues);
diff --git
a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
index f67c977..b01ed54 100644
---
a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
+++
b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
@@ -201,7 +201,7 @@ public class NetcdfStore extends DataStore implements
Aggregate {
public synchronized Collection<Resource> components() throws
DataStoreException {
if (components == null) try {
Resource[] resources = decoder.getDiscreteSampling();
- final List<Resource> grids = RasterResource.create(decoder);
+ final List<Resource> grids = RasterResource.create(decoder, this);
if (!grids.isEmpty()) {
grids.addAll(UnmodifiableArrayList.wrap(resources));
resources = grids.toArray(new Resource[grids.size()]);