diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/security/token/block/BlockTokenSecretManager.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/security/token/block/BlockTokenSecretManager.java index 001544cde7..58018963ef 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/security/token/block/BlockTokenSecretManager.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/security/token/block/BlockTokenSecretManager.java @@ -63,6 +63,17 @@ public class BlockTokenSecretManager extends public static final Token DUMMY_TOKEN = new Token(); + /** + * In order to prevent serial No. of different NameNode from overlapping, + * Using 6 bits (identify 64=2^6 namenodes, and presuppose that no scenario + * where deploy more than 64 namenodes (include ANN, SBN, Observers, etc.) + * in one namespace) to identify index of NameNode, and the remainder 26 bits + * auto-incr to change the serial No. + */ + @VisibleForTesting + public static final int NUM_VALID_BITS = 26; + private static final int LOW_MASK = (1 << NUM_VALID_BITS) - 1; + private final boolean isMaster; /** @@ -79,8 +90,8 @@ public class BlockTokenSecretManager extends private String blockPoolId; private final String encryptionAlgorithm; - private final int intRange; - private final int nnRangeStart; + private final int nnIndex; + private final boolean useProto; private final SecureRandom nonceGenerator = new SecureRandom(); @@ -129,8 +140,7 @@ public class BlockTokenSecretManager extends private BlockTokenSecretManager(boolean isMaster, long keyUpdateInterval, long tokenLifetime, String blockPoolId, String encryptionAlgorithm, int nnIndex, int numNNs, boolean useProto) { - this.intRange = Integer.MAX_VALUE / numNNs; - this.nnRangeStart = intRange * nnIndex; + this.nnIndex = nnIndex; this.isMaster = isMaster; this.keyUpdateInterval = keyUpdateInterval; this.tokenLifetime = tokenLifetime; @@ -144,8 +154,7 @@ public class BlockTokenSecretManager extends @VisibleForTesting public synchronized void setSerialNo(int serialNo) { - // we mod the serial number by the range and then add that times the index - this.serialNo = (serialNo % intRange) + (nnRangeStart); + this.serialNo = (serialNo & LOW_MASK) | (nnIndex << NUM_VALID_BITS); } public void setBlockPoolId(String blockPoolId) { diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestFailoverWithBlockTokensEnabled.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestFailoverWithBlockTokensEnabled.java index 43ab69d82d..850b96173a 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestFailoverWithBlockTokensEnabled.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/server/namenode/ha/TestFailoverWithBlockTokensEnabled.java @@ -116,7 +116,36 @@ public class TestFailoverWithBlockTokensEnabled { } } } - + + @Test + public void testSerialNumberMaskMatchIndex() { + BlockTokenSecretManager btsm1 = cluster.getNamesystem(0).getBlockManager() + .getBlockTokenSecretManager(); + BlockTokenSecretManager btsm2 = cluster.getNamesystem(1).getBlockManager() + .getBlockTokenSecretManager(); + BlockTokenSecretManager btsm3 = cluster.getNamesystem(2).getBlockManager() + .getBlockTokenSecretManager(); + int[] testSet = {0, Integer.MAX_VALUE, Integer.MIN_VALUE, + Integer.MAX_VALUE / 2, Integer.MIN_VALUE / 2, + Integer.MAX_VALUE / 3, Integer.MIN_VALUE / 3}; + for (int i = 0; i < testSet.length; i++) { + setAndCheckHighBitsSerialNumber(testSet[i], btsm1, 0); + setAndCheckHighBitsSerialNumber(testSet[i], btsm2, 1); + setAndCheckHighBitsSerialNumber(testSet[i], btsm3, 2); + } + } + + /** + * Check mask of serial number if equal to index of NameNode. + */ + private void setAndCheckHighBitsSerialNumber(int serialNumber, + BlockTokenSecretManager btsm, int nnIndex) { + btsm.setSerialNo(serialNumber); + int serialNo = btsm.getSerialNoForTesting(); + int index = serialNo >> BlockTokenSecretManager.NUM_VALID_BITS; + assertEquals(index, nnIndex); + } + @Test public void ensureInvalidBlockTokensAreRejected() throws IOException, URISyntaxException {