Add save/resume support for fullrender/radiusrender jobs
This commit is contained in:
parent
472129b11f
commit
74cefd899b
2 changed files with 134 additions and 10 deletions
|
|
@ -165,7 +165,7 @@ public class MapManager {
|
||||||
long timeaccum;
|
long timeaccum;
|
||||||
HashSet<MapType> renderedmaps = new HashSet<MapType>();
|
HashSet<MapType> renderedmaps = new HashSet<MapType>();
|
||||||
String activemaps;
|
String activemaps;
|
||||||
List<String> activemaplist;
|
int activemapcnt;
|
||||||
/* Min and max limits for chunk coords (for radius limit) */
|
/* Min and max limits for chunk coords (for radius limit) */
|
||||||
int cxmin, cxmax, czmin, czmax;
|
int cxmin, cxmax, czmin, czmax;
|
||||||
String rendertype;
|
String rendertype;
|
||||||
|
|
@ -209,6 +209,99 @@ public class MapManager {
|
||||||
cxmax = czmax = Integer.MAX_VALUE;
|
cxmax = czmax = Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FullWorldRenderState(ConfigurationNode n) throws Exception {
|
||||||
|
String w = n.getString("world", "");
|
||||||
|
world = getWorld(w);
|
||||||
|
if(world == null) throw new Exception();
|
||||||
|
loc = new Location(world.world, n.getDouble("locX", 0.0), n.getDouble("locY", 0.0), n.getDouble("locZ", 0.0));
|
||||||
|
String m = n.getString("map","");
|
||||||
|
map_index = n.getInteger("mapindex", -1);
|
||||||
|
map = world.maps.get(map_index);
|
||||||
|
if((map == null) || (map.getName().equals(m) == false)) throw new Exception();
|
||||||
|
found = new TileFlags();
|
||||||
|
List<String> sl = n.getStrings("found", null);
|
||||||
|
if(sl != null)
|
||||||
|
found.load(sl);
|
||||||
|
rendered = new TileFlags();
|
||||||
|
sl = n.getStrings("rendered", null);
|
||||||
|
if(sl != null)
|
||||||
|
rendered.load(sl);
|
||||||
|
renderQueue = new LinkedList<MapTile>();
|
||||||
|
List<ConfigurationNode> tl = n.getNodes("queue");
|
||||||
|
if(tl != null) {
|
||||||
|
for(ConfigurationNode cn : tl) {
|
||||||
|
MapTile mt = MapTile.restoreTile(world, cn);
|
||||||
|
if(mt != null) {
|
||||||
|
renderQueue.add(mt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rendercnt = n.getInteger("count", 0);
|
||||||
|
timeaccum = n.getInteger("timeaccum", 0);
|
||||||
|
renderedmaps = new HashSet<MapType>();
|
||||||
|
sl = n.getStrings("renderedmaps", null);
|
||||||
|
if(sl != null) {
|
||||||
|
for(String s : sl) {
|
||||||
|
for(int i = 0; i < world.maps.size(); i++) {
|
||||||
|
MapType mt = world.maps.get(i);
|
||||||
|
if(mt.getName().equals(s)) {
|
||||||
|
renderedmaps.add(mt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(sl.size() > renderedmaps.size()) { /* Missed one or more? */
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activemaps = n.getString("activemaps", "");
|
||||||
|
activemapcnt = n.getInteger("activemapcnt", 0);
|
||||||
|
cxmin = n.getInteger("cxmin", 0);
|
||||||
|
cxmax = n.getInteger("cxmax", 0);
|
||||||
|
czmin = n.getInteger("czmin", 0);
|
||||||
|
czmax = n.getInteger("czmax", 0);
|
||||||
|
rendertype = n.getString("rendertype", "");
|
||||||
|
mapname = n.getString("mapname", "");
|
||||||
|
sender = plug_in.getServer().getConsoleSender();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String,Object> saveState() {
|
||||||
|
HashMap<String,Object> v = new HashMap<String,Object>();
|
||||||
|
|
||||||
|
v.put("world", world.world.getName());
|
||||||
|
v.put("locX", loc.getX());
|
||||||
|
v.put("locY", loc.getY());
|
||||||
|
v.put("locZ", loc.getZ());
|
||||||
|
v.put("mapindex", map_index);
|
||||||
|
v.put("map", map.getName());
|
||||||
|
v.put("found", found.save());
|
||||||
|
v.put("rendered", rendered.save());
|
||||||
|
LinkedList<ConfigurationNode> queue = new LinkedList<ConfigurationNode>();
|
||||||
|
for(MapTile tq : renderQueue) {
|
||||||
|
ConfigurationNode n = tq.saveTile();
|
||||||
|
if(n != null)
|
||||||
|
queue.add(n);
|
||||||
|
}
|
||||||
|
v.put("queue", queue);
|
||||||
|
v.put("count", rendercnt);
|
||||||
|
v.put("timeaccum", timeaccum);
|
||||||
|
LinkedList<String> rmaps = new LinkedList<String>();
|
||||||
|
for(MapType mt : renderedmaps) {
|
||||||
|
rmaps.add(mt.getName());
|
||||||
|
}
|
||||||
|
v.put("renderedmaps", rmaps);
|
||||||
|
v.put("activemaps", activemaps);
|
||||||
|
v.put("activemapcnt", activemapcnt);
|
||||||
|
v.put("cxmin", cxmin);
|
||||||
|
v.put("cxmax", cxmax);
|
||||||
|
v.put("czmin", czmin);
|
||||||
|
v.put("czmax", czmax);
|
||||||
|
v.put("rendertype", rendertype);
|
||||||
|
v.put("mapname", mapname);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "world=" + world.world.getName() + ", map=" + map;
|
return "world=" + world.world.getName() + ", map=" + map;
|
||||||
}
|
}
|
||||||
|
|
@ -233,8 +326,8 @@ public class MapManager {
|
||||||
/* If render queue is empty, start next map */
|
/* If render queue is empty, start next map */
|
||||||
if(renderQueue.isEmpty()) {
|
if(renderQueue.isEmpty()) {
|
||||||
if(map_index >= 0) { /* Finished a map? */
|
if(map_index >= 0) { /* Finished a map? */
|
||||||
double msecpertile = (double)timeaccum / (double)((rendercnt>0)?rendercnt:1)/(double)activemaplist.size();
|
double msecpertile = (double)timeaccum / (double)((rendercnt>0)?rendercnt:1)/(double)activemapcnt;
|
||||||
if(activemaplist.size() > 1)
|
if(activemapcnt > 1)
|
||||||
sender.sendMessage(rendertype + " of maps [" + activemaps + "] of '" +
|
sender.sendMessage(rendertype + " of maps [" + activemaps + "] of '" +
|
||||||
world.world.getName() + "' completed - " + rendercnt + " tiles rendered each (" + String.format("%.2f", msecpertile) + " msec/map-tile).");
|
world.world.getName() + "' completed - " + rendercnt + " tiles rendered each (" + String.format("%.2f", msecpertile) + " msec/map-tile).");
|
||||||
else
|
else
|
||||||
|
|
@ -266,17 +359,20 @@ public class MapManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
map = world.maps.get(map_index);
|
map = world.maps.get(map_index);
|
||||||
activemaplist = map.getMapNamesSharingRender(world);
|
List<String> activemaplist = map.getMapNamesSharingRender(world);
|
||||||
/* Build active map list */
|
/* Build active map list */
|
||||||
activemaps = "";
|
activemaps = "";
|
||||||
if(mapname != null) {
|
if(mapname != null) {
|
||||||
activemaps = mapname;
|
activemaps = mapname;
|
||||||
|
activemapcnt = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
activemapcnt = 0;
|
||||||
for(String n : activemaplist) {
|
for(String n : activemaplist) {
|
||||||
if(activemaps.length() > 0)
|
if(activemaps.length() > 0)
|
||||||
activemaps += ",";
|
activemaps += ",";
|
||||||
activemaps += n;
|
activemaps += n;
|
||||||
|
activemapcnt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Mark all the concurrently rendering maps rendered */
|
/* Mark all the concurrently rendering maps rendered */
|
||||||
|
|
@ -428,8 +524,8 @@ public class MapManager {
|
||||||
rendercnt++;
|
rendercnt++;
|
||||||
timeaccum += System.currentTimeMillis() - tstart;
|
timeaccum += System.currentTimeMillis() - tstart;
|
||||||
if((rendercnt % progressinterval) == 0) {
|
if((rendercnt % progressinterval) == 0) {
|
||||||
double msecpertile = (double)timeaccum / (double)rendercnt / (double)activemaplist.size();
|
double msecpertile = (double)timeaccum / (double)rendercnt / (double)activemapcnt;
|
||||||
if(activemaplist.size() > 1)
|
if(activemapcnt > 1)
|
||||||
sender.sendMessage(rendertype + " of maps [" + activemaps + "] of '" +
|
sender.sendMessage(rendertype + " of maps [" + activemaps + "] of '" +
|
||||||
w.getName() + "' in progress - " + rendercnt + " tiles rendered each (" + String.format("%.2f", msecpertile) + " msec/map-tile).");
|
w.getName() + "' in progress - " + rendercnt + " tiles rendered each (" + String.format("%.2f", msecpertile) + " msec/map-tile).");
|
||||||
else
|
else
|
||||||
|
|
@ -716,7 +812,8 @@ public class MapManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadPending(DynmapWorld w) {
|
private void loadPending(DynmapWorld w) {
|
||||||
File f = new File(plug_in.getDataFolder(), w.world.getName() + ".pending");
|
String wname = w.world.getName();
|
||||||
|
File f = new File(plug_in.getDataFolder(), wname + ".pending");
|
||||||
if(f.exists()) {
|
if(f.exists()) {
|
||||||
org.bukkit.util.config.Configuration saved = new org.bukkit.util.config.Configuration(f);
|
org.bukkit.util.config.Configuration saved = new org.bukkit.util.config.Configuration(f);
|
||||||
saved.load();
|
saved.load();
|
||||||
|
|
@ -733,8 +830,19 @@ public class MapManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(cnt > 0)
|
if(cnt > 0)
|
||||||
Log.info("Loaded " + cnt + " pending tile renders for world '" + w.world.getName());
|
Log.info("Loaded " + cnt + " pending tile renders for world '" + wname);
|
||||||
}
|
}
|
||||||
|
/* Get saved render job, if any */
|
||||||
|
ConfigurationNode job = cn.getNode("job");
|
||||||
|
if(job != null) {
|
||||||
|
try {
|
||||||
|
FullWorldRenderState j = new FullWorldRenderState(job);
|
||||||
|
active_renders.put(wname, j);
|
||||||
|
} catch (Exception x) {
|
||||||
|
Log.info("Unable to restore render job for world '" + wname + "' - map configuration changed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
f.delete(); /* And clean it up */
|
f.delete(); /* And clean it up */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -742,6 +850,7 @@ public class MapManager {
|
||||||
private void savePending() {
|
private void savePending() {
|
||||||
List<MapTile> mt = tileQueue.popAll();
|
List<MapTile> mt = tileQueue.popAll();
|
||||||
for(DynmapWorld w : worlds) {
|
for(DynmapWorld w : worlds) {
|
||||||
|
boolean dosave = false;
|
||||||
File f = new File(plug_in.getDataFolder(), w.world.getName() + ".pending");
|
File f = new File(plug_in.getDataFolder(), w.world.getName() + ".pending");
|
||||||
org.bukkit.util.config.Configuration saved = new org.bukkit.util.config.Configuration(f);
|
org.bukkit.util.config.Configuration saved = new org.bukkit.util.config.Configuration(f);
|
||||||
ArrayList<ConfigurationNode> savedtiles = new ArrayList<ConfigurationNode>();
|
ArrayList<ConfigurationNode> savedtiles = new ArrayList<ConfigurationNode>();
|
||||||
|
|
@ -754,6 +863,16 @@ public class MapManager {
|
||||||
}
|
}
|
||||||
if(savedtiles.size() > 0) { /* Something to save? */
|
if(savedtiles.size() > 0) { /* Something to save? */
|
||||||
saved.setProperty("tiles", savedtiles);
|
saved.setProperty("tiles", savedtiles);
|
||||||
|
dosave = true;
|
||||||
|
Log.info("Saved " + savedtiles.size() + " pending tile renders in world '" + w.world.getName());
|
||||||
|
}
|
||||||
|
FullWorldRenderState job = active_renders.get(w.world.getName());
|
||||||
|
if(job != null) {
|
||||||
|
saved.setProperty("job", job.saveState());
|
||||||
|
dosave = true;
|
||||||
|
Log.info("Saved active render job in world '" + w.world.getName());
|
||||||
|
}
|
||||||
|
if(dosave) {
|
||||||
saved.save();
|
saved.save();
|
||||||
Log.info("Saved " + savedtiles.size() + " pending tile renders in world '" + w.world.getName());
|
Log.info("Saved " + savedtiles.size() + " pending tile renders in world '" + w.world.getName());
|
||||||
}
|
}
|
||||||
|
|
@ -809,6 +928,11 @@ public class MapManager {
|
||||||
render_pool = new DynmapScheduledThreadPoolExecutor();
|
render_pool = new DynmapScheduledThreadPoolExecutor();
|
||||||
scheduleDelayedJob(new DoZoomOutProcessing(), 60000);
|
scheduleDelayedJob(new DoZoomOutProcessing(), 60000);
|
||||||
scheduleDelayedJob(new CheckWorldTimes(), 5000);
|
scheduleDelayedJob(new CheckWorldTimes(), 5000);
|
||||||
|
/* Resume pending jobs */
|
||||||
|
for(FullWorldRenderState job : active_renders.values()) {
|
||||||
|
scheduleDelayedJob(job, 5000);
|
||||||
|
Log.info("Resumed render starting on world '" + job.world.world.getName() + "'...");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopRendering() {
|
public void stopRendering() {
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ public class TileFlags {
|
||||||
ArrayList<String> v = new ArrayList<String>();
|
ArrayList<String> v = new ArrayList<String>();
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for(Map.Entry<Long, long[]> ent : chunkmap.entrySet()) {
|
for(Map.Entry<Long, long[]> ent : chunkmap.entrySet()) {
|
||||||
sb.append(String.format("%lx", ent.getKey().longValue()));
|
sb.append(String.format("%x", ent.getKey().longValue()));
|
||||||
long[] val = ent.getValue();
|
long[] val = ent.getValue();
|
||||||
for(long vv : val) {
|
for(long vv : val) {
|
||||||
sb.append(String.format(":%lx", vv));
|
sb.append(String.format(":%x", vv));
|
||||||
}
|
}
|
||||||
v.add(sb.toString());
|
v.add(sb.toString());
|
||||||
sb.setLength(0);
|
sb.setLength(0);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue