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>
|
||||
</dependency>
|
||||
|
||||
<!-- Caching -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
<version>3.5.2</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -101,17 +101,17 @@ public class TileRenderer {
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Integer count = ctx
|
||||
.select(DSL.count())
|
||||
.from(BLOCKS)
|
||||
.where(
|
||||
BLOCKS.POSX.ge(Math.min(x1, x2))
|
||||
.and(BLOCKS.POSX.le(Math.max(x1, x2)))
|
||||
.and(BLOCKS.POSZ.ge(Math.min(z1, z2)))
|
||||
.and(BLOCKS.POSZ.le(Math.max(z1, z2)))
|
||||
.and(yCondition)
|
||||
)
|
||||
.fetchOne(DSL.count());
|
||||
Result<BlocksRecord> firstResult = ctx
|
||||
.selectFrom(BLOCKS)
|
||||
.where(
|
||||
BLOCKS.POSX.ge(Math.min(x1, x2))
|
||||
.and(BLOCKS.POSX.le(Math.max(x1, x2)))
|
||||
.and(BLOCKS.POSZ.ge(Math.min(z1, z2)))
|
||||
.and(BLOCKS.POSZ.le(Math.max(z1, z2)))
|
||||
.and(yCondition)
|
||||
)
|
||||
.limit(1)
|
||||
.fetch();
|
||||
|
||||
long diff = System.currentTimeMillis() - start;
|
||||
|
||||
@ -119,7 +119,7 @@ public class TileRenderer {
|
||||
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);
|
||||
|
||||
byte[] data = WhiteTile.getPNG();
|
||||
@ -293,15 +293,15 @@ public class TileRenderer {
|
||||
start = now;
|
||||
|
||||
|
||||
Integer count = ctx
|
||||
.select(DSL.count())
|
||||
.from(BLOCKS)
|
||||
Result<BlocksRecord> countList = ctx
|
||||
.selectFrom(BLOCKS)
|
||||
.where(
|
||||
BLOCKS.POSX.eq(mapblockX)
|
||||
.and(BLOCKS.POSZ.eq(mapblockZ))
|
||||
.and(yCondition)
|
||||
)
|
||||
.fetchOne(DSL.count());
|
||||
.limit(1)
|
||||
.fetch();
|
||||
|
||||
now = System.currentTimeMillis();
|
||||
long timingZeroCountCheck = now - start;
|
||||
@ -314,7 +314,7 @@ public class TileRenderer {
|
||||
|
||||
long timingRender = 0;
|
||||
|
||||
if (count > 0) {
|
||||
if (!countList.isEmpty()) {
|
||||
|
||||
|
||||
blockRenderer.render(mapblockX, mapblockZ, graphics, 16);
|
||||
|
@ -42,6 +42,10 @@ public interface TileServerConfig extends Config {
|
||||
@DefaultValue("2")
|
||||
int playerUpdateInterval();
|
||||
|
||||
@Key("tile.route.reentrycount")
|
||||
@DefaultValue("5000")
|
||||
int tileRouteReentryCount();
|
||||
|
||||
/*
|
||||
Logging stuff
|
||||
*/
|
||||
@ -67,12 +71,13 @@ public interface TileServerConfig extends Config {
|
||||
*/
|
||||
|
||||
@Key("tile.cache.impl")
|
||||
@DefaultValue("FILE")
|
||||
@DefaultValue("EHCACHE")
|
||||
CacheType tileCacheType();
|
||||
|
||||
enum CacheType {
|
||||
DATABASE,
|
||||
FILE
|
||||
FILE,
|
||||
EHCACHE
|
||||
}
|
||||
|
||||
@Key("tiles.directory")
|
||||
|
@ -119,6 +119,12 @@ public class UpdateChangedTilesJob implements Runnable {
|
||||
int count = blocks.size();
|
||||
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) {
|
||||
logger.warn("Got max-blocks ({}) from update-queue", LIMIT);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
public class DBModule extends AbstractModule {
|
||||
|
||||
public DBModule(TileServerConfig cfg) throws Exception {
|
||||
public DBModule(TileServerConfig cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ public class LoggingExecuteListener extends DefaultExecuteListener {
|
||||
super.executeEnd(ctx);
|
||||
if (watch.split() > 5_000_000_000L)
|
||||
logger.warn(
|
||||
"Slow SQL",
|
||||
"Slow SQL: " + ctx.sql(),
|
||||
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.TileCache;
|
||||
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.FileTileCache;
|
||||
import org.jooq.util.jaxb.Database;
|
||||
|
||||
public class ServiceModule extends AbstractModule {
|
||||
|
||||
public ServiceModule(TileServerConfig cfg) throws Exception {
|
||||
public ServiceModule(TileServerConfig cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
@ -30,10 +31,13 @@ public class ServiceModule extends AbstractModule {
|
||||
|
||||
if (cfg.tileCacheType() == TileServerConfig.CacheType.DATABASE)
|
||||
bind(TileCache.class).to(DatabaseTileCache.class);
|
||||
|
||||
else if (cfg.tileCacheType() == TileServerConfig.CacheType.EHCACHE)
|
||||
bind(TileCache.class).to(EHTileCache.class);
|
||||
|
||||
else
|
||||
bind(TileCache.class).to(FileTileCache.class);
|
||||
|
||||
//bind(TileCache.class).to(FileTileCache.class);
|
||||
bind(EventBus.class).to(EventBusImpl.class);
|
||||
bind(ColorTable.class).toProvider(ColorTableProvider.class);
|
||||
bind(ExecutorService.class).toProvider(ExecutorProvider.class);
|
||||
|
@ -15,6 +15,7 @@ import spark.Route;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Singleton
|
||||
public class TileRoute implements Route {
|
||||
@ -25,12 +26,18 @@ public class TileRoute implements Route {
|
||||
public TileRoute(TileRenderer renderer, TileServerConfig cfg, TileCache cache) {
|
||||
this.renderer = renderer;
|
||||
this.cache = cache;
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
private final TileRenderer renderer;
|
||||
|
||||
private final TileCache cache;
|
||||
|
||||
private final TileServerConfig cfg;
|
||||
|
||||
//TODO: proper rate limit
|
||||
private final AtomicInteger entryCount = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public Object handle(Request req, Response res) throws Exception {
|
||||
res.header("Content-Type", "image/png");
|
||||
@ -46,7 +53,17 @@ public class TileRoute implements Route {
|
||||
|
||||
logger.debug("Rendering tile @ {}/{} zoom: {}", x,y,z);
|
||||
|
||||
return renderer.render(x, y, z);
|
||||
try {
|
||||
while (entryCount.get() > cfg.tileRouteReentryCount()){
|
||||
Thread.sleep(50);
|
||||
}
|
||||
|
||||
entryCount.incrementAndGet();
|
||||
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