001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hdfs.server.blockmanagement; 019 020import com.google.common.annotations.VisibleForTesting; 021import com.google.common.base.Preconditions; 022import org.apache.hadoop.hdfs.protocol.Block; 023import org.apache.hadoop.hdfs.protocol.HdfsConstants; 024import org.apache.hadoop.hdfs.server.common.GenerationStamp; 025 026import java.io.IOException; 027 028/** 029 * BlockIdManager allocates the generation stamps and the block ID. The 030 * {@see FSNamesystem} is responsible for persisting the allocations in the 031 * {@see EditLog}. 032 */ 033public class BlockIdManager { 034 /** 035 * The global generation stamp for legacy blocks with randomly 036 * generated block IDs. 037 */ 038 private final GenerationStamp generationStampV1 = new GenerationStamp(); 039 /** 040 * The global generation stamp for this file system. 041 */ 042 private final GenerationStamp generationStampV2 = new GenerationStamp(); 043 /** 044 * The value of the generation stamp when the first switch to sequential 045 * block IDs was made. Blocks with generation stamps below this value 046 * have randomly allocated block IDs. Blocks with generation stamps above 047 * this value had sequentially allocated block IDs. Read from the fsImage 048 * (or initialized as an offset from the V1 (legacy) generation stamp on 049 * upgrade). 050 */ 051 private long generationStampV1Limit; 052 /** 053 * The global block ID space for this file system. 054 */ 055 private final SequentialBlockIdGenerator blockIdGenerator; 056 057 public BlockIdManager(BlockManager blockManager) { 058 this.generationStampV1Limit = GenerationStamp.GRANDFATHER_GENERATION_STAMP; 059 this.blockIdGenerator = new SequentialBlockIdGenerator(blockManager); 060 } 061 062 /** 063 * Upgrades the generation stamp for the filesystem 064 * by reserving a sufficient range for all existing blocks. 065 * Should be invoked only during the first upgrade to 066 * sequential block IDs. 067 */ 068 public long upgradeGenerationStampToV2() { 069 Preconditions.checkState(generationStampV2.getCurrentValue() == 070 GenerationStamp.LAST_RESERVED_STAMP); 071 generationStampV2.skipTo(generationStampV1.getCurrentValue() + 072 HdfsConstants.RESERVED_GENERATION_STAMPS_V1); 073 074 generationStampV1Limit = generationStampV2.getCurrentValue(); 075 return generationStampV2.getCurrentValue(); 076 } 077 078 /** 079 * Sets the generation stamp that delineates random and sequentially 080 * allocated block IDs. 081 * 082 * @param stamp set generation stamp limit to this value 083 */ 084 public void setGenerationStampV1Limit(long stamp) { 085 Preconditions.checkState(generationStampV1Limit == GenerationStamp 086 .GRANDFATHER_GENERATION_STAMP); 087 generationStampV1Limit = stamp; 088 } 089 090 /** 091 * Gets the value of the generation stamp that delineates sequential 092 * and random block IDs. 093 */ 094 public long getGenerationStampAtblockIdSwitch() { 095 return generationStampV1Limit; 096 } 097 098 @VisibleForTesting 099 SequentialBlockIdGenerator getBlockIdGenerator() { 100 return blockIdGenerator; 101 } 102 103 /** 104 * Sets the maximum allocated block ID for this filesystem. This is 105 * the basis for allocating new block IDs. 106 */ 107 public void setLastAllocatedBlockId(long blockId) { 108 blockIdGenerator.skipTo(blockId); 109 } 110 111 /** 112 * Gets the maximum sequentially allocated block ID for this filesystem 113 */ 114 public long getLastAllocatedBlockId() { 115 return blockIdGenerator.getCurrentValue(); 116 } 117 118 /** 119 * Sets the current generation stamp for legacy blocks 120 */ 121 public void setGenerationStampV1(long stamp) { 122 generationStampV1.setCurrentValue(stamp); 123 } 124 125 /** 126 * Gets the current generation stamp for legacy blocks 127 */ 128 public long getGenerationStampV1() { 129 return generationStampV1.getCurrentValue(); 130 } 131 132 /** 133 * Gets the current generation stamp for this filesystem 134 */ 135 public void setGenerationStampV2(long stamp) { 136 generationStampV2.setCurrentValue(stamp); 137 } 138 139 public long getGenerationStampV2() { 140 return generationStampV2.getCurrentValue(); 141 } 142 143 /** 144 * Increments, logs and then returns the stamp 145 */ 146 public long nextGenerationStamp(boolean legacyBlock) throws IOException { 147 return legacyBlock ? getNextGenerationStampV1() : 148 getNextGenerationStampV2(); 149 } 150 151 @VisibleForTesting 152 long getNextGenerationStampV1() throws IOException { 153 long genStampV1 = generationStampV1.nextValue(); 154 155 if (genStampV1 >= generationStampV1Limit) { 156 // We ran out of generation stamps for legacy blocks. In practice, it 157 // is extremely unlikely as we reserved 1T v1 generation stamps. The 158 // result is that we can no longer append to the legacy blocks that 159 // were created before the upgrade to sequential block IDs. 160 throw new OutOfV1GenerationStampsException(); 161 } 162 163 return genStampV1; 164 } 165 166 @VisibleForTesting 167 long getNextGenerationStampV2() { 168 return generationStampV2.nextValue(); 169 } 170 171 public long getGenerationStampV1Limit() { 172 return generationStampV1Limit; 173 } 174 175 /** 176 * Determine whether the block ID was randomly generated (legacy) or 177 * sequentially generated. The generation stamp value is used to 178 * make the distinction. 179 * 180 * @return true if the block ID was randomly generated, false otherwise. 181 */ 182 public boolean isLegacyBlock(Block block) { 183 return block.getGenerationStamp() < getGenerationStampV1Limit(); 184 } 185 186 /** 187 * Increments, logs and then returns the block ID 188 */ 189 public long nextBlockId() { 190 return blockIdGenerator.nextValue(); 191 } 192 193 public boolean isGenStampInFuture(Block block) { 194 if (isLegacyBlock(block)) { 195 return block.getGenerationStamp() > getGenerationStampV1(); 196 } else { 197 return block.getGenerationStamp() > getGenerationStampV2(); 198 } 199 } 200 201 public void clear() { 202 generationStampV1.setCurrentValue(GenerationStamp.LAST_RESERVED_STAMP); 203 generationStampV2.setCurrentValue(GenerationStamp.LAST_RESERVED_STAMP); 204 getBlockIdGenerator().setCurrentValue(SequentialBlockIdGenerator 205 .LAST_RESERVED_BLOCK_ID); 206 generationStampV1Limit = GenerationStamp.GRANDFATHER_GENERATION_STAMP; 207 } 208}