| /** |
| * 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.hadoop.hdfs.server.namenode; |
| |
| import java.util.Arrays; |
| |
| /** |
| * File name generator. |
| * |
| * Each directory contains not more than a fixed number (filesPerDir) |
| * of files and directories. |
| * When the number of files in one directory reaches the maximum, |
| * the generator creates a new directory and proceeds generating files in it. |
| * The generated namespace tree is balanced that is any path to a leaf |
| * file is not less than the height of the tree minus one. |
| */ |
| public class FileNameGenerator { |
| private static final int DEFAULT_FILES_PER_DIRECTORY = 32; |
| |
| private final int[] pathIndecies = new int[20]; // this will support up to 32**20 = 2**100 = 10**30 files |
| private final String baseDir; |
| private String currentDir; |
| private final int filesPerDirectory; |
| private long fileCount; |
| |
| FileNameGenerator(String baseDir) { |
| this(baseDir, DEFAULT_FILES_PER_DIRECTORY); |
| } |
| |
| FileNameGenerator(String baseDir, int filesPerDir) { |
| this.baseDir = baseDir; |
| this.filesPerDirectory = filesPerDir; |
| reset(); |
| } |
| |
| String getNextDirName(String prefix) { |
| int depth = 0; |
| while(pathIndecies[depth] >= 0) |
| depth++; |
| int level; |
| for(level = depth-1; |
| level >= 0 && pathIndecies[level] == filesPerDirectory-1; level--) |
| pathIndecies[level] = 0; |
| if(level < 0) |
| pathIndecies[depth] = 0; |
| else |
| pathIndecies[level]++; |
| level = 0; |
| String next = baseDir; |
| while(pathIndecies[level] >= 0) |
| next = next + "/" + prefix + pathIndecies[level++]; |
| return next; |
| } |
| |
| synchronized String getNextFileName(String fileNamePrefix) { |
| long fNum = fileCount % filesPerDirectory; |
| if(fNum == 0) { |
| currentDir = getNextDirName(fileNamePrefix + "Dir"); |
| } |
| String fn = currentDir + "/" + fileNamePrefix + fileCount; |
| fileCount++; |
| return fn; |
| } |
| |
| private synchronized void reset() { |
| Arrays.fill(pathIndecies, -1); |
| fileCount = 0L; |
| currentDir = ""; |
| } |
| |
| synchronized int getFilesPerDirectory() { |
| return filesPerDirectory; |
| } |
| |
| synchronized String getCurrentDir() { |
| return currentDir; |
| } |
| } |