mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-27 06:20:02 +00:00
Relax test fsync
- Add Durability, a process-wide fsync policy defaulting to real barriers and switchable to relaxed through the iris.durability system property - Route the history, studio, journal, structure and datapack fsync barriers through Durability so relaxed mode skips both the force and the channel open - Add the DurabilityMode test rule and enable relaxed durability on the twenty slowest core stores tests - Split GenerationHistoryTest into epoch, legacy adoption and recovery classes over a shared GenerationHistorySupport base
This commit is contained in:
1 parent
c75cfd387e
commit
c332c86849
34 files changed
+862
-621
No files matched your search
@@ -37,6 +37,7 @@ import art.arcane.iris.core.structure.authoring.StructureTransactionWriter;
|
||||
import art.arcane.iris.engine.object.IrisDimension;
|
||||
import art.arcane.iris.engine.object.IrisImportedStructureControl;
|
||||
import art.arcane.iris.util.common.format.C;
|
||||
import art.arcane.iris.util.common.io.Durability;
|
||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.io.IO;
|
||||
@@ -5396,17 +5397,25 @@ public final class DatapackIngestService {
|
||||
}
|
||||
|
||||
private static void forceFile(Path file) throws IOException {
|
||||
if (!Durability.enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileChannel channel = FileChannel.open(file, StandardOpenOption.WRITE)) {
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
}
|
||||
}
|
||||
|
||||
private static void forceDirectoryIfSupported(Path directory) throws IOException {
|
||||
if (!Durability.enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Files.getFileStore(directory).supportsFileAttributeView("posix")) {
|
||||
return;
|
||||
}
|
||||
try (FileChannel channel = FileChannel.open(directory, StandardOpenOption.READ)) {
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package art.arcane.iris.core.lifecycle;
|
||||
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
|
||||
import art.arcane.iris.util.common.io.Durability;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
@@ -19,11 +20,15 @@ final class DirectoryDurability {
|
||||
}
|
||||
|
||||
static void forceDirectoryRequired(Path directory) throws IOException {
|
||||
if (!Durability.enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (File.separatorChar == '\\') {
|
||||
return;
|
||||
}
|
||||
try (FileChannel channel = FileChannel.open(directory, StandardOpenOption.READ)) {
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
} catch (UnsupportedOperationException failure) {
|
||||
throw new IOException("Directory durability sync is unavailable for " + directory + ".", failure);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import art.arcane.iris.core.IrisWorldStorage;
|
||||
import art.arcane.iris.core.WorldSlotKey;
|
||||
import art.arcane.iris.core.lifecycle.BukkitWorldConfiguration.WorldGeneratorSnapshot;
|
||||
|
||||
import art.arcane.iris.util.common.io.Durability;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -345,7 +346,7 @@ public final class WorldReplacementJournal {
|
||||
while (buffer.hasRemaining()) {
|
||||
channel.write(buffer);
|
||||
}
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
}
|
||||
forceDirectoryRequired(parent);
|
||||
try {
|
||||
|
||||
@@ -12,6 +12,7 @@ import art.arcane.iris.core.structure.authoring.StructureTransactionWriter;
|
||||
import art.arcane.iris.core.structure.authoring.StructureWriteOptions;
|
||||
import art.arcane.iris.core.structure.authoring.StructureWriteResult;
|
||||
import art.arcane.iris.engine.framework.structure.StructureResourceBundleGraphCompiler;
|
||||
import art.arcane.iris.util.common.io.Durability;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
@@ -303,7 +304,7 @@ final class JigsawStudioHistoryStore {
|
||||
while (buffer.hasRemaining()) {
|
||||
channel.write(buffer);
|
||||
}
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
}
|
||||
try {
|
||||
Files.move(
|
||||
@@ -374,6 +375,10 @@ final class JigsawStudioHistoryStore {
|
||||
}
|
||||
|
||||
private static void forceDirectory(Path directory) throws IOException {
|
||||
if (!Durability.enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A directory can only be opened and fsynced on a POSIX filesystem; Windows rejects the
|
||||
// open outright. Matches DirectoryDurability and DatapackIngestService, which already
|
||||
// skip the barrier there.
|
||||
@@ -381,7 +386,7 @@ final class JigsawStudioHistoryStore {
|
||||
return;
|
||||
}
|
||||
try (FileChannel channel = FileChannel.open(directory, StandardOpenOption.READ)) {
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.core.structure.authoring;
|
||||
|
||||
import art.arcane.iris.util.common.io.Durability;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.channels.FileChannel;
|
||||
@@ -70,17 +71,25 @@ interface StructureFileOperations {
|
||||
}
|
||||
|
||||
default void forceFile(Path path) throws IOException {
|
||||
if (!Durability.enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (FileChannel channel = FileChannel.open(path, StandardOpenOption.WRITE)) {
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
}
|
||||
}
|
||||
|
||||
default void forceDirectory(Path path) throws IOException {
|
||||
if (!Durability.enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Files.getFileStore(path).supportsFileAttributeView("posix")) {
|
||||
return;
|
||||
}
|
||||
try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ)) {
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package art.arcane.iris.engine.history;
|
||||
|
||||
import art.arcane.iris.core.pack.AtomicDirectoryPublisher;
|
||||
import art.arcane.iris.util.common.io.Durability;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
|
||||
import java.io.File;
|
||||
@@ -1153,11 +1154,15 @@ public final class GenerationHistory {
|
||||
}
|
||||
|
||||
private static void forceDirectory(Path directory) throws IOException {
|
||||
if (!Durability.enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (File.separatorChar == '\\') {
|
||||
return;
|
||||
}
|
||||
try (FileChannel channel = FileChannel.open(directory, StandardOpenOption.READ)) {
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
} catch (UnsupportedOperationException exception) {
|
||||
throw new IOException("Generation history directory cannot be durability-synced: "
|
||||
+ directory, exception);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package art.arcane.iris.engine.history;
|
||||
|
||||
import art.arcane.iris.util.common.io.Durability;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
@@ -282,7 +283,7 @@ public final class GenerationHistoryStore {
|
||||
while (buffer.hasRemaining()) {
|
||||
channel.write(buffer);
|
||||
}
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
}
|
||||
try {
|
||||
if (replaceExisting) {
|
||||
@@ -352,7 +353,7 @@ public final class GenerationHistoryStore {
|
||||
while (buffer.hasRemaining()) {
|
||||
channel.write(buffer);
|
||||
}
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
}
|
||||
try {
|
||||
Files.move(temporary, metadata, StandardCopyOption.ATOMIC_MOVE);
|
||||
@@ -439,11 +440,15 @@ public final class GenerationHistoryStore {
|
||||
}
|
||||
|
||||
private static void forceDirectory(Path directory) throws IOException {
|
||||
if (!Durability.enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (File.separatorChar == '\\') {
|
||||
return;
|
||||
}
|
||||
try (FileChannel channel = FileChannel.open(directory, StandardOpenOption.READ)) {
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
} catch (UnsupportedOperationException exception) {
|
||||
throw new IOException("Generation history directory cannot be durability-synced: " + directory, exception);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package art.arcane.iris.engine.history;
|
||||
|
||||
import art.arcane.iris.engine.hydrology.HydrologyFeatureType;
|
||||
import art.arcane.iris.util.common.io.Durability;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
@@ -1949,14 +1950,14 @@ public final class GenerationSemanticIndex {
|
||||
channel.write(entry);
|
||||
}
|
||||
}
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
if (created) {
|
||||
RegionShard.forceDirectory(directory);
|
||||
}
|
||||
} catch (IOException failure) {
|
||||
try {
|
||||
channel.truncate(size);
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
if (created) {
|
||||
RegionShard.forceDirectory(directory);
|
||||
}
|
||||
@@ -2079,7 +2080,7 @@ public final class GenerationSemanticIndex {
|
||||
|
||||
private static void truncateTail(RandomAccessFile file, long length) throws IOException {
|
||||
file.setLength(length);
|
||||
file.getFD().sync();
|
||||
Durability.force(file.getFD());
|
||||
}
|
||||
|
||||
private static IOException invalid(Path file, String reason) {
|
||||
@@ -2951,16 +2952,20 @@ public final class GenerationSemanticIndex {
|
||||
while (buffer.hasRemaining()) {
|
||||
channel.write(buffer);
|
||||
}
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
}
|
||||
}
|
||||
|
||||
private static void forceDirectory(Path directory) throws IOException {
|
||||
if (!Durability.enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (File.separatorChar == '\\') {
|
||||
return;
|
||||
}
|
||||
try (FileChannel channel = FileChannel.open(directory, StandardOpenOption.READ)) {
|
||||
channel.force(true);
|
||||
Durability.force(channel);
|
||||
} catch (UnsupportedOperationException error) {
|
||||
throw new IOException("Generation semantic directory cannot be durability-synced", error);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package art.arcane.iris.util.common.io;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
public final class Durability {
|
||||
public static final String MODE_PROPERTY = "iris.durability";
|
||||
private static final String RELAXED = "relaxed";
|
||||
|
||||
private Durability() {
|
||||
}
|
||||
|
||||
public static boolean enabled() {
|
||||
return !RELAXED.equalsIgnoreCase(System.getProperty(MODE_PROPERTY));
|
||||
}
|
||||
|
||||
public static void force(FileChannel channel) throws IOException {
|
||||
if (!enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
channel.force(true);
|
||||
}
|
||||
|
||||
public static void force(FileDescriptor descriptor) throws IOException {
|
||||
if (!enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
descriptor.sync();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user