Add own metrics and save and load the state the render-manager of the sponge-plugin

This commit is contained in:
Blue (Lukas Rieger) 2019-11-15 18:59:13 +01:00
parent 731c31e601
commit 82ab8c2c7c
6 changed files with 276 additions and 8 deletions

View File

@ -0,0 +1,7 @@
package de.bluecolored.bluemap.core;
public class BlueMap {
public static final String VERSION = "0.0.0";
}

View File

@ -0,0 +1,65 @@
package de.bluecolored.bluemap.core.metrics;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import javax.net.ssl.HttpsURLConnection;
import com.google.gson.JsonObject;
import de.bluecolored.bluemap.core.BlueMap;
public class Metrics {
private static final String METRICS_REPORT_URL = "https://metrics.bluecolored.de/bluemap/";
public static void sendReportAsync(String implementation) {
new Thread(() -> sendReport(implementation)).start();
}
public static void sendReport(String implementation) {
JsonObject data = new JsonObject();
data.addProperty("implementation", implementation);
data.addProperty("version", BlueMap.VERSION);
try {
sendData(data.toString());
} catch (Exception ex) {}
}
private static String sendData(String data) throws MalformedURLException, IOException {
byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
HttpsURLConnection connection = (HttpsURLConnection) new URL(METRICS_REPORT_URL).openConnection();
connection.setRequestMethod("POST");
connection.addRequestProperty("Content-Length", String.valueOf(bytes.length));
connection.setRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Connection", "close");
connection.setRequestProperty("User-Agent", "BlueMap");
connection.setDoOutput(true);
try (OutputStream out = connection.getOutputStream()){
out.write(bytes);
out.flush();
}
try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
String line;
StringBuilder builder = new StringBuilder();
while ((line = in.readLine()) != null) {
builder.append(line + "\n");
}
return builder.toString();
}
}
}

View File

@ -111,4 +111,15 @@ public class MapUpdateHandler {
return updateBuffer.size();
}
public void flushTileBuffer() {
RenderManager renderManager = SpongePlugin.getInstance().getRenderManager();
synchronized (updateBuffer) {
for (MapType map : updateBuffer.keySet()) {
renderManager.createTickets(map, updateBuffer.get(map));
}
updateBuffer.clear();
}
}
}

View File

@ -1,5 +1,7 @@
package de.bluecolored.bluemap.sponge;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
@ -7,9 +9,13 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.flowpowered.math.vector.Vector2i;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.MultimapBuilder;
import de.bluecolored.bluemap.core.logger.Logger;
@ -151,4 +157,77 @@ public class RenderManager {
return running;
}
public void writeState(DataOutputStream out) throws IOException {
//prepare renderTickets
ListMultimap<MapType, Vector2i> tileMap = MultimapBuilder.hashKeys().arrayListValues().<MapType, Vector2i>build();
synchronized (renderTickets) {
for (RenderTicket ticket : renderTickets) {
tileMap.put(ticket.getMapType(), ticket.getTile());
}
}
//write renderTickets
Set<MapType> maps = tileMap.keySet();
out.writeInt(maps.size());
for (MapType map : maps) {
List<Vector2i> tiles = tileMap.get(map);
out.writeUTF(map.getId());
out.writeInt(tiles.size());
for (Vector2i tile : tiles) {
out.writeInt(tile.getX());
out.writeInt(tile.getY());
}
}
//write tasks
synchronized (renderTasks) {
out.writeInt(renderTasks.size());
for (RenderTask task : renderTasks) {
task.write(out);
}
}
}
public void readState(DataInputStream in) throws IOException {
//read renderTickets
int mapCount = in.readInt();
for (int i = 0; i < mapCount; i++) {
String mapId = in.readUTF();
MapType mapType = null;
for (MapType map : SpongePlugin.getInstance().getMapTypes()) {
if (map.getId().equals(mapId)) {
mapType = map;
break;
}
}
if (mapType == null) {
Logger.global.logWarning("Some render-tickets can not be loaded because the map (id: '" + mapId + "') does not exist anymore. They will be discarded.");
}
int tileCount = in.readInt();
List<Vector2i> tiles = new ArrayList<>();
for (int j = 0; j < tileCount; j++) {
int x = in.readInt();
int y = in.readInt();
Vector2i tile = new Vector2i(x, y);
tiles.add(tile);
}
createTickets(mapType, tiles);
}
//read tasks
int taskCount = in.readInt();
for (int i = 0; i < taskCount; i++) {
try {
RenderTask task = RenderTask.read(in);
addRenderTask(task);
} catch (IOException ex) {
Logger.global.logWarning("A render-task can not be loaded. It will be discared. (Error message: " + ex.toString() + ")");
}
}
}
}

View File

