Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions DynmapCore/src/main/java/org/dynmap/DynmapCore.java
Original file line number Diff line number Diff line change
Expand Up @@ -507,10 +507,6 @@ public boolean enableCore(EnableCoreCallbacks cb) {
authmgr = new WebAuthManager(this);
defaultStorage.setLoginEnabled(this);
}
// If storage serves web files, extract and publsh them
if (defaultStorage.needsStaticWebFiles()) {
updateStaticWebToStorage();
}
/* Load control for leaf transparency (spout lighting bug workaround) */
transparentLeaves = configuration.getBoolean("transparent-leaves", true);

Expand Down Expand Up @@ -632,6 +628,10 @@ public boolean enableCore(EnableCoreCallbacks cb) {

mapManager = new MapManager(this, configuration);
mapManager.startRendering();
// Network publication must not block the server startup thread.
if (defaultStorage.needsStaticWebFiles()) {
updateStaticWebToStorage();
}

if (markerapi != null) {
MarkerAPIImpl.completeInitializeMarkerAPI(markerapi);
Expand Down Expand Up @@ -2856,6 +2856,9 @@ private void updateStaticWebToStorage() {
return;
}
Log.info("Publishing web files to storage");
org.dynmap.utils.RetryingFileQueue publication = new org.dynmap.utils.RetryingFileQueue(
defaultStorage::setStaticWebFile, MapManager::scheduleDelayedJob,
name -> Log.severe("Web asset publication failed; retry queued: " + name));
/* Open JAR as ZIP */
ZipFile zf = null;
InputStream ins = null;
Expand All @@ -2882,7 +2885,7 @@ private void updateStaticWebToStorage() {
while ((len = ins.read(buf)) >= 0) {
buffer.write(buf, 0, len);
}
defaultStorage.setStaticWebFile(n, buffer);
publication.enqueue(n, buffer);
} catch(IOException io) {
Log.severe("Error updating file in storage - " + n, io);
} finally {
Expand Down
21 changes: 16 additions & 5 deletions DynmapCore/src/main/java/org/dynmap/DynmapWorld.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.dynmap.hdmap.TexturePack;
import org.dynmap.storage.MapStorage;
import org.dynmap.storage.MapStorageTile;
import org.dynmap.storage.StorageReadException;
import org.dynmap.utils.DynmapBufferedImage;
import org.dynmap.utils.ImageIOManager;
import org.dynmap.utils.MapChunkCache;
Expand Down Expand Up @@ -116,7 +117,10 @@ public void freshenZoomOutFiles() {
if(cancelled) return;
for (int varIdx = 0; varIdx < var.length; varIdx++) {
MapStorageTile tile = storage.getTile(this, mt, c.x, c.y, c.zoomlevel, var[varIdx]);
processZoomFile(mts, tile, varIdx == 0);
if (!processZoomFile(mts, tile, varIdx == 0)) {
// Accumulator is separate from this pass: no tight retry loop.
mts.setZoomOutInv(tile.x, tile.y, tile.zoom);
}
}
}
}
Expand All @@ -132,7 +136,7 @@ public void activateZoomOutFreshen() {

private static final int[] stepseq = { 3, 1, 2, 0 };

private void processZoomFile(MapTypeState mts, MapStorageTile tile, boolean firstVariant) {
private boolean processZoomFile(MapTypeState mts, MapStorageTile tile, boolean firstVariant) {
long mostRecentTimestamp = 0;
int step = 1 << tile.zoom;
MapStorageTile ztile = tile.getZoomOutTile();
Expand All @@ -148,6 +152,7 @@ private void processZoomFile(MapTypeState mts, MapStorageTile tile, boolean firs
/* create image buffer */
kzIm = DynmapBufferedImage.allocateBufferedImage(width, height);
zIm = kzIm.buf_img;
try {
for(int i = 0; i < 4; i++) {
boolean doblit = true;
int tx1 = tx + step * (1 & stepseq[i]);
Expand Down Expand Up @@ -236,22 +241,28 @@ private void processZoomFile(MapTypeState mts, MapStorageTile tile, boolean firs
try {
MapManager mm = MapManager.mapman;
if(mm == null)
return;
return false;
long crc = MapStorage.calculateImageHashCode(kzIm.argb_buf, 0, kzIm.argb_buf.length); /* Get hash of tile */
if(blank) {
if (ztile.exists()) {
ztile.delete();
if (!ztile.delete()) return false;
MapManager.mapman.pushUpdate(this, new Client.Tile(ztile.getURI()));
enqueueZoomOutUpdate(ztile);
}
}
else /* if (!ztile.matchesHashCode(crc)) */ {
ztile.write(crc, zIm, (mostRecentTimestamp == 0)? System.currentTimeMillis() : mostRecentTimestamp);
if (!ztile.write(crc, zIm, (mostRecentTimestamp == 0)? System.currentTimeMillis() : mostRecentTimestamp)) return false;
MapManager.mapman.pushUpdate(this, new Client.Tile(ztile.getURI()));
enqueueZoomOutUpdate(ztile);
}
} finally {
ztile.releaseWriteLock();
}
return true;
} catch (StorageReadException ex) {
Log.warning("Storage read failed; retaining zoom update for " + tile.getURI());
return false;
} finally {
DynmapBufferedImage.freeBufferedImage(kzIm);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.dynmap.storage.MapStorage;
import org.dynmap.utils.BufferInputStream;
import org.dynmap.utils.BufferOutputStream;
import org.dynmap.utils.RetryingFileQueue;
import org.dynmap.web.Json;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
Expand Down Expand Up @@ -50,69 +50,20 @@ public class JsonFileClientUpdateComponent extends ClientUpdateComponent {
private MapStorage storage;
private File baseStandaloneDir;

private static class FileToWrite {
String filename;
byte[] content;
boolean phpwrapper;
@Override
public boolean equals(Object o) {
if(o instanceof FileToWrite) {
return ((FileToWrite)o).filename.equals(this.filename);
}
return false;
}
}
private class FileProcessor implements Runnable {
public void run() {
while(true) {
FileToWrite f = null;
synchronized(lock) {
if(files_to_write.isEmpty() == false) {
f = files_to_write.removeFirst();
}
else {
pending = null;
return;
}
}
BufferOutputStream buf = null;
if (f.content != null) {
buf = new BufferOutputStream();
if(f.phpwrapper) {
buf.write("<?php /*\n".getBytes(cs_utf8));
}
buf.write(f.content);
if(f.phpwrapper) {
buf.write("\n*/ ?>\n".getBytes(cs_utf8));
}
}
if (!storage.setStandaloneFile(f.filename, buf)) {
Log.severe("Exception while writing JSON-file - " + f.filename);
}
}
}
}
private Object lock = new Object();
private FileProcessor pending;
private LinkedList<FileToWrite> files_to_write = new LinkedList<FileToWrite>();
private final RetryingFileQueue files = new RetryingFileQueue(
(name, content) -> storage.setStandaloneFile(name, content),
MapManager::scheduleDelayedJob,
name -> Log.severe("Exception while writing JSON-file - " + name + "; retry queued"));

private void enqueueFileWrite(String filename, byte[] content, boolean phpwrap) {
FileToWrite ftw = new FileToWrite();
ftw.filename = filename;
ftw.content = content;
ftw.phpwrapper = phpwrap;
synchronized(lock) {
boolean didadd = false;
if(pending == null) {
didadd = true;
pending = new FileProcessor();
}
files_to_write.remove(ftw);
files_to_write.add(ftw);
if(didadd) {
MapManager.scheduleDelayedJob(new FileProcessor(), 0);
}
BufferOutputStream buf = null;
if (content != null) {
buf = new BufferOutputStream();
if (phpwrap) buf.write("<?php /*\n".getBytes(cs_utf8));
buf.write(content);
if (phpwrap) buf.write("\n*/ ?>\n".getBytes(cs_utf8));
}
files.enqueue(filename, buf);
}

private static Charset cs_utf8 = Charset.forName("UTF-8");
Expand Down Expand Up @@ -274,9 +225,7 @@ private void generateConfigJS(DynmapCore core) {
MapManager.scheduleDelayedJob(new Runnable() {
public void run() {
if (core.getDefaultMapStorage().needsStaticWebFiles()) {
BufferOutputStream os = new BufferOutputStream();
os.write(outputBytes);
core.getDefaultMapStorage().setStaticWebFile("standalone/config.js", os);
enqueueFileWrite("config.js", outputBytes, false);
}
else {
File f = new File(baseStandaloneDir, "config.js");
Expand Down
11 changes: 11 additions & 0 deletions DynmapCore/src/main/java/org/dynmap/MapTypeState.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,17 @@ public void restoreZoomOut(List<List<String>> dat) {
}
zoomOutInvAccum.set(i, tf);
}
// A shutdown can interrupt the active pass. The next startZoomOutIter()
// replaces that pass with the accumulator, so retain both halves there.
for (int i = 0; i < zoomOutInv.size(); i++) {
TileFlags active = zoomOutInv.get(i);
if (active != null) {
TileFlags accumulated = zoomOutInvAccum.get(i);
if (accumulated == null) zoomOutInvAccum.set(i, active);
else accumulated.union(active);
zoomOutInv.set(i, null);
}
}
}
}

Expand Down
32 changes: 14 additions & 18 deletions DynmapCore/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java
Original file line number Diff line number Diff line change
Expand Up @@ -1402,19 +1402,17 @@ public boolean render(MapChunkCache cache, HDMapTile tile, String mapname) {
try {
if(mtile.matchesHashCode(crc) == false) {
/* Wrap buffer as buffered image */
if(rendered[i]) {
mtile.write(crc, im[i].buf_img, startTimestamp);
}
else {
mtile.delete();
tile_update = rendered[i] ? mtile.write(crc, im[i].buf_img, startTimestamp) : mtile.delete();
if (tile_update) {
MapManager.mapman.pushUpdate(tile.getDynmapWorld(), new Client.Tile(mtile.getURI()));
renderone = true;
} else {
world.getMapState(shaderstate[i].getMap()).invalidateTile(tile.tx, tile.ty);
}
MapManager.mapman.pushUpdate(tile.getDynmapWorld(), new Client.Tile(mtile.getURI()));
tile_update = true;
renderone = true;
}
else {
if(!rendered[i]) {
mtile.delete();
if (!mtile.delete()) world.getMapState(shaderstate[i].getMap()).invalidateTile(tile.tx, tile.ty);
}
}
} finally {
Expand All @@ -1433,19 +1431,17 @@ public boolean render(MapChunkCache cache, HDMapTile tile, String mapname) {
try {
if(mtile.matchesHashCode(crc) == false) {
/* Wrap buffer as buffered image */
if(rendered[i]) {
mtile.write(crc, dayim[i].buf_img, startTimestamp);
tile_update = rendered[i] ? mtile.write(crc, dayim[i].buf_img, startTimestamp) : mtile.delete();
if (tile_update) {
MapManager.mapman.pushUpdate(tile.getDynmapWorld(), new Client.Tile(mtile.getURI()));
renderone = true;
} else {
world.getMapState(shaderstate[i].getMap()).invalidateTile(tile.tx, tile.ty);
}
else {
mtile.delete();
}
MapManager.mapman.pushUpdate(tile.getDynmapWorld(), new Client.Tile(mtile.getURI()));
tile_update = true;
renderone = true;
}
else {
if(!rendered[i]) {
mtile.delete();
if (!mtile.delete()) world.getMapState(shaderstate[i].getMap()).invalidateTile(tile.tx, tile.ty);
}
}
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public abstract class MapStorage {
private static HashMap<String, Integer> filelocks = new HashMap<String, Integer>();
private static final Integer WRITELOCK = (-1);
protected File baseStandaloneDir;
protected boolean isShutdown;
protected volatile boolean isShutdown;

protected long serverID;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.dynmap.storage;

/** A failed read is not an absent tile: callers must preserve and retry the work. */
public class StorageReadException extends RuntimeException {
public StorageReadException(Throwable cause) { super(cause); }
}
Loading
Loading