You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ea...@apache.org on 2019/06/04 08:07:13 UTC

[incubator-iotdb] 01/02: multi-directories avoid using disk without space

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

east pushed a commit to branch update_mult_dir_avoid_full_disk
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git

commit f699d67bf5d081844a7ffea93da822206e576c6f
Author: mdf369 <95...@qq.com>
AuthorDate: Mon Jun 3 18:35:09 2019 +0800

    multi-directories avoid using disk without space
---
 .../iotdb/db/conf/directories/Directories.java     |  5 +-
 .../directories/strategy/DirectoryStrategy.java    | 16 ++++-
 .../strategy/MaxDiskUsableSpaceFirstStrategy.java  | 35 ++++------
 .../strategy/MinDirOccupiedSpaceFirstStrategy.java | 76 ----------------------
 .../MinFolderOccupiedSpaceFirstStrategy.java       | 39 +++++------
 .../directories/strategy/SequenceStrategy.java     | 32 ++++++---
 .../db/engine/filenode/FileNodeProcessor.java      | 12 +++-
 .../DiskSpaceInsufficientException.java}           | 28 ++------
 .../iotdb/db/sync/receiver/SyncServiceImpl.java    | 14 ++--
 9 files changed, 102 insertions(+), 155 deletions(-)

diff --git a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/Directories.java b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/Directories.java
index ad9c847..d792c37 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/Directories.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/Directories.java
@@ -24,6 +24,7 @@ import java.util.Arrays;
 import java.util.List;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.conf.directories.strategy.DirectoryStrategy;
+import org.apache.iotdb.db.exception.DiskSpaceInsufficientException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -78,7 +79,7 @@ public class Directories {
     tsfileFolders.set(0, path);
   }
 
