wip coordinate resolver

master
Thomas Rudin 2018-12-17 16:02:05 +01:00
parent 7b5c4346b6
commit 51313efd99
9 changed files with 157 additions and 97 deletions

View File

@ -94,7 +94,7 @@ public class TileRenderer {
int x2 = mapblockInfo.x + (int)mapblockInfo.width;
int z1 = mapblockInfo.z;
int z2 = mapblockInfo.z + ((int)mapblockInfo.height * -1);
int z2 = (mapblockInfo.z *-1) + ((int)mapblockInfo.height);
long start = System.currentTimeMillis();
@ -117,7 +117,7 @@ public class TileRenderer {
}
if (firstResult.isEmpty()) {
logger.debug("Fail-fast, got zero mapblock count for x={}-{} z={}-{}", x1,x2, z1,z2);
logger.debug("Fail-fast, got zero mapblock count for x=({})-({}) z=({})-({})", x1,x2, z1,z2);
byte[] data = WhiteTile.getPNG();
@ -260,7 +260,7 @@ public class TileRenderer {
long diff = System.currentTimeMillis() - start;
logger.debug("Timings of cross-stitched tile X={} Y={} Zoom={}: render={} ms", tileX, tileY, zoom, diff);
logger.trace("Timings of cross-stitched tile X={} Y={} Zoom={}: render={} ms", tileX, tileY, zoom, diff);
cache.put(layer.id, tileX, tileY, zoom, data);
@ -314,6 +314,7 @@ public class TileRenderer {
long timingRender = 0;
if (!countList.isEmpty()) {
logger.debug("Rendering tile for mapblock: X={}, Z={}", mapblockX, mapblockZ);
blockRenderer.render(layer.from, layer.to, mapblockX, mapblockZ, graphics, 16);
now = System.currentTimeMillis();
@ -330,7 +331,7 @@ public class TileRenderer {
long timingBufferOutput = now - start;
logger.debug("Timings of tile X={} Y={} Zoom={}: setup={} ms, zeroCheck={} ms, render={} ms, output={} ms",
logger.trace("Timings of tile X={} Y={} Zoom={}: setup={} ms, zeroCheck={} ms, render={} ms, output={} ms",
tileX, tileY, zoom,
timingImageSetup, timingZeroCountCheck, timingRender, timingBufferOutput
);

View File

@ -106,12 +106,46 @@ public class UpdateChangedTilesJob implements Runnable {
private final Map<Integer, Long> timestampMap = new HashMap<>();
@Override
public void run() {
//Run without parsing summary
updateChangedTiles();
}
/**
* Execution summory of changed tiles
*/
public static class ChangedTilesResult {
public Map<Integer, Integer> renderedTilesPerLayer = new HashMap<>();
public Map<Integer, Integer> skippedTilesPerLayer = new HashMap<>();
public Map<Integer, Integer> changedBlocksPerLayer = new HashMap<>();
public double executionTime;
@Override
public String toString() {
return "ChangedTilesResult{" +
"renderedTilesPerLayer=" + renderedTilesPerLayer +
", skippedTilesPerLayer=" + skippedTilesPerLayer +
", changedBlocksPerLayer=" + changedBlocksPerLayer +
", executionTime=" + executionTime +
'}';
}
}
/**
* Updates the changed tiles and returns a summary of all actions
* @return
*/
public ChangedTilesResult updateChangedTiles(){
ChangedTilesResult result = new ChangedTilesResult();
if (running) {
//skip multiple invocations
return;
return result;
}
if (timestampMap.isEmpty()) {
@ -179,6 +213,10 @@ public class UpdateChangedTilesJob implements Runnable {
int count = blocks.size();
int invalidatedTiles = 0;
//internal summary
result.changedBlocksPerLayer.put(layer.id, count);
//prometheus
layerBlockQueryTimingGaugeMap.get(layer.id).set(queryTime);
layerBlockChangeGaugeMap.get(layer.id).set(count);
@ -207,32 +245,8 @@ public class UpdateChangedTilesJob implements Runnable {
logger.debug("Starting rendering of changed tiles");
//run with rendering of highest zoom level without cache
for (BlocksRecord record : blocks) {
Integer x = record.getPosx();
Integer z = record.getPosz();
TileInfo tileInfo = CoordinateResolver.fromCoordinates(x, z);
TileInfo zoomedTile = tileInfo.toZoom(CoordinateResolver.MAX_ZOOM);
String tileKey = getTileKey(zoomedTile);
logger.debug("Rendering tile x={} y={} zoom={}", zoomedTile.x, zoomedTile.y, zoomedTile.zoom);
tileRenderer.render(layer, zoomedTile.x, zoomedTile.y, zoomedTile.zoom, false); //render without cache
logger.debug("Dispatching tile-changed-event for tile: {}/{}", zoomedTile.x, zoomedTile.y);
EventBus.TileChangedEvent event = new EventBus.TileChangedEvent();
event.layerId = layer.id;
event.x = zoomedTile.x;
event.y = zoomedTile.y;
event.zoom = zoomedTile.zoom;
event.mapblockX = x;
event.mapblockZ = z;
eventBus.post(event);
}
int changedTileCount = 0;
int skippedTileCount = 0;
List<String> updatedTileKeys = new ArrayList<>();
@ -244,7 +258,7 @@ public class UpdateChangedTilesJob implements Runnable {
TileInfo tileInfo = CoordinateResolver.fromCoordinates(x, z);
for (int i = CoordinateResolver.MAX_ZOOM-1; i >= CoordinateResolver.MIN_ZOOM+2; i--) {
for (int i = CoordinateResolver.MAX_ZOOM; i >= CoordinateResolver.MIN_ZOOM+2; i--) {
TileInfo zoomedTile = tileInfo.toZoom(i);
String tileKey = getTileKey(zoomedTile);
@ -252,7 +266,7 @@ public class UpdateChangedTilesJob implements Runnable {
//Generate tiles now
logger.debug("Rendering tile x={} y={} zoom={}", zoomedTile.x, zoomedTile.y, zoomedTile.zoom);
tileRenderer.render(layer, zoomedTile.x, zoomedTile.y, zoomedTile.zoom, false); //render without cache
tileRenderer.render(layer, zoomedTile.x, zoomedTile.y, zoomedTile.zoom);
logger.debug("Dispatching tile-changed-event for tile: {}/{}", zoomedTile.x, zoomedTile.y);
@ -265,13 +279,21 @@ public class UpdateChangedTilesJob implements Runnable {
event.mapblockZ = z;
eventBus.post(event);
changedTileCount++;
updatedTileKeys.add(tileKey);
} else {
skippedTileCount++;
}
}
}
result.renderedTilesPerLayer.put(layer.id, changedTileCount);
result.skippedTilesPerLayer.put(layer.id, skippedTileCount);
final String msg = "Tile update job took {} ms for {} blocks in layer: '{}' (invalidated {} tiles)";
final Object[] params = new Object[]{
System.currentTimeMillis() - start,
@ -293,9 +315,10 @@ public class UpdateChangedTilesJob implements Runnable {
changedTiles.set(tileCount);
running = false;
timer.observeDuration();
result.executionTime = timer.observeDuration();
}
return result;
}
}

View File

@ -143,7 +143,25 @@ public class DatabaseTileCache implements TileCache {
} else {
//fallback
record.store();
TilesRecord existingRecord = ctx.selectFrom(TILES)
.where(TILES.X.eq(record.getX()))
.and(TILES.Y.eq(record.getY()))
.and(TILES.Z.eq(record.getZ()))
.and(TILES.LAYERID.eq(record.getLayerid()))
.fetchOne();
if (existingRecord != null){
//update
existingRecord.setTile(record.getTile());
existingRecord.setMtime(record.getMtime());
existingRecord.update();
} else {
//insert
record.insert();
}
}
}

View File

@ -8,7 +8,10 @@ public class CoordinateResolver {
public static final int MAX_ZOOM = 13;
public static final int MIN_ZOOM = 1;
public static final int ONE_TO_ONE_ZOOM = 13; // 1 tile == 1 mapblock
/**
* Tile information
*/
public static class TileInfo {
public int x, y;
public int zoom;
@ -31,8 +34,25 @@ public class CoordinateResolver {
return info;
}
@Override
public String toString() {
return "TileInfo{" +
"x=" + x +
", y=" + y +
", zoom=" + zoom +
", width=" + width +
", height=" + height +
'}';
}
}
/**
* Get tile coordinates from mapblock coords
* @param x
* @param z
* @return
*/
public static TileInfo fromCoordinates(int x, int z) {
TileInfo info = new TileInfo();
@ -48,6 +68,8 @@ public class CoordinateResolver {
public static class MapBlockCoordinateInfo {
public int x, z;
@Deprecated //area
public double width, height; //in map-blocks
@Override
@ -60,22 +82,35 @@ public class CoordinateResolver {
'}';
}
}
/*
* ...
* 7 == 0.25
* 8 == 0.5
* 9 == 1 (16x16 mapblocks)
* 10 == 2 (8x8 mapblocks)
* 11 == 4 (4x4 mapblocks)
* 12 == 8 (2x2 mapblocks)
* 13 == 16 (1 mapblock)
* ...
/**
* An area defined by two mapblock "points"
*/
public static double getZoomFactor(int zoom) {
return Math.pow(2, zoom - 9);
public static class MapBlockArea {
public MapBlockCoordinateInfo pos1, pos2;
}
public static MapBlockArea getMapBlockArea(int x, int y, int zoom){
MapBlockArea area = new MapBlockArea();
MapBlockCoordinateInfo pos1 = new MapBlockCoordinateInfo();
MapBlockCoordinateInfo pos2 = new MapBlockCoordinateInfo();
double factor = Math.pow(2, ONE_TO_ONE_ZOOM - zoom);
pos1.x = (int)(x * factor);
pos1.z = (int)((y-1) * factor * -1);
//TODO
area.pos1 = pos1;
area.pos2 = pos2;
return area;
}
@Deprecated
public static MapBlockCoordinateInfo fromTile(int x, int y, int zoom) {
MapBlockCoordinateInfo info = new MapBlockCoordinateInfo();
@ -96,7 +131,7 @@ public class CoordinateResolver {
// tile with 1:1 map resolution
info.x = (int)(x * factor);
info.z = (int)(y * factor * -1) - 1; //offset hack
info.z = (int)((y-1) * factor * -1);
info.height = factor;
info.width = factor;

View File

@ -175,12 +175,17 @@ Zoom: 8
public void testTileZoomIterate() {
TileInfo tileInfo = CoordinateResolver.fromCoordinates(32, -32);
for (int i=CoordinateResolver.MIN_ZOOM; i<=CoordinateResolver.MAX_ZOOM; i++) {
for (int i=CoordinateResolver.MAX_ZOOM; i>=CoordinateResolver.MIN_ZOOM; i--) {
TileInfo zoomedTile = tileInfo.toZoom(i);
System.out.println("Zoom: " + i + " x=" + zoomedTile.x + " y=" + zoomedTile.y + " width=" + zoomedTile.width);
MapBlockCoordinateInfo coordinateInfo = CoordinateResolver.fromTile(zoomedTile.x, zoomedTile.y, zoomedTile.zoom);
System.out.println("Zoom: " + i);
System.out.println("+Tile: " + zoomedTile);
System.out.println("+MapBlock: " + coordinateInfo);
}
}
}

View File

@ -8,9 +8,12 @@ import io.rudin.minetest.tileserver.job.UpdateChangedTilesJob;
import io.rudin.minetest.tileserver.qualifier.MapDB;
import io.rudin.minetest.tileserver.service.BlocksRecordService;
import io.rudin.minetest.tileserver.service.TileCache;
import io.rudin.minetest.tileserver.util.CoordinateResolver;
import org.jooq.DSLContext;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.io.IOException;
@ -25,28 +28,39 @@ public class UpdateChangedTilesTest extends TileServerTest {
@Inject TileCache tileCache;
@Inject @MapDB DSLContext ctx;
private static final Logger logger = LoggerFactory.getLogger(TileServerTest.class);
@Test
public void test() throws IOException {
byte[] tile = tileCache.get(0, 0, 1, 13);
final int mapblockX = 0;
final int mapblockZ = 0;
CoordinateResolver.TileInfo coordinates = CoordinateResolver.fromCoordinates(mapblockX, mapblockZ);
logger.debug("Mapblock X={} Z={} / Tile X={} Y={} Zoom={} Width={} Height={}",
mapblockX, mapblockZ,
coordinates.x, coordinates.y, coordinates.zoom, coordinates.width, coordinates.height);
byte[] tile = tileCache.get(0, coordinates.x, coordinates.y, 13);
Assert.assertNull(tile);
changedTilesJob.run();
logger.debug("First result: {}", changedTilesJob.updateChangedTiles());
tile = tileCache.get(0, 0, 1, 13);
tile = tileCache.get(0, coordinates.x, coordinates.y, 13);
Assert.assertNotNull(tile);
BlocksRecord block = ctx.selectFrom(BLOCKS)
.where(BLOCKS.POSX.eq(0).and(BLOCKS.POSY.eq(0).and(BLOCKS.POSZ.eq(0))))
.where(BLOCKS.POSX.eq(mapblockX).and(BLOCKS.POSY.eq(0).and(BLOCKS.POSZ.eq(mapblockZ))))
.fetchOne();
block.setMtime(System.currentTimeMillis());
block.update();
changedTilesJob.run();
logger.debug("Second result: {}", changedTilesJob.updateChangedTiles());
tile = tileCache.get(0, 0, 1, 13);
tile = tileCache.get(0, coordinates.x, coordinates.y, 13);
Assert.assertNotNull(tile);

View File

@ -3,22 +3,17 @@ package io.rudin.minetest.tileserver.base;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
import io.rudin.minetest.tileserver.DBMigration;
import io.rudin.minetest.tileserver.blockdb.tables.Blocks;
import io.rudin.minetest.tileserver.blockdb.tables.records.BlocksRecord;
import io.rudin.minetest.tileserver.config.TileServerConfig;
import io.rudin.minetest.tileserver.module.ConfigModule;
import io.rudin.minetest.tileserver.module.DBModule;
import io.rudin.minetest.tileserver.module.ServiceModule;
import io.rudin.minetest.tileserver.module.TestServiceModule;
import io.rudin.minetest.tileserver.qualifier.MapDB;
import io.rudin.minetest.tileserver.qualifier.TileDB;
import io.rudin.minetest.tileserver.util.StreamUtil;
import org.aeonbits.owner.ConfigFactory;
import org.jooq.DSLContext;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,32 +0,0 @@
package io.rudin.minetest.tileserver.module;
import com.google.inject.AbstractModule;
import io.rudin.minetest.tileserver.ColorTable;
import io.rudin.minetest.tileserver.config.LayerConfig;
import io.rudin.minetest.tileserver.config.TileServerConfig;
import io.rudin.minetest.tileserver.provider.ColorTableProvider;
import io.rudin.minetest.tileserver.provider.ExecutorProvider;
import io.rudin.minetest.tileserver.provider.LayerConfigProvider;
import io.rudin.minetest.tileserver.service.*;
import io.rudin.minetest.tileserver.service.impl.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
public class TestServiceModule extends AbstractModule {
@Override
protected void configure() {
bind(TileCache.class).to(FileTileCache.class);
bind(EventBus.class).to(EventBusImpl.class);
bind(ColorTable.class).toProvider(ColorTableProvider.class);
bind(ExecutorService.class).toProvider(ExecutorProvider.class);
bind(ScheduledExecutorService.class).toProvider(ExecutorProvider.class);
bind(LayerConfig.class).toProvider(LayerConfigProvider.class);
bind(MapBlockRenderService.class).to(DefaultMapBlockRenderService.class);
bind(BlocksRecordService.class).to(BlocksRecordDatabaseService.class);
}
}

View File

@ -10,6 +10,7 @@
<logger name="org.jooq.Constants" level="WARN"></logger>
<logger name="io.rudin.minetest.tileserver.TileRenderer" level="DEBUG"/>
<logger name="io.rudin.minetest" level="DEBUG"/>
<root level="info">
<appender-ref ref="console" />