You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by jm...@apache.org on 2015/01/08 18:51:06 UTC
cassandra git commit: Switch CommitLogSegment from RandomAccessFile
to nio
Repository: cassandra
Updated Branches:
refs/heads/trunk 028fd2950 -> 2b4029a76
Switch CommitLogSegment from RandomAccessFile to nio
Patch by jmckenzie; reviewed by belliottsmith for CASSANDRA-8308
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/2b4029a7
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/2b4029a7
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/2b4029a7
Branch: refs/heads/trunk
Commit: 2b4029a763173af31633274844a4a3de1f73fa99
Parents: 028fd29
Author: Joshua McKenzie <jm...@apache.org>
Authored: Thu Jan 8 11:49:09 2015 -0600
Committer: Joshua McKenzie <jm...@apache.org>
Committed: Thu Jan 8 11:49:09 2015 -0600
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../db/commitlog/CommitLogSegment.java | 42 +++++++++++++-------
.../org/apache/cassandra/utils/CLibrary.java | 21 +++++++++-
.../unit/org/apache/cassandra/SchemaLoader.java | 11 ++++-
4 files changed, 57 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b4029a7/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 9f946a3..71ccc58 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -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)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b4029a7/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java b/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java
index 185f57a..3383f1e 100644
--- a/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java
+++ b/src/java/org/apache/cassandra/db/commitlog/CommitLogSegment.java
@@ -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)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b4029a7/src/java/org/apache/cassandra/utils/CLibrary.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/utils/CLibrary.java b/src/java/org/apache/cassandra/utils/CLibrary.java
index b2595f6..4dbd904 100644
--- a/src/java/org/apache/cassandra/utils/CLibrary.java
+++ b/src/java/org/apache/cassandra/utils/CLibrary.java
@@ -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;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b4029a7/test/unit/org/apache/cassandra/SchemaLoader.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/SchemaLoader.java b/test/unit/org/apache/cassandra/SchemaLoader.java
index 2fcfd55..2be4cc0 100644
--- a/test/unit/org/apache/cassandra/SchemaLoader.java
+++ b/test/unit/org/apache/cassandra/SchemaLoader.java
@@ -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));
}
}