use ehcache
This commit is contained in:
parent
fc518ee0ca
commit
24c015341b
8
pom.xml
8
pom.xml
@ -137,6 +137,14 @@
|
|||||||
<version>1.1.1</version>
|
<version>1.1.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Caching -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ehcache</groupId>
|
||||||
|
<artifactId>ehcache</artifactId>
|
||||||
|
<version>3.5.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -101,9 +101,8 @@ public class TileRenderer {
|
|||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
Integer count = ctx
|
Result<BlocksRecord> firstResult = ctx
|
||||||
.select(DSL.count())
|
.selectFrom(BLOCKS)
|
||||||
.from(BLOCKS)
|
|
||||||
.where(
|
.where(
|
||||||
BLOCKS.POSX.ge(Math.min(x1, x2))
|
BLOCKS.POSX.ge(Math.min(x1, x2))
|
||||||
.and(BLOCKS.POSX.le(Math.max(x1, x2)))
|
.and(BLOCKS.POSX.le(Math.max(x1, x2)))
|
||||||
@ -111,7 +110,8 @@ public class TileRenderer {
|
|||||||
.and(BLOCKS.POSZ.le(Math.max(z1, z2)))
|
.and(BLOCKS.POSZ.le(Math.max(z1, z2)))
|
||||||
.and(yCondition)
|
.and(yCondition)
|
||||||
)
|
)
|
||||||
.fetchOne(DSL.count());
|
.limit(1)
|
||||||
|
.fetch();
|
||||||
|
|
||||||
long diff = System.currentTimeMillis() - start;
|
long diff = System.currentTimeMillis() - start;
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ public class TileRenderer {
|
|||||||
logger.warn("white-count-query took {} ms", diff);
|
logger.warn("white-count-query took {} ms", diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
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();
|
byte[] data = WhiteTile.getPNG();
|
||||||
@ -293,15 +293,15 @@ public class TileRenderer {
|
|||||||
start = now;
|
start = now;
|
||||||
|
|
||||||
|
|
||||||
Integer count = ctx
|
Result<BlocksRecord> countList = ctx
|
||||||
.select(DSL.count())
|
.selectFrom(BLOCKS)
|
||||||
.from(BLOCKS)
|
|
||||||
.where(
|
.where(
|
||||||
BLOCKS.POSX.eq(mapblockX)
|
BLOCKS.POSX.eq(mapblockX)
|
||||||
.and(BLOCKS.POSZ.eq(mapblockZ))
|
.and(BLOCKS.POSZ.eq(mapblockZ))
|
||||||
.and(yCondition)
|
.and(yCondition)
|
||||||
)
|
)
|
||||||
.fetchOne(DSL.count());
|
.limit(1)
|
||||||
|
.fetch();
|
||||||
|
|
||||||
now = System.currentTimeMillis();
|
now = System.currentTimeMillis();
|
||||||
long timingZeroCountCheck = now - start;
|
long timingZeroCountCheck = now - start;
|
||||||
@ -314,7 +314,7 @@ public class TileRenderer {
|
|||||||
|
|
||||||
long timingRender = 0;
|
long timingRender = 0;
|
||||||
|
|
||||||
if (count > 0) {
|
if (!countList.isEmpty()) {
|
||||||
|
|
||||||
|
|
||||||
blockRenderer.render(mapblockX, mapblockZ, graphics, 16);
|
blockRenderer.render(mapblockX, mapblockZ, graphics, 16);
|
||||||
|
@ -42,6 +42,10 @@ public interface TileServerConfig extends Config {
|
|||||||
@DefaultValue("2")
|
@DefaultValue("2")
|
||||||
int playerUpdateInterval();
|
int playerUpdateInterval();
|
||||||
|
|
||||||
|
@Key("tile.route.reentrycount")
|
||||||
|
@DefaultValue("5000")
|
||||||
|
int tileRouteReentryCount();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Logging stuff
|
Logging stuff
|
||||||
*/
|
*/
|
||||||
@ -67,12 +71,13 @@ public interface TileServerConfig extends Config {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@Key("tile.cache.impl")
|
@Key("tile.cache.impl")
|
||||||
@DefaultValue("FILE")
|
@DefaultValue("EHCACHE")
|
||||||
CacheType tileCacheType();
|
CacheType tileCacheType();
|
||||||
|
|
||||||
enum CacheType {
|
enum CacheType {
|
||||||
DATABASE,
|
DATABASE,
|
||||||
FILE
|
FILE,
|
||||||
|
EHCACHE
|
||||||
}
|
}
|
||||||
|
|
||||||
@Key("tiles.directory")
|
@Key("tiles.directory")
|
||||||
|
@ -119,6 +119,12 @@ public class UpdateChangedTilesJob implements Runnable {
|
|||||||
int count = blocks.size();
|
int count = blocks.size();
|
||||||
int invalidatedTiles = 0;
|
int invalidatedTiles = 0;
|
||||||
|
|
||||||
|
long diff = start - System.currentTimeMillis();
|
||||||
|
|
||||||
|
if (diff > 1000 && cfg.logQueryPerformance()){
|
||||||
|
logger.warn("updated-tiles-query took {} ms", diff);
|
||||||
|
}
|
||||||
|
|
||||||
if (blocks.size() == LIMIT) {
|
if (blocks.size() == LIMIT) {
|
||||||
logger.warn("Got max-blocks ({}) from update-queue", LIMIT);
|
logger.warn("Got max-blocks ({}) from update-queue", LIMIT);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import com.zaxxer.hikari.HikariDataSource;
|
|||||||
|
|
||||||
public class DBModule extends AbstractModule {
|
public class DBModule extends AbstractModule {
|
||||||
|
|
||||||
public DBModule(TileServerConfig cfg) throws Exception {
|
public DBModule(TileServerConfig cfg) {
|
||||||
this.cfg = cfg;
|
this.cfg = cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ public class LoggingExecuteListener extends DefaultExecuteListener {
|
|||||||
super.executeEnd(ctx);
|
super.executeEnd(ctx);
|
||||||
if (watch.split() > 5_000_000_000L)
|
if (watch.split() > 5_000_000_000L)
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"Slow SQL",
|
"Slow SQL: " + ctx.sql(),
|
||||||
new SQLPerformanceWarning());
|
new SQLPerformanceWarning());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,14 @@ import io.rudin.minetest.tileserver.provider.ExecutorProvider;
|
|||||||
import io.rudin.minetest.tileserver.service.EventBus;
|
import io.rudin.minetest.tileserver.service.EventBus;
|
||||||
import io.rudin.minetest.tileserver.service.TileCache;
|
import io.rudin.minetest.tileserver.service.TileCache;
|
||||||
import io.rudin.minetest.tileserver.service.impl.DatabaseTileCache;
|
import io.rudin.minetest.tileserver.service.impl.DatabaseTileCache;
|
||||||
|
import io.rudin.minetest.tileserver.service.impl.EHTileCache;
|
||||||
import io.rudin.minetest.tileserver.service.impl.EventBusImpl;
|
import io.rudin.minetest.tileserver.service.impl.EventBusImpl;
|
||||||
import io.rudin.minetest.tileserver.service.impl.FileTileCache;
|
import io.rudin.minetest.tileserver.service.impl.FileTileCache;
|
||||||
import org.jooq.util.jaxb.Database;
|
import org.jooq.util.jaxb.Database;
|
||||||
|
|
||||||
public class ServiceModule extends AbstractModule {
|
public class ServiceModule extends AbstractModule {
|
||||||
|
|
||||||
public ServiceModule(TileServerConfig cfg) throws Exception {
|
public ServiceModule(TileServerConfig cfg) {
|
||||||
this.cfg = cfg;
|
this.cfg = cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,10 +31,13 @@ public class ServiceModule extends AbstractModule {
|
|||||||
|
|
||||||
if (cfg.tileCacheType() == TileServerConfig.CacheType.DATABASE)
|
if (cfg.tileCacheType() == TileServerConfig.CacheType.DATABASE)
|
||||||
bind(TileCache.class).to(DatabaseTileCache.class);
|
bind(TileCache.class).to(DatabaseTileCache.class);
|
||||||
|
|
||||||
|
else if (cfg.tileCacheType() == TileServerConfig.CacheType.EHCACHE)
|
||||||
|
bind(TileCache.class).to(EHTileCache.class);
|
||||||
|
|
||||||
else
|
else
|
||||||
bind(TileCache.class).to(FileTileCache.class);
|
bind(TileCache.class).to(FileTileCache.class);
|
||||||
|
|
||||||
//bind(TileCache.class).to(FileTileCache.class);
|
|
||||||
bind(EventBus.class).to(EventBusImpl.class);
|
bind(EventBus.class).to(EventBusImpl.class);
|
||||||
bind(ColorTable.class).toProvider(ColorTableProvider.class);
|
bind(ColorTable.class).toProvider(ColorTableProvider.class);
|
||||||
bind(ExecutorService.class).toProvider(ExecutorProvider.class);
|
bind(ExecutorService.class).toProvider(ExecutorProvider.class);
|
||||||
|
@ -15,6 +15,7 @@ import spark.Route;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class TileRoute implements Route {
|
public class TileRoute implements Route {
|
||||||
@ -25,12 +26,18 @@ public class TileRoute implements Route {
|
|||||||
public TileRoute(TileRenderer renderer, TileServerConfig cfg, TileCache cache) {
|
public TileRoute(TileRenderer renderer, TileServerConfig cfg, TileCache cache) {
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
|
this.cfg = cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final TileRenderer renderer;
|
private final TileRenderer renderer;
|
||||||
|
|
||||||
private final TileCache cache;
|
private final TileCache cache;
|
||||||
|
|
||||||
|
private final TileServerConfig cfg;
|
||||||
|
|
||||||
|
//TODO: proper rate limit
|
||||||
|
private final AtomicInteger entryCount = new AtomicInteger();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object handle(Request req, Response res) throws Exception {
|
public Object handle(Request req, Response res) throws Exception {
|
||||||
res.header("Content-Type", "image/png");
|
res.header("Content-Type", "image/png");
|
||||||
@ -46,7 +53,17 @@ public class TileRoute implements Route {
|
|||||||
|
|
||||||
logger.debug("Rendering tile @ {}/{} zoom: {}", x,y,z);
|
logger.debug("Rendering tile @ {}/{} zoom: {}", x,y,z);
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (entryCount.get() > cfg.tileRouteReentryCount()){
|
||||||
|
Thread.sleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
entryCount.incrementAndGet();
|
||||||
return renderer.render(x, y, z);
|
return renderer.render(x, y, z);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
entryCount.decrementAndGet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
package io.rudin.minetest.tileserver.service.impl;
|
||||||
|
|
||||||
|
import io.rudin.minetest.tileserver.config.TileServerConfig;
|
||||||
|
import io.rudin.minetest.tileserver.service.TileCache;
|
||||||
|
import org.ehcache.Cache;
|
||||||
|
import org.ehcache.PersistentCacheManager;
|
||||||
|
import org.ehcache.config.builders.CacheConfigurationBuilder;
|
||||||
|
import org.ehcache.config.builders.CacheManagerBuilder;
|
||||||
|
import org.ehcache.config.builders.ResourcePoolsBuilder;
|
||||||
|
import org.ehcache.config.units.EntryUnit;
|
||||||
|
import org.ehcache.config.units.MemoryUnit;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class EHTileCache implements TileCache {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public EHTileCache(TileServerConfig cfg){
|
||||||
|
this.cfg = cfg;
|
||||||
|
this.timestampMarker = new File(cfg.tileDirectory(), "timestampmarker-ehcache");
|
||||||
|
|
||||||
|
if (!timestampMarker.isFile()){
|
||||||
|
try (OutputStream output = new FileOutputStream(timestampMarker)){
|
||||||
|
output.write(0x00);
|
||||||
|
} catch (Exception e){
|
||||||
|
throw new IllegalArgumentException("could not create timestamp marker!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
timestampMarker.setLastModified(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
|
||||||
|
.with(CacheManagerBuilder.persistence(new File(cfg.tileDirectory(), "ehcache")))
|
||||||
|
.withCache("cache",
|
||||||
|
CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, byte[].class,
|
||||||
|
ResourcePoolsBuilder.newResourcePoolsBuilder()
|
||||||
|
.heap(10, MemoryUnit.MB)
|
||||||
|
.offheap(50, MemoryUnit.MB)
|
||||||
|
.disk(10, MemoryUnit.GB, true)
|
||||||
|
)
|
||||||
|
).build(true);
|
||||||
|
|
||||||
|
cache = persistentCacheManager.getCache("cache", String.class, byte[].class);
|
||||||
|
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(persistentCacheManager::close));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final File timestampMarker;
|
||||||
|
|
||||||
|
private final TileServerConfig cfg;
|
||||||
|
|
||||||
|
private final Cache<String, byte[]> cache;
|
||||||
|
|
||||||
|
private String getKey(int x, int y, int z){
|
||||||
|
//TODO: long key
|
||||||
|
return x + "/" + y + "/" + z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(int x, int y, int z, byte[] data) throws IOException {
|
||||||
|
cache.put(getKey(x,y,z), data);
|
||||||
|
timestampMarker.setLastModified(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] get(int x, int y, int z) throws IOException {
|
||||||
|
return cache.get(getKey(x,y,z));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean has(int x, int y, int z) {
|
||||||
|
return cache.containsKey(getKey(x,y,z));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(int x, int y, int z) {
|
||||||
|
cache.remove(getKey(x,y,z));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLatestTimestamp() {
|
||||||
|
return timestampMarker.lastModified();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user