Switch CommitLogSegment from RandomAccessFile to nio

Patch by jmckenzie; reviewed by belliottsmith for CASSANDRA-8308
This commit is contained in:
Joshua McKenzie 2015-01-08 11:49:09 -06:00
parent 028fd29501
commit 2b4029a763
4 changed files with 57 additions and 18 deletions

View File

@ -1,4 +1,5 @@
3.0
* Switch CommitLogSegment from RandomAccessFile to nio (CASSANDRA-8308)
* Allow mixing token and partition key restrictions (CASSANDRA-7016)
* Support index key/value entries on map collections (CASSANDRA-8473)
* Modernize schema tables (CASSANDRA-8261)

View File

@ -23,6 +23,7 @@ import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
@ -104,7 +105,7 @@ public class CommitLogSegment
public final long id;
private final File logFile;
private final RandomAccessFile logFileAccessor;
private final FileChannel channel;
private final int fd;
private final MappedByteBuffer buffer;
@ -134,7 +135,6 @@ public class CommitLogSegment
id = getNextId();
descriptor = new CommitLogDescriptor(id);
logFile = new File(DatabaseDescriptor.getCommitLogLocation(), descriptor.fileName());
boolean isCreating = true;
try
{
@ -147,25 +147,37 @@ public class CommitLogSegment
logger.debug("Re-using discarded CommitLog segment for {} from {}", id, filePath);
if (!oldFile.renameTo(logFile))
throw new IOException("Rename from " + filePath + " to " + id + " failed");
isCreating = false;
}
else
{
logger.debug("Creating new CommitLog segment: " + logFile);
}
}
// Open the initial the segment file
logFileAccessor = new RandomAccessFile(logFile, "rw");
// Extend or truncate the file size to the standard segment size as we may have restarted after a segment
// size configuration change, leaving "incorrectly" sized segments on disk.
// NOTE: while we're using RAF to allow extension of file on disk w/out sparse, we need to avoid using RAF
// for grabbing the FileChannel due to FILE_SHARE_DELETE flag bug on windows.
// See: https://bugs.openjdk.java.net/browse/JDK-6357433 and CASSANDRA-8308
if (logFile.length() != DatabaseDescriptor.getCommitLogSegmentSize())
{
try (RandomAccessFile raf = new RandomAccessFile(logFile, "rw"))
{
raf.setLength(DatabaseDescriptor.getCommitLogSegmentSize());
}
catch (IOException e)
{
throw new FSWriteError(e, logFile);
}
}
if (isCreating)
logger.debug("Creating new commit log segment {}", logFile.getPath());
channel = FileChannel.open(logFile.toPath(), StandardOpenOption.WRITE, StandardOpenOption.READ);
// Map the segment, extending or truncating it to the standard segment size.
// (We may have restarted after a segment size configuration change, leaving "incorrectly"
// sized segments on disk.)
logFileAccessor.setLength(DatabaseDescriptor.getCommitLogSegmentSize());
fd = CLibrary.getfd(logFileAccessor.getFD());
fd = CLibrary.getfd(channel);
buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, DatabaseDescriptor.getCommitLogSegmentSize());
buffer = logFileAccessor.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, DatabaseDescriptor.getCommitLogSegmentSize());
// write the header
CommitLogDescriptor.writeHeader(buffer, descriptor);
// mark the initial sync marker as uninitialised
buffer.putInt(CommitLogDescriptor.HEADER_SIZE, 0);
buffer.putLong(CommitLogDescriptor.HEADER_SIZE + 4, 0);
@ -415,7 +427,7 @@ public class CommitLogSegment
{
if (FileUtils.isCleanerAvailable())
FileUtils.clean(buffer);
logFileAccessor.close();
channel.close();
}
catch (IOException e)
{

View File

@ -20,6 +20,7 @@ package org.apache.cassandra.utils;
import java.io.FileDescriptor;
import java.io.RandomAccessFile;
import java.lang.reflect.Field;
import java.nio.channels.FileChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -276,6 +277,24 @@ public final class CLibrary
}
}
public static int getfd(FileChannel channel)
{
Field field = FBUtilities.getProtectedField(channel.getClass(), "fd");
if (field == null)
return -1;
try
{
return getfd((FileDescriptor)field.get(channel));
}
catch (IllegalArgumentException|IllegalAccessException e)
{
logger.warn("Unable to read fd field from FileChannel");
}
return -1;
}
/**
* Get system file descriptor from FileDescriptor object.
* @param descriptor - FileDescriptor objec to get fd from
@ -295,7 +314,7 @@ public final class CLibrary
catch (Exception e)
{
JVMStabilityInspector.inspectThrowable(e);
logger.warn("unable to read fd field from FileDescriptor");
logger.warn("Unable to read fd field from FileDescriptor");
}
return -1;

View File

@ -419,6 +419,7 @@ public class SchemaLoader
public static void cleanupAndLeaveDirs()
{
CommitLog.instance.resetUnsafe(); // unmap CLS before attempting to delete or Windows complains
mkdirs();
cleanup();
mkdirs();
@ -434,7 +435,11 @@ public class SchemaLoader
File dir = new File(dirName);
if (!dir.exists())
throw new RuntimeException("No such directory: " + dir.getAbsolutePath());
FileUtils.deleteRecursive(dir);
// Leave the folder around as Windows will complain about directory deletion w/handles open to children files
String[] children = dir.list();
for (String child : children)
FileUtils.deleteRecursive(new File(dir, child));
}
cleanupSavedCaches();
@ -445,7 +450,9 @@ public class SchemaLoader
File dir = new File(dirName);
if (!dir.exists())
throw new RuntimeException("No such directory: " + dir.getAbsolutePath());
FileUtils.deleteRecursive(dir);
String[] children = dir.list();
for (String child : children)
FileUtils.deleteRecursive(new File(dir, child));
}
}