@ -1,9 +1,14 @@
package de.bluecolored.bluemap.sponge;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import java.util.UUID;
import com.flowpowered.math.vector.Vector2d;
@ -21,8 +26,6 @@ public class RenderTask {
private long additionalRunTime;
private int renderedTiles;
private UUID taskOwner;
public RenderTask(String name, MapType mapType) {
this.uuid = UUID.randomUUID();
this.name = name;
@ -31,7 +34,6 @@ public class RenderTask {
this.firstTileTime = -1;
this.additionalRunTime = 0;
this.renderedTiles = 0;
this.taskOwner = null;
}
public void optimizeQueue() {
@ -132,8 +134,54 @@ public class RenderTask {
return renderTiles.isEmpty();
}
public UUID getTaskOwner() {
return taskOwner;
public void write(DataOutputStream out) throws IOException {
synchronized (renderTiles) {
pause();
out.writeUTF(name);
out.writeUTF(mapType.getId());
out.writeLong(additionalRunTime);
out.writeInt(renderedTiles);
out.writeInt(renderTiles.size());
for (Vector2i tile : renderTiles) {
out.writeInt(tile.getX());
out.writeInt(tile.getY());
}
}
}
public static RenderTask read(DataInputStream in) throws IOException {
String name = in.readUTF();
String mapId = in.readUTF();
MapType mapType = null;
for (MapType map : SpongePlugin.getInstance().getMapTypes()) {
if (map.getId().equals(mapId)) {
mapType = map;
break;
}
}
if (mapType == null) throw new IOException("Map type with id '" + mapId + "' does not exist!");
RenderTask task = new RenderTask(name, mapType);
task.additionalRunTime = in.readLong();
task.renderedTiles = in.readInt();
int tileCount = in.readInt();
List<Vector2i> tiles = new ArrayList<>();
for (int i = 0; i < tileCount; i++) {
int x = in.readInt();
int y = in.readInt();
Vector2i tile = new Vector2i(x, y);
tiles.add(tile);
}
task.addTiles(tiles);
return task;
}
}

View File

@ -24,13 +24,21 @@
*/
package de.bluecolored.bluemap.sponge;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.inject.Inject;
@ -42,15 +50,19 @@ import org.spongepowered.api.event.game.GameReloadEvent;
import org.spongepowered.api.event.game.state.GameStartingServerEvent;
import org.spongepowered.api.event.game.state.GameStoppingEvent;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.scheduler.SpongeExecutorService;
import org.spongepowered.api.util.Tristate;
import com.flowpowered.math.vector.Vector2i;
import com.google.common.collect.Lists;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.config.ConfigurationFile;
import de.bluecolored.bluemap.core.config.ConfigurationFile.MapConfig;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.mca.MCAWorld;
import de.bluecolored.bluemap.core.metrics.Metrics;
import de.bluecolored.bluemap.core.render.TileRenderer;
import de.bluecolored.bluemap.core.render.hires.HiresModelManager;
import de.bluecolored.bluemap.core.render.lowres.LowresModelManager;
@ -74,7 +86,7 @@ public class SpongePlugin {
public static final String PLUGIN_ID = "bluemap";
public static final String PLUGIN_NAME = "BlueMap";
public static final String PLUGIN_VERSION = "0.0.0";
public static final String PLUGIN_VERSION = BlueMap.VERSION;
private static SpongePlugin instance;
@ -190,6 +202,20 @@ public class SpongePlugin {
renderManager = new RenderManager(config.getRenderThreadCount());
renderManager.start();
//load render-manager state
try {
File saveFile = configurationDir.resolve("rmstate").toFile();
saveFile.getParentFile().mkdirs();
if (saveFile.exists()) {
try (DataInputStream in = new DataInputStream(new GZIPInputStream(new FileInputStream(saveFile)))) {
renderManager.readState(in);
}
}
saveFile.delete();
} catch (IOException ex) {
Logger.global.logError("Failed to load render-manager state!", ex);
}
//start map updater
updateHandler = new MapUpdateHandler();
@ -217,6 +243,21 @@ public class SpongePlugin {
webServer.start();
}
//metrics
Sponge.getScheduler().createTaskBuilder()
.async()
.delay(0, TimeUnit.MINUTES)
.interval(30, TimeUnit.MINUTES)
.execute(() -> {
Optional<PluginContainer> plugin = Sponge.getPluginManager().fromInstance(this);
if (!plugin.isPresent()) return;
Tristate metricsEnabled = Sponge.getMetricsConfigManager().getCollectionState(plugin.get());
if (metricsEnabled == Tristate.UNDEFINED) metricsEnabled = Sponge.getMetricsConfigManager().getGlobalCollectionState();
if (metricsEnabled == Tristate.TRUE) Metrics.sendReport("Sponge");
})
.submit(this);
loaded = true;
}
@ -228,7 +269,6 @@ public class SpongePlugin {
//unregister listeners
if (updateHandler != null) Sponge.getEventManager().unregisterListeners(updateHandler);
updateHandler = null;
//unregister commands
Sponge.getCommandManager().getOwnedBy(this).forEach(Sponge.getCommandManager()::removeMapping);
@ -236,6 +276,23 @@ public class SpongePlugin {
//stop scheduled tasks
Sponge.getScheduler().getScheduledTasks(this).forEach(t -> t.cancel());
//save render-manager state
if (updateHandler != null) updateHandler.flushTileBuffer(); //first write all buffered tiles to the render manager to save them too
if (renderManager != null) {
try {
File saveFile = configurationDir.resolve("rmstate").toFile();
saveFile.getParentFile().mkdirs();
if (saveFile.exists()) saveFile.delete();
saveFile.createNewFile();
try (DataOutputStream out = new DataOutputStream(new GZIPOutputStream(new FileOutputStream(saveFile)))) {
renderManager.writeState(out);
}
} catch (IOException ex) {
Logger.global.logError("Failed to save render-manager state!", ex);
}
}
//save renders
for (MapType map : maps.values()) {
map.getTileRenderer().save();
@ -244,13 +301,14 @@ public class SpongePlugin {
//clear resources and configs
renderManager = null;
webServer = null;
updateHandler = null;
resourcePack = null;
config = null;
maps.clear();
worlds.clear();
loaded = false;
}
}
public synchronized void reload() throws IOException, NoSuchResourceException {
unload();