Delayed write to file (experimental)

This commit is contained in:
snowleo 2013-04-22 23:31:11 +02:00
parent e291633ac8
commit 2588e20140

View file

@ -9,6 +9,9 @@ import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult; import java.nio.charset.CoderResult;
import java.util.*; import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.bukkit.*; import org.bukkit.*;
@ -24,21 +27,27 @@ import org.bukkit.util.Vector;
public class EssentialsConf extends YamlConfiguration public class EssentialsConf extends YamlConfiguration
{ {
private static final Logger LOGGER = Logger.getLogger("Minecraft"); private static final Logger LOGGER = Logger.getLogger("Minecraft");
private transient File configFile; private final File configFile;
private transient String templateName = null; private String templateName = null;
private transient Class<?> resourceClass = EssentialsConf.class; private Class<?> resourceClass = EssentialsConf.class;
private static final Charset UTF8 = Charset.forName("UTF-8"); private static final Charset UTF8 = Charset.forName("UTF-8");
private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
private final AtomicInteger pendingDiskWrites = new AtomicInteger(0);
public EssentialsConf(final File configFile) public EssentialsConf(final File configFile)
{ {
super(); super();
this.configFile = configFile; this.configFile = configFile.getAbsoluteFile();
} }
private final byte[] bytebuffer = new byte[1024]; private final byte[] bytebuffer = new byte[1024];
public synchronized void load() public synchronized void load()
{ {
configFile = configFile.getAbsoluteFile(); if (pendingDiskWrites.get() != 0)
{
LOGGER.log(Level.INFO, "File " + configFile + " not read, because it's not yet written to disk.");
return;
}
if (!configFile.getParentFile().exists()) if (!configFile.getParentFile().exists())
{ {
if (!configFile.getParentFile().mkdirs()) if (!configFile.getParentFile().mkdirs())
@ -241,13 +250,12 @@ public class EssentialsConf extends YamlConfiguration
@Override @Override
public synchronized void save(final File file) throws IOException public synchronized void save(final File file) throws IOException
{ {
//long startTime = System.nanoTime();
if (file == null) if (file == null)
{ {
throw new IllegalArgumentException("File cannot be null"); throw new IllegalArgumentException("File cannot be null");
} }
Files.createParentDirs(file);
final String data = saveToString(); final String data = saveToString();
if (data.length() == 0) if (data.length() == 0)
@ -255,6 +263,45 @@ public class EssentialsConf extends YamlConfiguration
return; return;
} }
pendingDiskWrites.incrementAndGet();
EXECUTOR_SERVICE.submit(new WriteRunner(configFile, data, pendingDiskWrites));
//LOGGER.log(Level.INFO, configFile + " prepared for writing in " + (System.nanoTime() - startTime) + " nsec.");
}
private static class WriteRunner implements Runnable
{
private final File configFile;
private final String data;
private final AtomicInteger pendingDiskWrites;
private WriteRunner(final File configFile, final String data, final AtomicInteger pendingDiskWrites)
{
this.configFile = configFile;
this.data = data;
this.pendingDiskWrites = pendingDiskWrites;
}
@Override
public void run()
{
//long startTime = System.nanoTime();
synchronized (configFile)
{
if (pendingDiskWrites.get() > 1)
{
// Writes can be skipped, because they are stored in a queue (in the executor).
// Only the last is actually written.
pendingDiskWrites.decrementAndGet();
//LOGGER.log(Level.INFO, configFile + " skipped writing in " + (System.nanoTime() - startTime) + " nsec.");
return;
}
try
{
Files.createParentDirs(configFile);
if (!configFile.exists()) if (!configFile.exists())
{ {
try try
@ -263,16 +310,18 @@ public class EssentialsConf extends YamlConfiguration
if (!configFile.createNewFile()) if (!configFile.createNewFile())
{ {
LOGGER.log(Level.SEVERE, _("failedToCreateConfig", configFile.toString())); LOGGER.log(Level.SEVERE, _("failedToCreateConfig", configFile.toString()));
return;
} }
} }
catch (IOException ex) catch (IOException ex)
{ {
LOGGER.log(Level.SEVERE, _("failedToCreateConfig", configFile.toString()), ex); LOGGER.log(Level.SEVERE, _("failedToCreateConfig", configFile.toString()), ex);
return;
} }
} }
final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), UTF8); final OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(configFile), UTF8);
try try
{ {
@ -283,6 +332,18 @@ public class EssentialsConf extends YamlConfiguration
writer.close(); writer.close();
} }
} }
catch (IOException e)
{
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
finally
{
//LOGGER.log(Level.INFO, configFile + " written to disk in " + (System.nanoTime() - startTime) + " nsec.");
pendingDiskWrites.decrementAndGet();
}
}
}
}
public boolean hasProperty(final String path) public boolean hasProperty(final String path)
{ {