-  public String getNextFolderForTsfile() {
+  public String getNextFolderForTsfile() throws DiskSpaceInsufficientException {
     return getTsFileFolder(getNextFolderIndexForTsFile());
   }
 
@@ -87,7 +88,7 @@ public class Directories {
    *
    * @return next folder index
    */
-  public int getNextFolderIndexForTsFile() {
+  public int getNextFolderIndexForTsFile() throws DiskSpaceInsufficientException {
     return strategy.nextFolderIndex();
   }
 
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java
index 52b550b..04133ba 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/DirectoryStrategy.java
@@ -18,7 +18,9 @@
  */
 package org.apache.iotdb.db.conf.directories.strategy;
 
+import java.io.File;
 import java.util.List;
+import org.apache.iotdb.db.exception.DiskSpaceInsufficientException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,7 +44,7 @@ public abstract class DirectoryStrategy {
    *
    * @param folders the folders from conf
    */
-  public void init(List<String> folders) {
+  public void init(List<String> folders) throws DiskSpaceInsufficientException {
     this.folders = folders;
   }
 
@@ -51,7 +53,7 @@ public abstract class DirectoryStrategy {
    *
    * @return the index of folder that will be allocated
    */
-  public abstract int nextFolderIndex();
+  public abstract int nextFolderIndex() throws DiskSpaceInsufficientException;
 
   /**
    * Return the actual string value of a folder by its index.
@@ -72,4 +74,14 @@ public abstract class DirectoryStrategy {
   public void setFolderForTest(String path) {
     folders.set(0, path);
   }
+
+  protected long getUsableSpace(String dir) {
+    long space = new File(dir).getFreeSpace();
+    LOGGER.debug("Folder {} has {} available bytes.", dir, space);
+    return space;
+  }
+
+  protected boolean hasSpace(String dir) {
+    return getUsableSpace(dir) > 0;
+  }
 }
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MaxDiskUsableSpaceFirstStrategy.java b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MaxDiskUsableSpaceFirstStrategy.java
index 8ff1450..8f3ea7d 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MaxDiskUsableSpaceFirstStrategy.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MaxDiskUsableSpaceFirstStrategy.java
@@ -18,41 +18,34 @@
  */
 package org.apache.iotdb.db.conf.directories.strategy;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
+import org.apache.iotdb.db.exception.DiskSpaceInsufficientException;
 
 public class MaxDiskUsableSpaceFirstStrategy extends DirectoryStrategy {
 
   @Override
-  public int nextFolderIndex() {
+  public int nextFolderIndex() throws DiskSpaceInsufficientException {
     return getMaxSpaceFolder();
   }
 
   /**
    * get max space folder.
    */
-  public int getMaxSpaceFolder() {
-    List<Integer> candidates = new ArrayList<>();
-    long max;
+  public int getMaxSpaceFolder() throws DiskSpaceInsufficientException {
+    int maxIndex = -1;
+    long maxSpace = 0;
 
-    candidates.add(0);
-    max = new File(folders.get(0)).getUsableSpace();
-    for (int i = 1; i < folders.size(); i++) {
-      long current = new File(folders.get(i)).getUsableSpace();
-      if (max < current) {
-        candidates.clear();
-        candidates.add(i);
-        max = current;
-      } else if (max == current) {
-        candidates.add(i);
+    for (int i = 0; i < folders.size(); i++) {
+      long space = getUsableSpace(folders.get(i));
+      if (space > maxSpace) {
+        maxSpace = space;
+        maxIndex = i;
       }
     }
 
-    Random random = new Random(System.currentTimeMillis());
-    int index = random.nextInt(candidates.size());
+    if (maxIndex == -1) {
+      throw new DiskSpaceInsufficientException(folders);
+    }
 
-    return candidates.get(index);
+    return maxIndex;
   }
 }
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MinDirOccupiedSpaceFirstStrategy.java b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MinDirOccupiedSpaceFirstStrategy.java
deleted file mode 100644
index 8174a36..0000000
--- a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MinDirOccupiedSpaceFirstStrategy.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.iotdb.db.conf.directories.strategy;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-import java.util.stream.Stream;
-
-public class MinDirOccupiedSpaceFirstStrategy extends DirectoryStrategy {
-
-  // directory space is measured by MB
-  private static final long DATA_SIZE_SHIFT = 1024L * 1024;
-
-  @Override
-  public int nextFolderIndex() {
-    return getMinOccupiedSpaceFolder();
-  }
-
-  private int getMinOccupiedSpaceFolder() {
-    List<Integer> candidates = new ArrayList<>();
-    candidates.add(0);
-    long min = getOccupiedSpace(folders.get(0));
-    for (int i = 1; i < folders.size(); i++) {
-      long current = getOccupiedSpace(folders.get(i));
-      if (min > current) {
-        candidates.clear();
-        candidates.add(i);
-        min = current;
-      } else if (min == current) {
-        candidates.add(i);
-      }
-    }
-
-    Random random = new Random(System.currentTimeMillis());
-    int index = random.nextInt(candidates.size());
-
-    return candidates.get(index);
-  }
-
-  private long getOccupiedSpace(String path) {
-    Path folder = Paths.get(path);
-    long size = 0;
-    try {
-      try (Stream<Path> stream = Files.walk(folder)) {
-        size = stream.filter(p -> p.toFile().isFile())
-            .mapToLong(p -> p.toFile().length())
-            .sum();
-      }
-    } catch (IOException e) {
-      LOGGER.error("Cannot calculate occupied space for seriesPath {}.", path, e);
-    }
-
-    return size / DATA_SIZE_SHIFT;
-  }
-}
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MinFolderOccupiedSpaceFirstStrategy.java b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MinFolderOccupiedSpaceFirstStrategy.java
index 90e3119..9cbe647 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MinFolderOccupiedSpaceFirstStrategy.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/MinFolderOccupiedSpaceFirstStrategy.java
@@ -22,10 +22,8 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
 import java.util.stream.Stream;
+import org.apache.iotdb.db.exception.DiskSpaceInsufficientException;
 
 public class MinFolderOccupiedSpaceFirstStrategy extends DirectoryStrategy {
 
@@ -33,29 +31,32 @@ public class MinFolderOccupiedSpaceFirstStrategy extends DirectoryStrategy {
   private static final long DATA_SIZE_SHIFT = 1024L * 1024;
 
   @Override
-  public int nextFolderIndex() {
+  public int nextFolderIndex() throws DiskSpaceInsufficientException {
     return getMinOccupiedSpaceFolder();
   }
 
-  private int getMinOccupiedSpaceFolder() {
-    List<Integer> candidates = new ArrayList<>();
-    candidates.add(0);
-    long min = getOccupiedSpace(folders.get(0));
-    for (int i = 1; i < folders.size(); i++) {
-      long current = getOccupiedSpace(folders.get(i));
-      if (min > current) {
-        candidates.clear();
-        candidates.add(i);
-        min = current;
-      } else if (min == current) {
-        candidates.add(i);
+  private int getMinOccupiedSpaceFolder() throws DiskSpaceInsufficientException {
+    int minIndex = -1;
+    long minSpace = Integer.MAX_VALUE;
+
+    for (int i = 0; i < folders.size(); i++) {
+      String folder = folders.get(i);
+      if (hasSpace(folder)) {
+        continue;
+      }
+
+      long space = getOccupiedSpace(folder);
+      if (space < minSpace) {
+        minSpace = space;
+        minIndex = i;
       }
     }
 
-    Random random = new Random(System.currentTimeMillis());
-    int index = random.nextInt(candidates.size());
+    if (minIndex == -1) {
+      throw new DiskSpaceInsufficientException(folders);
+    }
 
-    return candidates.get(index);
+    return minIndex;
   }
 
   private long getOccupiedSpace(String path) {
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/SequenceStrategy.java b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/SequenceStrategy.java
index d2a28bd..e119546 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/SequenceStrategy.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/SequenceStrategy.java
@@ -19,30 +19,46 @@
 package org.apache.iotdb.db.conf.directories.strategy;
 
 import java.util.List;
+import org.apache.iotdb.db.exception.DiskSpaceInsufficientException;
 
 public class SequenceStrategy extends DirectoryStrategy {
 
   private int currentIndex;
 
   @Override
-  public void init(List<String> folders) {
+  public void init(List<String> folders) throws DiskSpaceInsufficientException {
     super.init(folders);
 
-    currentIndex = 0;
+    currentIndex = -1;
+    for (int i = 0; i < folders.size(); i++) {
+      if (hasSpace(folders.get(i))) {
+        currentIndex = i;
+        break;
+      }
+    }
+
+    if (currentIndex == -1) {
+      throw new DiskSpaceInsufficientException(
+          String.format("All disks of folders %s are full, can't init.", folders));
+    }
   }
 
   @Override
-  public int nextFolderIndex() {
+  public int nextFolderIndex() throws DiskSpaceInsufficientException {
     int index = currentIndex;
-    updateIndex();
+    currentIndex = tryGetNextIndex(index);
 
     return index;
   }
 
-  private void updateIndex() {
-    currentIndex++;
-    if (currentIndex >= folders.size()) {
-      currentIndex = 0;
+  private int tryGetNextIndex(int start) throws DiskSpaceInsufficientException {
+    int index = start;
+    while (!hasSpace(folders.get(index))) {
+      index = (index + 1) % folders.size();
+      if (index == start) {
+        throw new DiskSpaceInsufficientException(folders);
+      }
     }
+    return index;
   }
 }
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/engine/filenode/FileNodeProcessor.java b/iotdb/src/main/java/org/apache/iotdb/db/engine/filenode/FileNodeProcessor.java
index 209c1f1..701aefb 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/engine/filenode/FileNodeProcessor.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/engine/filenode/FileNodeProcessor.java
@@ -67,6 +67,7 @@ import org.apache.iotdb.db.engine.querycontext.UnsealedTsFile;
 import org.apache.iotdb.db.engine.version.SimpleFileVersionController;
 import org.apache.iotdb.db.engine.version.VersionController;
 import org.apache.iotdb.db.exception.BufferWriteProcessorException;
+import org.apache.iotdb.db.exception.DiskSpaceInsufficientException;
 import org.apache.iotdb.db.exception.ErrorDebugException;
 import org.apache.iotdb.db.exception.FileNodeProcessorException;
 import org.apache.iotdb.db.exception.OverflowProcessorException;
@@ -527,7 +528,12 @@ public class FileNodeProcessor extends Processor implements IStatistic {
       params.put(FileNodeConstants.BUFFERWRITE_CLOSE_ACTION, bufferwriteCloseAction);
       params
           .put(FileNodeConstants.FILENODE_PROCESSOR_FLUSH_ACTION, flushFileNodeProcessorAction);
-      String baseDir = directories.getNextFolderForTsfile();
+      String baseDir = null;
+      try {
+        baseDir = directories.getNextFolderForTsfile();
+      } catch (DiskSpaceInsufficientException e) {
+        throw new FileNodeProcessorException(e);
+      }
       LOGGER.info("Allocate folder {} for the new bufferwrite processor.", baseDir);
       // construct processor or restore
       try {
@@ -1532,6 +1538,8 @@ public class FileNodeProcessor extends Processor implements IStatistic {
           mergeFileWriter.endChunkGroup(footer, 0);
         }
       }
+    } catch (DiskSpaceInsufficientException e) {
+      throw new FileNodeProcessorException(e);
     } finally {
       FileReaderManager.getInstance().decreaseFileReaderReference(backupIntervalFile.getFilePath(),
           true);
@@ -1557,7 +1565,7 @@ public class FileNodeProcessor extends Processor implements IStatistic {
       SingleSeriesExpression seriesFilter, TSDataType dataType,
       Map<String, Long> startTimeMap, Map<String, Long> endTimeMap,
       OverflowSeriesDataSource overflowSeriesDataSource)
-      throws IOException {
+      throws IOException, DiskSpaceInsufficientException {
     int numOfChunk = 0;
     try {
       if (!seriesReader.hasNext()) {
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/SequenceStrategy.java b/iotdb/src/main/java/org/apache/iotdb/db/exception/DiskSpaceInsufficientException.java
similarity index 63%
copy from iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/SequenceStrategy.java
copy to iotdb/src/main/java/org/apache/iotdb/db/exception/DiskSpaceInsufficientException.java
index d2a28bd..1649fa1 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/conf/directories/strategy/SequenceStrategy.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/exception/DiskSpaceInsufficientException.java
@@ -16,33 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.conf.directories.strategy;
+package org.apache.iotdb.db.exception;
 
 import java.util.List;
 
-public class SequenceStrategy extends DirectoryStrategy {
+public class DiskSpaceInsufficientException extends Exception {
 
-  private int currentIndex;
+  private static final long serialVersionUID = 9001643829368311032L;
 
-  @Override
-  public void init(List<String> folders) {
-    super.init(folders);
-
-    currentIndex = 0;
-  }
-
-  @Override
-  public int nextFolderIndex() {
-    int index = currentIndex;
-    updateIndex();
-
-    return index;
+  public DiskSpaceInsufficientException(String message) {
+    super(message);
   }
 
-  private void updateIndex() {
-    currentIndex++;
-    if (currentIndex >= folders.size()) {
-      currentIndex = 0;
-    }
+  public DiskSpaceInsufficientException(List<String> folders) {
+    this(String.format("Can't get next folder from %s, because they are all full.", folders));
   }
 }
diff --git a/iotdb/src/main/java/org/apache/iotdb/db/sync/receiver/SyncServiceImpl.java b/iotdb/src/main/java/org/apache/iotdb/db/sync/receiver/SyncServiceImpl.java
index ad2722d..46919b4 100644
--- a/iotdb/src/main/java/org/apache/iotdb/db/sync/receiver/SyncServiceImpl.java
+++ b/iotdb/src/main/java/org/apache/iotdb/db/sync/receiver/SyncServiceImpl.java
@@ -46,6 +46,7 @@ import org.apache.iotdb.db.conf.directories.Directories;
 import org.apache.iotdb.db.engine.filenode.FileNodeManager;
 import org.apache.iotdb.db.engine.filenode.OverflowChangeType;
 import org.apache.iotdb.db.engine.filenode.TsFileResource;
+import org.apache.iotdb.db.exception.DiskSpaceInsufficientException;
 import org.apache.iotdb.db.exception.FileNodeManagerException;
 import org.apache.iotdb.db.exception.MetadataArgsErrorException;
 import org.apache.iotdb.db.exception.PathErrorException;
@@ -469,10 +470,15 @@ public class SyncServiceImpl implements SyncService.Iface {
         // create a new fileNode
         String header = syncDataPath;
         String relativePath = path.substring(header.length());
-        TsFileResource fileNode = new TsFileResource(startTimeMap, endTimeMap,
-            OverflowChangeType.NO_CHANGE, new File(
-            Directories.getInstance().getNextFolderIndexForTsFile() + File.separator + relativePath)
-        );
+        TsFileResource fileNode = null;
+        try {
+          fileNode = new TsFileResource(startTimeMap, endTimeMap,
+              OverflowChangeType.NO_CHANGE, new File(
+              Directories.getInstance().getNextFolderIndexForTsFile() + File.separator + relativePath)
+          );
+        } catch (DiskSpaceInsufficientException e) {
+          throw new FileNodeManagerException(e);
+        }
         // call interface of load external file
         try {
           if (!fileNodeManager.appendFileToFileNode(storageGroup, fileNode, path)) {