Fix file system race condition that may cause LogAwareFileLister to fail to classify files
patch by Stefania Alborghetti; reviewed by Benjamin Lerer for CASSANDRA-11889 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/5cda140b Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/5cda140b Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/5cda140b Branch: refs/heads/trunk Commit: 5cda140bae05c84dde92998df1b85583be69812d Parents: da07130 Author: Stefania Alborghetti <stefania.alborghe...@datastax.com> Authored: Tue Aug 2 16:37:15 2016 +0800 Committer: Stefania Alborghetti <stefania.alborghe...@datastax.com> Committed: Tue Aug 30 08:51:08 2016 +0800 ---------------------------------------------------------------------- CHANGES.txt | 1 + src/java/org/apache/cassandra/db/lifecycle/LogFile.java | 2 +- src/java/org/apache/cassandra/db/lifecycle/LogRecord.java | 9 +++++++-- 3 files changed, 9 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/5cda140b/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index cf14f67..7a1fbc5 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0.9 + * Fix file system race condition that may cause LogAwareFileLister to fail to classify files (CASSANDRA-11889) * Fix file handle leaks due to simultaneous compaction/repair and listing snapshots, calculating snapshot sizes, or making schema changes (CASSANDRA-11594) http://git-wip-us.apache.org/repos/asf/cassandra/blob/5cda140b/src/java/org/apache/cassandra/db/lifecycle/LogFile.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/lifecycle/LogFile.java b/src/java/org/apache/cassandra/db/lifecycle/LogFile.java index 8560410..da5bb39 100644 --- a/src/java/org/apache/cassandra/db/lifecycle/LogFile.java +++ b/src/java/org/apache/cassandra/db/lifecycle/LogFile.java @@ -216,7 +216,7 @@ final class LogFile implements AutoCloseable // it matches. Because we delete files from oldest to newest, the latest update time should // always match. record.status.onDiskRecord = record.withExistingFiles(); - if (record.updateTime != record.status.onDiskRecord.updateTime && record.status.onDiskRecord.numFiles > 0) + if (record.updateTime != record.status.onDiskRecord.updateTime && record.status.onDiskRecord.updateTime > 0) { record.setError(String.format("Unexpected files detected for sstable [%s], " + "record [%s]: last update time [%tT] should have been [%tT]", http://git-wip-us.apache.org/repos/asf/cassandra/blob/5cda140b/src/java/org/apache/cassandra/db/lifecycle/LogRecord.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/lifecycle/LogRecord.java b/src/java/org/apache/cassandra/db/lifecycle/LogRecord.java index d7eb774..c981b02 100644 --- a/src/java/org/apache/cassandra/db/lifecycle/LogRecord.java +++ b/src/java/org/apache/cassandra/db/lifecycle/LogRecord.java @@ -26,6 +26,7 @@ import java.nio.file.Paths; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.zip.CRC32; import org.apache.cassandra.io.sstable.SSTable; @@ -156,8 +157,12 @@ final class LogRecord public static LogRecord make(Type type, List<File> files, int minFiles, String absolutePath) { - long lastModified = files.stream().map(File::lastModified).reduce(0L, Long::max); - return new LogRecord(type, absolutePath, lastModified, Math.max(minFiles, files.size())); + // CASSANDRA-11889: File.lastModified() returns a positive value only if the file exists, therefore + // we filter by positive values to only consider the files that still exists right now, in case things + // changed on disk since getExistingFiles() was called + List<Long> positiveModifiedTimes = files.stream().map(File::lastModified).filter(lm -> lm > 0).collect(Collectors.toList()); + long lastModified = positiveModifiedTimes.stream().reduce(0L, Long::max); + return new LogRecord(type, absolutePath, lastModified, Math.max(minFiles, positiveModifiedTimes.size())); } private LogRecord(Type type, long updateTime)