Quellcode durchsuchen

HDFS-14305. Fix serial number calculation in BlockTokenSecretManager to avoid token key ID overlap between NameNodes. Contributed by He Xiaoqiao.

Erik Krogen vor 6 Jahren
Ursprung
Commit
b170626c74

+ 15 - 6
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<BlockTokenIdentifier> DUMMY_TOKEN = new Token<BlockTokenIdentifier>();
 
+  /**
+   * 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) {

+ 30 - 1
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 {