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 <marc...@apache.org>
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: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to