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 <[email protected]> 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)) {
