mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-22 10:35:16 +01:00
Generalize purge task for all storages
This commit is contained in:
parent
c2499df3a7
commit
f3f609c573
@ -61,7 +61,7 @@ public boolean scheduleMapUpdateTask(BlueMapMap map, Collection<Vector2i> region
|
||||
@Override
|
||||
public boolean scheduleMapPurgeTask(BlueMapMap map) throws IOException {
|
||||
BlueMapMapImpl cmap = castMap(map);
|
||||
return renderManager.scheduleRenderTask(MapPurgeTask.create(cmap.getBmMap()));
|
||||
return renderManager.scheduleRenderTask(new MapPurgeTask(cmap.getBmMap()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -796,7 +796,7 @@ public int purgeCommand(CommandContext<S> context) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// delete map
|
||||
MapPurgeTask purgeTask = MapPurgeTask.create(map);
|
||||
MapPurgeTask purgeTask = new MapPurgeTask(map);
|
||||
|
||||
plugin.getRenderManager().scheduleRenderTaskNext(purgeTask);
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "Created new Task to purge map '" + map.getId() + "'"));
|
||||
@ -817,7 +817,7 @@ public int purgeCommand(CommandContext<S> context) {
|
||||
}
|
||||
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "Use ", TextColor.GRAY, "/bluemap", TextColor.GREEN, " to see the progress."));
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
} catch (IllegalArgumentException e) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "There was an error trying to purge '" + map.getId() + "', see console for details."));
|
||||
Logger.global.logError("Failed to purge map '" + map.getId() + "'!", e);
|
||||
}
|
||||
|
@ -26,191 +26,78 @@
|
||||
|
||||
import de.bluecolored.bluemap.api.debug.DebugDump;
|
||||
import de.bluecolored.bluemap.core.map.BmMap;
|
||||
import de.bluecolored.bluemap.core.storage.Storage;
|
||||
import de.bluecolored.bluemap.core.storage.file.FileStorage;
|
||||
import de.bluecolored.bluemap.core.util.DeletingPathVisitor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class MapPurgeTask implements RenderTask {
|
||||
public class MapPurgeTask implements RenderTask {
|
||||
|
||||
public static MapPurgeTask create(BmMap map) throws IOException {
|
||||
Storage storage = map.getStorage();
|
||||
if (storage instanceof FileStorage) {
|
||||
return new MapFilePurgeTask(map, (FileStorage) storage);
|
||||
} else {
|
||||
return new MapStoragePurgeTask(map);
|
||||
}
|
||||
private final BmMap map;
|
||||
|
||||
private volatile double progress;
|
||||
private volatile boolean hasMoreWork;
|
||||
private volatile boolean cancelled;
|
||||
|
||||
public MapPurgeTask(BmMap map) {
|
||||
this.map = Objects.requireNonNull(map);
|
||||
this.progress = 0d;
|
||||
this.hasMoreWork = true;
|
||||
this.cancelled = false;
|
||||
}
|
||||
|
||||
public static MapPurgeTask create(Path mapDirectory) throws IOException {
|
||||
return new MapFilePurgeTask(mapDirectory);
|
||||
}
|
||||
|
||||
@DebugDump
|
||||
private static class MapFilePurgeTask extends MapPurgeTask {
|
||||
|
||||
@Nullable private final BmMap map;
|
||||
private final Path directory;
|
||||
private final int subFilesCount;
|
||||
private final LinkedList<Path> subFiles;
|
||||
|
||||
private volatile boolean hasMoreWork;
|
||||
private volatile boolean cancelled;
|
||||
|
||||
public MapFilePurgeTask(Path mapDirectory) throws IOException {
|
||||
this(null, mapDirectory);
|
||||
}
|
||||
|
||||
public MapFilePurgeTask(BmMap map, FileStorage fileStorage) throws IOException {
|
||||
this(map, fileStorage.getFilePath(map.getId()));
|
||||
}
|
||||
|
||||
private MapFilePurgeTask(@Nullable BmMap map, Path directory) throws IOException {
|
||||
this.map = map;
|
||||
this.directory = directory;
|
||||
try (Stream<Path> pathStream = Files.walk(directory, 3)) {
|
||||
this.subFiles = pathStream.collect(Collectors.toCollection(LinkedList::new));
|
||||
}
|
||||
this.subFilesCount = subFiles.size();
|
||||
this.hasMoreWork = true;
|
||||
this.cancelled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWork() throws Exception {
|
||||
synchronized (this) {
|
||||
if (!this.hasMoreWork) return;
|
||||
this.hasMoreWork = false;
|
||||
}
|
||||
|
||||
try {
|
||||
// save lowres-tile-manager to clear/flush any buffered data
|
||||
if (this.map != null) this.map.getLowresTileManager().save();
|
||||
|
||||
// delete subFiles first to be able to track the progress and cancel
|
||||
while (!subFiles.isEmpty()) {
|
||||
Path subFile = subFiles.getLast();
|
||||
Files.walkFileTree(subFile, DeletingPathVisitor.INSTANCE);
|
||||
subFiles.removeLast();
|
||||
if (this.cancelled) return;
|
||||
}
|
||||
|
||||
// make sure everything is deleted
|
||||
if (Files.exists(directory)) {
|
||||
Files.walkFileTree(directory, DeletingPathVisitor.INSTANCE);
|
||||
}
|
||||
|
||||
// reset texture-gallery
|
||||
if (this.map != null) this.map.resetTextureGallery();
|
||||
|
||||
} finally {
|
||||
// reset map render state
|
||||
if (this.map != null) {
|
||||
this.map.getRenderState().reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreWork() {
|
||||
return this.hasMoreWork;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DebugDump
|
||||
public double estimateProgress() {
|
||||
return 1d - (subFiles.size() / (double) subFilesCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.cancelled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(RenderTask task) {
|
||||
if (task == this) return true;
|
||||
if (task instanceof MapFilePurgeTask) {
|
||||
return ((MapFilePurgeTask) task).directory.toAbsolutePath().normalize()
|
||||
.startsWith(this.directory.toAbsolutePath().normalize());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Purge Map " + directory.getFileName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@DebugDump
|
||||
private static class MapStoragePurgeTask extends MapPurgeTask {
|
||||
|
||||
private final BmMap map;
|
||||
|
||||
private volatile boolean hasMoreWork;
|
||||
|
||||
public MapStoragePurgeTask(BmMap map) {
|
||||
this.map = Objects.requireNonNull(map);
|
||||
this.hasMoreWork = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doWork() throws Exception {
|
||||
synchronized (this) {
|
||||
if (!this.hasMoreWork) return;
|
||||
this.hasMoreWork = false;
|
||||
}
|
||||
|
||||
try {
|
||||
map.getStorage().purgeMap(map.getId());
|
||||
} finally {
|
||||
// reset map render state
|
||||
map.getRenderState().reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreWork() {
|
||||
return this.hasMoreWork;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DebugDump
|
||||
public double estimateProgress() {
|
||||
return 0d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
@Override
|
||||
public void doWork() throws Exception {
|
||||
synchronized (this) {
|
||||
if (!this.hasMoreWork) return;
|
||||
this.hasMoreWork = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(RenderTask task) {
|
||||
if (task == this) return true;
|
||||
if (task instanceof MapStoragePurgeTask) {
|
||||
return map.equals(((MapStoragePurgeTask) task).map);
|
||||
}
|
||||
// save lowres-tile-manager to clear/flush any buffered data
|
||||
this.map.getLowresTileManager().save();
|
||||
|
||||
return false;
|
||||
try {
|
||||
// purge the map
|
||||
map.getStorage().purgeMap(map.getId(), progressInfo -> {
|
||||
this.progress = progressInfo.getProgress();
|
||||
return !this.cancelled;
|
||||
});
|
||||
|
||||
// reset texture gallery
|
||||
map.resetTextureGallery();
|
||||
} finally {
|
||||
// reset renderstate
|
||||
map.getRenderState().reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Purge Map " + map.getId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public boolean hasMoreWork() {
|
||||
return this.hasMoreWork && !this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DebugDump
|
||||
public double estimateProgress() {
|
||||
return this.progress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.cancelled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(RenderTask task) {
|
||||
if (task == this) return true;
|
||||
if (task instanceof MapPurgeTask) {
|
||||
return map.equals(((MapPurgeTask) task).map);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Purge Map " + map.getId();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,7 +30,9 @@
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class Storage implements Closeable {
|
||||
|
||||
@ -52,7 +54,11 @@ public abstract class Storage implements Closeable {
|
||||
|
||||
public abstract void deleteMeta(String mapId, String name) throws IOException;
|
||||
|
||||
public abstract void purgeMap(String mapId) throws IOException;
|
||||
public abstract void purgeMap(String mapId, Function<ProgressInfo, Boolean> onProgress) throws IOException;
|
||||
|
||||
public abstract Collection<String> collectMapIds() throws IOException;
|
||||
|
||||
public abstract long estimateMapSize(String mapId) throws IOException;
|
||||
|
||||
public MapStorage mapStorage(final String mapId) {
|
||||
return new MapStorage(mapId);
|
||||
@ -118,6 +124,20 @@ public Storage getStorage() {
|
||||
|
||||
}
|
||||
|
||||
public static class ProgressInfo {
|
||||
|
||||
private final double progress;
|
||||
|
||||
public ProgressInfo(double progress) {
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
public double getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static String escapeMetaName(String name) {
|
||||
return name.replaceAll("[^\\w\\d.\\-_/]", "_").replace("..", "_.");
|
||||
}
|
||||
|
@ -27,16 +27,18 @@
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import de.bluecolored.bluemap.api.debug.DebugDump;
|
||||
import de.bluecolored.bluemap.core.storage.*;
|
||||
import de.bluecolored.bluemap.core.util.FileHelper;
|
||||
import de.bluecolored.bluemap.core.util.DeletingPathVisitor;
|
||||
import de.bluecolored.bluemap.core.util.FileHelper;
|
||||
import de.bluecolored.bluemap.core.util.SizeCollectingPathVisitor;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@DebugDump
|
||||
public class FileStorage extends Storage {
|
||||
@ -188,8 +190,48 @@ public void deleteMeta(String mapId, String name) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void purgeMap(String mapId) throws IOException {
|
||||
Files.walkFileTree(getFilePath(mapId), DeletingPathVisitor.INSTANCE);
|
||||
public void purgeMap(String mapId, Function<ProgressInfo, Boolean> onProgress) throws IOException {
|
||||
final Path directory = getFilePath(mapId);
|
||||
final int subFilesCount;
|
||||
final LinkedList<Path> subFiles;
|
||||
|
||||
// collect sub-files to be able to provide progress-updates
|
||||
try (Stream<Path> pathStream = Files.walk(directory, 3)) {
|
||||
subFiles = pathStream.collect(Collectors.toCollection(LinkedList::new));
|
||||
}
|
||||
subFilesCount = subFiles.size();
|
||||
|
||||
// delete subFiles first to be able to track the progress and cancel
|
||||
while (!subFiles.isEmpty()) {
|
||||
Path subFile = subFiles.getLast();
|
||||
Files.walkFileTree(subFile, DeletingPathVisitor.INSTANCE);
|
||||
subFiles.removeLast();
|
||||
|
||||
if (!onProgress.apply(
|
||||
new ProgressInfo(1d - (subFiles.size() / (double) subFilesCount))
|
||||
)) return;
|
||||
}
|
||||
|
||||
// make sure everything is deleted
|
||||
if (Files.exists(directory))
|
||||
Files.walkFileTree(directory, DeletingPathVisitor.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> collectMapIds() throws IOException {
|
||||
try (Stream<Path> fileStream = Files.list(root)) {
|
||||
return fileStream
|
||||
.filter(Files::isDirectory)
|
||||
.map(path -> path.getFileName().toString())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateMapSize(String mapId) throws IOException {
|
||||
SizeCollectingPathVisitor visitor = new SizeCollectingPathVisitor();
|
||||
Files.walkFileTree(getFilePath(mapId), visitor);
|
||||
return visitor.getSize();
|
||||
}
|
||||
|
||||
public Path getFilePath(String mapId, int lod, Vector2i tile){
|
||||
|
@ -46,6 +46,7 @@
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class SQLStorage extends Storage {
|
||||
|
||||
@ -375,7 +376,7 @@ public void deleteMeta(String mapId, String name) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void purgeMap(String mapId) throws IOException {
|
||||
public void purgeMap(String mapId, Function<ProgressInfo, Boolean> onProgress) throws IOException {
|
||||
try {
|
||||
recoveringConnection(connection -> {
|
||||
executeUpdate(connection,
|
||||
@ -395,12 +396,29 @@ public void purgeMap(String mapId) throws IOException {
|
||||
"WHERE m.`map_id` = ?",
|
||||
mapId
|
||||
);
|
||||
|
||||
executeUpdate(connection,
|
||||
"DELETE t " +
|
||||
"FROM `bluemap_map`" +
|
||||
"WHERE `map_id` = ?",
|
||||
mapId
|
||||
);
|
||||
}, 2);
|
||||
} catch (SQLException ex) {
|
||||
throw new IOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> collectMapIds() throws IOException {
|
||||
return Collections.emptyList(); //TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateMapSize(String mapId) throws IOException {
|
||||
return 0; //TODO
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedAssignment")
|
||||
public void initialize() throws IOException {
|
||||
try {
|
||||
|
@ -0,0 +1,24 @@
|
||||
package de.bluecolored.bluemap.core.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class SizeCollectingPathVisitor extends SimpleFileVisitor<Path> {
|
||||
|
||||
private final AtomicLong size = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
size.addAndGet(attrs.size());
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size.get();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user