This is an automated email from the ASF dual-hosted git repository.
marcuse pushed a commit to branch cassandra-3.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/cassandra-3.0 by this push:
new f02e535 Improve empty/corrupt hint file handling on startup
f02e535 is described below
commit f02e53568dbc193b7ac75cc19b0a7751d5514b95
Author: Marcus Eriksson <[email protected]>
AuthorDate: Fri Oct 2 08:23:05 2020 +0200
Improve empty/corrupt hint file handling on startup
Patch by marcuse; reviewed by Benjamin Lerer and Yifan Cai for
CASSANDRA-16162
---
CHANGES.txt | 1 +
.../apache/cassandra/hints/HintsDescriptor.java | 28 ++++++++++++++++-
.../cassandra/hints/HintsDescriptorTest.java | 35 ++++++++++++++++++----
3 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 5cb4f1d..ee4cf6e 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
3.0.24:
+ * Improve empty hint file handling during startup (CASSANDRA-16162)
* Allow empty string in collections with COPY FROM in cqlsh (CASSANDRA-16372)
* Fix skipping on pre-3.0 created compact storage sstables due to missing
primary key liveness (CASSANDRA-16226)
* Fix DecimalDeserializer#toString OOM (CASSANDRA-14925)
diff --git a/src/java/org/apache/cassandra/hints/HintsDescriptor.java
b/src/java/org/apache/cassandra/hints/HintsDescriptor.java
index e9e1c30..d1f1116 100644
--- a/src/java/org/apache/cassandra/hints/HintsDescriptor.java
+++ b/src/java/org/apache/cassandra/hints/HintsDescriptor.java
@@ -21,6 +21,7 @@ import java.io.DataInput;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
@@ -28,6 +29,7 @@ import java.util.UUID;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMap;
@@ -148,11 +150,35 @@ final class HintsDescriptor
}
catch (IOException e)
{
- logger.error("Failed to deserialize hints descriptor {}",
path.toString(), e);
+ handleDescriptorIOE(e, path);
return Optional.empty();
}
}
+ @VisibleForTesting
+ static void handleDescriptorIOE(IOException e, Path path)
+ {
+ try
+ {
+ if (Files.size(path) > 0)
+ {
+ String newFileName =
path.getFileName().toString().replace(".hints", ".corrupt.hints");
+ Path target = path.getParent().resolve(newFileName);
+ logger.error("Failed to deserialize hints descriptor {} -
saving file as {}", path.toString(), target, e);
+ Files.move(path, target);
+ }
+ else
+ {
+ logger.warn("Found empty hints file {} on startup, removing",
path.toString());
+ Files.delete(path);
+ }
+ }
+ catch (IOException ex)
+ {
+ logger.error("Error handling corrupt hints file {}",
path.toString(), ex);
+ }
+ }
+
static HintsDescriptor readFromFile(Path path)
{
try (RandomAccessFile raf = new RandomAccessFile(path.toFile(), "r"))
diff --git a/test/unit/org/apache/cassandra/hints/HintsDescriptorTest.java
b/test/unit/org/apache/cassandra/hints/HintsDescriptorTest.java
index 08487d1..bab2356 100644
--- a/test/unit/org/apache/cassandra/hints/HintsDescriptorTest.java
+++ b/test/unit/org/apache/cassandra/hints/HintsDescriptorTest.java
@@ -20,11 +20,14 @@ package org.apache.cassandra.hints;
import java.io.DataInput;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
import java.util.UUID;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
-import com.google.common.io.Files;
+import org.junit.Assert;
import org.junit.Test;
import org.apache.cassandra.io.compress.LZ4Compressor;
@@ -33,6 +36,8 @@ import org.apache.cassandra.io.util.DataOutputBuffer;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotSame;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
public class HintsDescriptorTest
{
@@ -100,21 +105,41 @@ public class HintsDescriptorTest
ImmutableMap<String, Object> parameters = ImmutableMap.of();
HintsDescriptor expected = new HintsDescriptor(hostId, version,
timestamp, parameters);
- File directory = Files.createTempDir();
+ Path directory = Files.createTempDirectory("hints");
try
{
- try (HintsWriter ignored = HintsWriter.create(directory, expected))
+ try (HintsWriter ignored = HintsWriter.create(directory.toFile(),
expected))
{
}
- HintsDescriptor actual = HintsDescriptor.readFromFile(new
File(directory, expected.fileName()).toPath());
+ HintsDescriptor actual =
HintsDescriptor.readFromFile(directory.resolve(expected.fileName()));
assertEquals(expected, actual);
}
finally
{
- directory.deleteOnExit();
+ directory.toFile().deleteOnExit();
}
}
+ @Test
+ public void testHandleIOE() throws IOException
+ {
+ Path p = Files.createTempFile("testing", ".hints");
+ // empty file;
+ assertTrue(p.toFile().exists());
+ Assert.assertEquals(0, Files.size(p));
+ HintsDescriptor.handleDescriptorIOE(new IOException("test"), p);
+ assertFalse(Files.exists(p));
+
+ // non-empty
+ p = Files.createTempFile("testing", ".hints");
+ Files.write(p, Collections.singleton("hello"));
+ HintsDescriptor.handleDescriptorIOE(new IOException("test"), p);
+ File newFile = new File(p.getParent().toFile(),
p.getFileName().toString().replace(".hints", ".corrupt.hints"));
+ assertFalse(Files.exists(p));
+ assertTrue(newFile.toString(), newFile.exists());
+ newFile.deleteOnExit();
+ }
+
private static void testSerializeDeserializeLoop(HintsDescriptor
descriptor) throws IOException
{
// serialize to a byte array
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]