You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ratis.apache.org by sz...@apache.org on 2021/06/10 06:37:12 UTC

[ratis] branch master updated: RATIS-1377. Ratis min free space for storage dirs. (#479)

This is an automated email from the ASF dual-hosted git repository.

szetszwo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ratis.git


The following commit(s) were added to refs/heads/master by this push:
     new a731551  RATIS-1377. Ratis min free space for storage dirs. (#479)
a731551 is described below

commit a7315511bddcc12dc4acea25f2d0d71608a8591c
Author: Gui Hecheng <ma...@tencent.com>
AuthorDate: Thu Jun 10 14:37:03 2021 +0800

    RATIS-1377. Ratis min free space for storage dirs. (#479)
---
 .../org/apache/ratis/server/RaftServerConfigKeys.java | 10 ++++++++++
 .../org/apache/ratis/server/impl/ServerState.java     |  3 ++-
 .../server/storage/RaftStorageDirectoryImpl.java      | 17 ++++++++++++++++-
 .../apache/ratis/server/storage/RaftStorageImpl.java  | 10 ++++++----
 .../ratis/server/storage/RaftStorageTestUtils.java    |  2 +-
 .../apache/ratis/server/storage/TestRaftStorage.java  | 19 +++++++++++++++----
 6 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/ratis-server-api/src/main/java/org/apache/ratis/server/RaftServerConfigKeys.java b/ratis-server-api/src/main/java/org/apache/ratis/server/RaftServerConfigKeys.java
index 7e888ff..892cc16 100644
--- a/ratis-server-api/src/main/java/org/apache/ratis/server/RaftServerConfigKeys.java
+++ b/ratis-server-api/src/main/java/org/apache/ratis/server/RaftServerConfigKeys.java
@@ -51,6 +51,16 @@ public interface RaftServerConfigKeys {
     setFiles(properties::setFiles, STORAGE_DIR_KEY, storageDir);
   }
 
+  String STORAGE_FREE_SPACE_MIN_KEY = PREFIX + ".storage.free-space.min";
+  SizeInBytes STORAGE_FREE_SPACE_MIN_DEFAULT = SizeInBytes.valueOf("0MB");
+  static SizeInBytes storageFreeSpaceMin(RaftProperties properties) {
+    return getSizeInBytes(properties::getSizeInBytes,
+        STORAGE_FREE_SPACE_MIN_KEY, STORAGE_FREE_SPACE_MIN_DEFAULT, getDefaultLog());
+  }
+  static void setStorageFreeSpaceMin(RaftProperties properties, SizeInBytes storageFreeSpaceMin) {
+    setSizeInBytes(properties::set, STORAGE_FREE_SPACE_MIN_KEY, storageFreeSpaceMin);
+  }
+
   String REMOVED_GROUPS_DIR_KEY = PREFIX + ".removed.groups.dir";
   File REMOVED_GROUPS_DIR_DEFAULT = new File("/tmp/raft-server/removed-groups/");
   static File removedGroupsDir(RaftProperties properties) {
diff --git a/ratis-server/src/main/java/org/apache/ratis/server/impl/ServerState.java b/ratis-server/src/main/java/org/apache/ratis/server/impl/ServerState.java
index b5557c5..38a37a1 100644
--- a/ratis-server/src/main/java/org/apache/ratis/server/impl/ServerState.java
+++ b/ratis-server/src/main/java/org/apache/ratis/server/impl/ServerState.java
@@ -110,7 +110,8 @@ class ServerState implements Closeable {
       // use full uuid string to create a subdirectory
       File dir = chooseStorageDir(directories, group.getGroupId().getUuid().toString());
       try {
-        storage = new RaftStorageImpl(dir, RaftServerConfigKeys.Log.corruptionPolicy(prop));
+        storage = new RaftStorageImpl(dir, RaftServerConfigKeys.Log.corruptionPolicy(prop),
+            RaftServerConfigKeys.storageFreeSpaceMin(prop).getSize());
         storageFound = true;
         break;
       } catch (IOException e) {
diff --git a/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageDirectoryImpl.java b/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageDirectoryImpl.java
index 5e69f7d..8647179 100644
--- a/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageDirectoryImpl.java
+++ b/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageDirectoryImpl.java
@@ -43,19 +43,22 @@ class RaftStorageDirectoryImpl implements RaftStorageDirectory {
   enum StorageState {
     NON_EXISTENT,
     NOT_FORMATTED,
+    NO_SPACE,
     NORMAL
   }
 
   private final File root; // root directory
   private FileLock lock;   // storage lock
+  private long freeSpaceMin;
 
   /**
    * Constructor
    * @param dir directory corresponding to the storage
    */
-  RaftStorageDirectoryImpl(File dir) {
+  RaftStorageDirectoryImpl(File dir, long freeSpaceMin) {
     this.root = dir;
     this.lock = null;
+    this.freeSpaceMin = freeSpaceMin;
   }
 
   @Override
@@ -150,6 +153,14 @@ class RaftStorageDirectoryImpl implements RaftStorageDirectory {
       this.lock(); // lock storage if it exists
     }
 
+    // check enough space
+    if (!hasEnoughSpace()) {
+      LOG.warn("There are not enough space left for directory " + rootPath
+          + " free space min required: " + freeSpaceMin
+          + " free space actual: " + root.getFreeSpace());
+      return StorageState.NO_SPACE;
+    }
+
     // check whether current directory is valid
     if (isHealthy()) {
       return StorageState.NORMAL;
@@ -163,6 +174,10 @@ class RaftStorageDirectoryImpl implements RaftStorageDirectory {
     return getMetaFile().exists();
   }
 
+  private boolean hasEnoughSpace() {
+    return root.getFreeSpace() > freeSpaceMin;
+  }
+
   /**
    * Lock storage to provide exclusive access.
    *
diff --git a/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageImpl.java b/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageImpl.java
index 93772da..0bbf902 100644
--- a/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageImpl.java
+++ b/ratis-server/src/main/java/org/apache/ratis/server/storage/RaftStorageImpl.java
@@ -47,12 +47,14 @@ public class RaftStorageImpl implements RaftStorage {
   private final CorruptionPolicy logCorruptionPolicy;
   private volatile RaftStorageMetadataFileImpl metaFile;
 
-  public RaftStorageImpl(File dir, CorruptionPolicy logCorruptionPolicy) throws IOException {
-    this(dir, logCorruptionPolicy, null);
+  public RaftStorageImpl(File dir, CorruptionPolicy logCorruptionPolicy,
+      long storageFeeSpaceMin) throws IOException {
+    this(dir, logCorruptionPolicy, null, storageFeeSpaceMin);
   }
 
-  RaftStorageImpl(File dir, CorruptionPolicy logCorruptionPolicy, StartupOption option) throws IOException {
-    this.storageDir = new RaftStorageDirectoryImpl(dir);
+  RaftStorageImpl(File dir, CorruptionPolicy logCorruptionPolicy, StartupOption option,
+      long storageFeeSpaceMin) throws IOException {
+    this.storageDir = new RaftStorageDirectoryImpl(dir, storageFeeSpaceMin);
     if (option == StartupOption.FORMAT) {
       if (storageDir.analyzeStorage(false) == StorageState.NON_EXISTENT) {
         throw new IOException("Cannot format " + storageDir);
diff --git a/ratis-server/src/test/java/org/apache/ratis/server/storage/RaftStorageTestUtils.java b/ratis-server/src/test/java/org/apache/ratis/server/storage/RaftStorageTestUtils.java
index 9f192e4..d8c48ff 100644
--- a/ratis-server/src/test/java/org/apache/ratis/server/storage/RaftStorageTestUtils.java
+++ b/ratis-server/src/test/java/org/apache/ratis/server/storage/RaftStorageTestUtils.java
@@ -33,7 +33,7 @@ import java.util.function.Consumer;
 
 public interface RaftStorageTestUtils {
   static RaftStorage newRaftStorage(File dir) throws IOException {
-    return new RaftStorageImpl(dir, null);
+    return new RaftStorageImpl(dir, null, 0L);
   }
 
   static String getLogFlushTimeMetric(String memberId) {
diff --git a/ratis-test/src/test/java/org/apache/ratis/server/storage/TestRaftStorage.java b/ratis-test/src/test/java/org/apache/ratis/server/storage/TestRaftStorage.java
index 678e432..89e2cce 100644
--- a/ratis-test/src/test/java/org/apache/ratis/server/storage/TestRaftStorage.java
+++ b/ratis-test/src/test/java/org/apache/ratis/server/storage/TestRaftStorage.java
@@ -31,6 +31,7 @@ import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 
 import java.io.File;
 import java.io.IOException;
@@ -46,7 +47,7 @@ import java.util.regex.Matcher;
  */
 public class TestRaftStorage extends BaseTest {
   static RaftStorageImpl newRaftStorage(File dir) throws IOException {
-    return new RaftStorageImpl(dir, null);
+    return new RaftStorageImpl(dir, null, 0);
   }
 
   private File storageDir;
@@ -64,7 +65,7 @@ public class TestRaftStorage extends BaseTest {
   }
 
   static RaftStorageImpl formatRaftStorage(File dir) throws IOException {
-    return new RaftStorageImpl(dir, null, RaftStorageImpl.StartupOption.FORMAT);
+    return new RaftStorageImpl(dir, null, RaftStorageImpl.StartupOption.FORMAT, 0);
   }
 
   @Test
@@ -99,7 +100,7 @@ public class TestRaftStorage extends BaseTest {
    */
   @Test
   public void testStorage() throws Exception {
-    final RaftStorageDirectoryImpl sd = new RaftStorageDirectoryImpl(storageDir);
+    final RaftStorageDirectoryImpl sd = new RaftStorageDirectoryImpl(storageDir, 0);
     try {
       StorageState state = sd.analyzeStorage(true);
       Assert.assertEquals(StorageState.NOT_FORMATTED, state);
@@ -156,7 +157,7 @@ public class TestRaftStorage extends BaseTest {
     Assert.assertEquals(StorageState.NORMAL, storage.getState());
     storage.close();
 
-    final RaftStorageDirectoryImpl sd = new RaftStorageDirectoryImpl(storageDir);
+    final RaftStorageDirectoryImpl sd = new RaftStorageDirectoryImpl(storageDir, 0);
     File metaFile = sd.getMetaFile();
     FileUtils.move(metaFile, sd.getMetaTmpFile());
 
@@ -265,4 +266,14 @@ public class TestRaftStorage extends BaseTest {
     Assert.assertTrue(stateMachineDir.listFiles().length == 5);
 
   }
+
+  @Test
+  public void testNotEnoughSpace() throws IOException {
+    File mockStorageDir = Mockito.spy(storageDir);
+    Mockito.when(mockStorageDir.getFreeSpace()).thenReturn(100L);  // 100B
+
+    final RaftStorageDirectoryImpl sd = new RaftStorageDirectoryImpl(mockStorageDir, 104857600); // 100MB
+    StorageState state = sd.analyzeStorage(false);
+    Assert.assertEquals(StorageState.NO_SPACE, state);
+  }
 }