Skip to content

Commit

Permalink
Replace long[] arrays by a TileIndex abstraction
Browse files Browse the repository at this point in the history
Dealing with `long[]` everywhere and knowing it means `{x,y,z}` is
tiring.

Introducing a `TileIndex` abstraction improves the semantics, and at the
same time allows to save memory on TileObject by storing the
coordinates as internal long,long,int fields and saving the object
reference to a `long` array.

---

> This is a **proposal**. Can we please stop using `long[]` everywhere?
> If accepted, there would be more places to get rid of `long` arrays
> and introduce higher level abstractions (e.g. `TileRangeInterator`)
  • Loading branch information
groldan committed Aug 27, 2024
1 parent 0d2fc0b commit 27e5d87
Show file tree
Hide file tree
Showing 46 changed files with 481 additions and 278 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.geowebcache.layer.ExpirationRule;
import org.geowebcache.mime.MimeException;
import org.geowebcache.mime.MimeType;
import org.geowebcache.storage.TileIndex;
import org.geowebcache.util.GWCVars;

/**
Expand Down Expand Up @@ -268,18 +269,18 @@ public ConveyorTile getTile(final ConveyorTile tile)

if (storageFormat.equals(CacheStorageInfo.COMPACT_FORMAT_CODE)
|| storageFormat.equals(CacheStorageInfo.COMPACT_FORMAT_CODE_V2)) {
final long[] tileIndex = tile.getTileIndex();
final TileIndex tileIndex = tile.getIndex();
final String gridSetId = tile.getGridSetId();
final GridSubset gridSubset = this.getGridSubset(gridSetId);

GridSet gridSet = gridSubset.getGridSet();
final int zoom = (int) tileIndex[2];
final int zoom = tileIndex.getZ();

Grid grid = gridSet.getGrid(zoom);
long coverageMaxY = grid.getNumTilesHigh() - 1;

final int col = (int) tileIndex[0];
final int row = (int) (coverageMaxY - tileIndex[1]);
final int col = (int) tileIndex.getX();
final int row = (int) (coverageMaxY - tileIndex.getY());

tileContent = compactCache.getBundleFileResource(zoom, row, col);

Expand All @@ -298,7 +299,7 @@ public ConveyorTile getTile(final ConveyorTile tile)
} else {
tile.setCacheResult(CacheResult.MISS);
if (!setLayerBlankTile(tile)) {
throw new OutsideCoverageException(tile.getTileIndex(), 0, 0);
throw new OutsideCoverageException(tile.getIndex().getZ(), 0, 0);
}
}

Expand Down Expand Up @@ -370,23 +371,23 @@ private boolean setLayerBlankTile(ConveyorTile tile) {
private String getTilePath(final ConveyorTile tile) {

final MimeType mimeType = tile.getMimeType();
final long[] tileIndex = tile.getTileIndex();
final TileIndex tileIndex = tile.getIndex();
final String gridSetId = tile.getGridSetId();
final GridSubset gridSubset = this.getGridSubset(gridSetId);

GridSet gridSet = gridSubset.getGridSet();
final int z = (int) tileIndex[2];
final int z = tileIndex.getZ();

Grid grid = gridSet.getGrid(z);

// long[] coverage = gridSubset.getCoverage(z);
// long coverageMinY = coverage[1];
long coverageMaxY = grid.getNumTilesHigh() - 1;

final long x = tileIndex[0];
final long x = tileIndex.getX();
// invert the order of the requested Y ordinate, since ArcGIS caches are top-left to
// bottom-right, and GWC computes tiles in bottom-left to top-right order
final long y = (coverageMaxY - tileIndex[1]);
final long y = (coverageMaxY - tileIndex.getY());

String level = (this.hexZoom) ? Integer.toHexString(z) : Integer.toString(z);
level = zeroPadder(level, 2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.geowebcache.mime.MimeType;
import org.geowebcache.storage.StorageBroker;
import org.geowebcache.storage.StorageException;
import org.geowebcache.storage.TileIndex;
import org.geowebcache.storage.TileObject;

/** Represents a request for a tile and carries the information needed to complete it. */
Expand Down Expand Up @@ -72,7 +73,7 @@ public ConveyorTile(
StorageBroker sb,
String layerId,
String gridSetId,
long[] tileIndex,
TileIndex tileIndex,
MimeType mimeType,
Map<String, String[]> fullParameters,
Map<String, String> filteringParameters,
Expand All @@ -95,7 +96,7 @@ public ConveyorTile(
StorageBroker sb,
String layerId,
String gridSetId,
long[] tileIndex,
TileIndex tileIndex,
MimeType mimeType,
Map<String, String> filteringParameters,
HttpServletRequest servletReq,
Expand All @@ -104,18 +105,11 @@ public ConveyorTile(
super(layerId, sb, servletReq, servletResp);
this.gridSetId = gridSetId;

long[] idx = new long[3];

if (tileIndex != null) {
idx[0] = tileIndex[0];
idx[1] = tileIndex[1];
idx[2] = tileIndex[2];
}

super.mimeType = mimeType;

this.filteringParameters = filteringParameters;

TileIndex idx = tileIndex == null ? null : TileIndex.copyOf(tileIndex);
stObj =
TileObject.createQueryTileObject(
layerId, idx, gridSetId, mimeType.getFormat(), filteringParameters);
Expand Down Expand Up @@ -180,6 +174,10 @@ public long[] getTileIndex() {
return stObj.getXYZ();
}

public TileIndex getIndex() {
return stObj.getIndex();
}

public synchronized GridSubset getGridSubset() {
if (gridSubset == null && gridSetId != null) {
gridSubset = tileLayer.getGridSubset(gridSetId);
Expand Down Expand Up @@ -248,7 +246,6 @@ public boolean retrieve(long maxAge) throws GeoWebCacheException {
public String toString() {
StringBuilder str = new StringBuilder();
str.append("ConveyorTile[");
long[] idx = stObj.getXYZ();

if (getLayerId() != null) {
str.append(getLayerId()).append(" ");
Expand All @@ -258,9 +255,7 @@ public String toString() {
str.append(gridSetId).append(" ");
}

if (idx != null && idx.length == 3) {
str.append("{" + idx[0] + "," + idx[1] + "," + idx[2] + "} ");
}
str.append("{" + stObj.getX() + "," + stObj.getY() + "," + stObj.getZ() + "} ");

if (this.mimeType != null) {
str.append(this.mimeType.getFormat());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.geowebcache.conveyor.ConveyorTile;
import org.geowebcache.grid.GridSubset;
import org.geowebcache.layer.TileLayer;
import org.geowebcache.storage.TileIndex;

/**
* This is a test filter for the new request filter core.
Expand All @@ -38,7 +39,8 @@ public void apply(ConveyorTile convTile) throws RequestFilterException {
// SRS srs = convTile.getSRS();
GridSubset gridSubset = tl.getGridSubset(convTile.getGridSetId());

int z = (int) convTile.getTileIndex()[2];
TileIndex tileIndex = convTile.getIndex();
int z = tileIndex.getZ();
long[] gridCoverage = gridSubset.getCoverage(z);

// Figure out the radius
Expand All @@ -58,8 +60,8 @@ public void apply(ConveyorTile convTile) throws RequestFilterException {
long midX = gridCoverage[0] + width / 2;
long midY = gridCoverage[1] + height / 2;

long xDist = midX - convTile.getTileIndex()[0];
long yDist = midY - convTile.getTileIndex()[1];
long xDist = midX - tileIndex.getX();
long yDist = midY - tileIndex.getY();

long rad = Math.round(Math.sqrt(xDist * xDist + yDist * yDist));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.geowebcache.grid.GridSubset;
import org.geowebcache.grid.OutsideCoverageException;
import org.geowebcache.layer.TileLayer;
import org.geowebcache.storage.TileIndex;

/**
* A raster filter allows to optimize data loading by avoiding the generation of requests and the
Expand Down Expand Up @@ -109,51 +110,54 @@ public void setDebug(Boolean debug) {

@Override
public void apply(ConveyorTile convTile) throws RequestFilterException {
long[] idx = convTile.getTileIndex().clone();
String gridSetId = convTile.getGridSetId();

// Basic bounds test first
try {
convTile.getGridSubset().checkCoverage(idx);
convTile.getGridSubset().checkCoverage(convTile.getIndex());
} catch (OutsideCoverageException oce) {
throw new BlankTileException(this);
}

long x = convTile.getIndex().getX();
long y = convTile.getIndex().getY();
int z = convTile.getIndex().getZ();
int zoomDiff = 0;

// Three scenarios below:
// 1. z is too low , upsample if resampling is enabled
// 2. z is within range, downsample one level and apply
// 3. z is too large , downsample
if (zoomStart != null && idx[2] < zoomStart) {
if (zoomStart != null && z < zoomStart) {
if (resample == null || !resample) {
// Filter does not apply, zoomlevel is too low
return;
} else {
// Upsample
zoomDiff = (int) (idx[2] - zoomStart);
idx[0] = idx[0] << (-1 * zoomDiff);
idx[1] = idx[1] << (-1 * zoomDiff);
idx[2] = zoomStart;
zoomDiff = z - zoomStart;
x = (x << (-1 * zoomDiff));
y = (y << (-1 * zoomDiff));
z = zoomStart;
}
} else if (idx[2] < zoomStop) {
} else if (z < zoomStop) {
// Sample one level higher
idx[0] = idx[0] * 2;
idx[1] = idx[1] * 2;
idx[2] = idx[2] + 1;
x = x * 2;
y = y * 2;
z = z + 1;
} else {
// Reduce to highest supported resolution
zoomDiff = (int) (idx[2] - zoomStop);
idx[0] = idx[0] >> zoomDiff;
idx[1] = idx[1] >> zoomDiff;
idx[2] = zoomStop;
zoomDiff = z - zoomStop;
x = x >> zoomDiff;
y = y >> zoomDiff;
z = zoomStop;
}

TileIndex idx = TileIndex.valueOf(x, y, z);
if (matrices == null
|| matrices.get(gridSetId) == null
|| matrices.get(gridSetId)[(int) idx[2]] == null) {
|| matrices.get(gridSetId)[idx.getZ()] == null) {
try {
setMatrix(convTile.getLayer(), gridSetId, (int) idx[2], false);
setMatrix(convTile.getLayer(), gridSetId, idx.getZ(), false);
} catch (Exception e) {
log.log(
Level.SEVERE,
Expand All @@ -162,14 +166,14 @@ public void apply(ConveyorTile convTile) throws RequestFilterException {
+ ", "
+ gridSetId
+ ", "
+ idx[2]
+ idx.getZ()
+ " : "
+ e.getMessage());
throw new RequestFilterException(
this,
500,
"Failed while trying to load filter for "
+ idx[2]
+ idx.getZ()
+ ", please check the logs");
}
}
Expand Down Expand Up @@ -229,14 +233,14 @@ public void initialize(TileLayer layer) throws GeoWebCacheException {
}

/** Performs a lookup against an internal raster. */
private boolean lookup(GridSubset grid, long[] idx) {
BufferedImage mat = matrices.get(grid.getName())[(int) idx[2]];
private boolean lookup(GridSubset grid, TileIndex idx) {
BufferedImage mat = matrices.get(grid.getName())[idx.getZ()];

long[] gridCoverage = grid.getCoverage((int) idx[2]);
long[] gridCoverage = grid.getCoverage(idx.getZ());

// Changing index to top left hand origin
long x = idx[0] - gridCoverage[0];
long y = gridCoverage[3] - idx[1];
long x = idx.getX() - gridCoverage[0];
long y = gridCoverage[3] - idx.getY();

return (mat.getRaster().getSample((int) x, (int) y, 0) == 0);
}
Expand All @@ -245,14 +249,14 @@ private boolean lookup(GridSubset grid, long[] idx) {
* Performs a lookup against an internal raster. The sampling is actually done against 4 pixels,
* idx should already have been modified to use one level higher than strictly necessary.
*/
private boolean lookupQuad(GridSubset grid, long[] idx) {
BufferedImage mat = matrices.get(grid.getName())[(int) idx[2]];
private boolean lookupQuad(GridSubset grid, TileIndex idx) {
BufferedImage mat = matrices.get(grid.getName())[idx.getZ()];

long[] gridCoverage = grid.getCoverage((int) idx[2]);
long[] gridCoverage = grid.getCoverage(idx.getZ());

// Changing index to top left hand origin
int baseX = (int) (idx[0] - gridCoverage[0]);
int baseY = (int) (gridCoverage[3] - idx[1]);
int baseX = (int) (idx.getX() - gridCoverage[0]);
int baseY = (int) (gridCoverage[3] - idx.getY());

int width = mat.getWidth();
int height = mat.getHeight();
Expand Down Expand Up @@ -298,16 +302,16 @@ private boolean lookupQuad(GridSubset grid, long[] idx) {
return hasData;
}

private boolean lookupSubsample(GridSubset grid, long[] idx, int zoomDiff) {
BufferedImage mat = matrices.get(grid.getName())[(int) idx[2]];
private boolean lookupSubsample(GridSubset grid, TileIndex idx, int zoomDiff) {
BufferedImage mat = matrices.get(grid.getName())[idx.getZ()];

int sampleChange = 1 << (-1 * zoomDiff);

long[] gridCoverage = grid.getCoverage((int) idx[2]);
long[] gridCoverage = grid.getCoverage(idx.getZ());

// Changing index to top left hand origin
int baseX = (int) (idx[0] - gridCoverage[0]);
int baseY = (int) (gridCoverage[3] - idx[1]);
int baseX = (int) (idx.getX() - gridCoverage[0]);
int baseY = (int) (gridCoverage[3] - idx.getY());

int width = mat.getWidth();
int height = mat.getHeight();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void checkSecurity(final ConveyorTile tile)
final BoundingBox bounds;
final SRS srs;
if (Objects.nonNull(gridSubset)) {
bounds = gridSubset.boundsFromIndex(tile.getTileIndex());
bounds = gridSubset.boundsFromIndex(tile.getIndex());
srs = gridSubset.getSRS();
} else {
bounds = null;
Expand Down
13 changes: 9 additions & 4 deletions geowebcache/core/src/main/java/org/geowebcache/grid/GridSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.geowebcache.config.Info;
import org.geowebcache.storage.TileIndex;

/** A grid set configuration */
public class GridSet implements Info {
Expand Down Expand Up @@ -110,15 +111,19 @@ void setResolutionsPreserved(boolean resolutionsPreserved) {
}

public BoundingBox boundsFromIndex(long[] tileIndex) {
final int tileZ = (int) tileIndex[2];
return boundsFromIndex(TileIndex.valueOf(tileIndex));
}

public BoundingBox boundsFromIndex(TileIndex tileIndex) {
final int tileZ = tileIndex.getZ();
Grid grid = getGrid(tileZ);

final long tileX = tileIndex[0];
final long tileX = tileIndex.getX();
final long tileY;
if (yBaseToggle) {
tileY = tileIndex[1] - grid.getNumTilesHigh();
tileY = tileIndex.getY() - grid.getNumTilesHigh();
} else {
tileY = tileIndex[1];
tileY = tileIndex.getY();
}

double width = grid.getResolution() * getTileWidth();
Expand Down
Loading

0 comments on commit 27e5d87

Please sign in to comment.