From ea3e7b82880f4da53802c5c75e6b3ceb2f206212 Mon Sep 17 00:00:00 2001 From: Yiqun Lin Date: Wed, 9 Jan 2019 17:18:43 +0800 Subject: [PATCH] HDFS-14150. RBF: Quotas of the sub-cluster should be removed when removing the mount point. Contributed by Takanobu Asanuma. --- .../federation/router/RouterAdminServer.java | 23 +++++---- .../src/main/resources/hdfs-rbf-default.xml | 4 +- .../src/site/markdown/HDFSRouterFederation.md | 4 +- .../federation/router/TestRouterQuota.java | 48 ++++++++++++++++++- 4 files changed, 67 insertions(+), 12 deletions(-) diff --git a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/RouterAdminServer.java b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/RouterAdminServer.java index 5bb7751cd1e..18c19e087e8 100644 --- a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/RouterAdminServer.java +++ b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/router/RouterAdminServer.java @@ -250,23 +250,25 @@ public class RouterAdminServer extends AbstractService MountTable mountTable = request.getEntry(); if (mountTable != null && router.isQuotaEnabled()) { - synchronizeQuota(mountTable); + synchronizeQuota(mountTable.getSourcePath(), + mountTable.getQuota().getQuota(), + mountTable.getQuota().getSpaceQuota()); } return response; } /** * Synchronize the quota value across mount table and subclusters. - * @param mountTable Quota set in given mount table. + * @param path Source path in given mount table. + * @param nsQuota Name quota definition in given mount table. + * @param ssQuota Space quota definition in given mount table. * @throws IOException */ - private void synchronizeQuota(MountTable mountTable) throws IOException { - String path = mountTable.getSourcePath(); - long nsQuota = mountTable.getQuota().getQuota(); - long ssQuota = mountTable.getQuota().getSpaceQuota(); - - if (nsQuota != HdfsConstants.QUOTA_DONT_SET - || ssQuota != HdfsConstants.QUOTA_DONT_SET) { + private void synchronizeQuota(String path, long nsQuota, long ssQuota) + throws IOException { + if (router.isQuotaEnabled() && + (nsQuota != HdfsConstants.QUOTA_DONT_SET + || ssQuota != HdfsConstants.QUOTA_DONT_SET)) { HdfsFileStatus ret = this.router.getRpcServer().getFileInfo(path); if (ret != null) { this.router.getRpcServer().getQuotaModule().setQuota(path, nsQuota, @@ -278,6 +280,9 @@ public class RouterAdminServer extends AbstractService @Override public RemoveMountTableEntryResponse removeMountTableEntry( RemoveMountTableEntryRequest request) throws IOException { + // clear sub-cluster's quota definition + synchronizeQuota(request.getSrcPath(), HdfsConstants.QUOTA_RESET, + HdfsConstants.QUOTA_RESET); return getMountTableStore().removeMountTableEntry(request); } diff --git a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/resources/hdfs-rbf-default.xml b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/resources/hdfs-rbf-default.xml index 72f6c2f1104..20ae778ef1d 100644 --- a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/resources/hdfs-rbf-default.xml +++ b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/resources/hdfs-rbf-default.xml @@ -447,7 +447,9 @@ dfs.federation.router.quota.enable false - Set to true to enable quota system in Router. + Set to true to enable quota system in Router. When it's enabled, setting + or clearing sub-cluster's quota directly is not recommended since Router + Admin server will override sub-cluster's quota with global quota. diff --git a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/site/markdown/HDFSRouterFederation.md b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/site/markdown/HDFSRouterFederation.md index adc43838fe5..959cd637dd9 100644 --- a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/site/markdown/HDFSRouterFederation.md +++ b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/site/markdown/HDFSRouterFederation.md @@ -143,6 +143,8 @@ For performance reasons, the Router caches the quota usage and updates it period will be used for quota-verification during each WRITE RPC call invoked in RouterRPCSever. See [HDFS Quotas Guide](../hadoop-hdfs/HdfsQuotaAdminGuide.html) for the quota detail. +Note: When global quota is enabled, setting or clearing sub-cluster's quota directly is not recommended since Router Admin server will override sub-cluster's quota with global quota. + ### State Store The (logically centralized, but physically distributed) State Store maintains: @@ -421,7 +423,7 @@ Global quota supported in federation. | Property | Default | Description| |:---- |:---- |:---- | -| dfs.federation.router.quota.enable | `false` | If `true`, the quota system enabled in the Router. | +| dfs.federation.router.quota.enable | `false` | If `true`, the quota system enabled in the Router. In that case, setting or clearing sub-cluster's quota directly is not recommended since Router Admin server will override sub-cluster's quota with global quota.| | dfs.federation.router.quota-cache.update.interval | 60s | How often the Router updates quota cache. This setting supports multiple time unit suffixes. If no suffix is specified then milliseconds is assumed. | Metrics diff --git a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/test/java/org/apache/hadoop/hdfs/server/federation/router/TestRouterQuota.java b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/test/java/org/apache/hadoop/hdfs/server/federation/router/TestRouterQuota.java index 6a29446f802..656b401ec24 100644 --- a/hadoop-hdfs-project/hadoop-hdfs-rbf/src/test/java/org/apache/hadoop/hdfs/server/federation/router/TestRouterQuota.java +++ b/hadoop-hdfs-project/hadoop-hdfs-rbf/src/test/java/org/apache/hadoop/hdfs/server/federation/router/TestRouterQuota.java @@ -605,7 +605,7 @@ public class TestRouterQuota { @Test public void testQuotaRefreshWhenDestinationNotPresent() throws Exception { long nsQuota = 5; - long ssQuota = 3*BLOCK_SIZE; + long ssQuota = 3 * BLOCK_SIZE; final FileSystem nnFs = nnContext1.getFileSystem(); // Add three mount tables: @@ -709,4 +709,50 @@ public class TestRouterQuota { assertEquals(updatedSpace, cacheQuota2.getSpaceConsumed()); assertEquals(updatedSpace, mountQuota2.getSpaceConsumed()); } + + @Test + public void testClearQuotaDefAfterRemovingMountTable() throws Exception { + long nsQuota = 5; + long ssQuota = 3 * BLOCK_SIZE; + final FileSystem nnFs = nnContext1.getFileSystem(); + + // Add one mount tables: + // /setdir --> ns0---testdir15 + // Create destination directory + nnFs.mkdirs(new Path("/testdir15")); + + MountTable mountTable = MountTable.newInstance("/setdir", + Collections.singletonMap("ns0", "/testdir15")); + mountTable.setQuota(new RouterQuotaUsage.Builder().quota(nsQuota) + .spaceQuota(ssQuota).build()); + addMountTable(mountTable); + + // Update router quota + RouterQuotaUpdateService updateService = + routerContext.getRouter().getQuotaCacheUpdateService(); + updateService.periodicInvoke(); + + RouterQuotaManager quotaManager = + routerContext.getRouter().getQuotaManager(); + ClientProtocol client = nnContext1.getClient().getNamenode(); + QuotaUsage routerQuota = quotaManager.getQuotaUsage("/setdir"); + QuotaUsage subClusterQuota = client.getQuotaUsage("/testdir15"); + + // Verify current quota definitions + assertEquals(nsQuota, routerQuota.getQuota()); + assertEquals(ssQuota, routerQuota.getSpaceQuota()); + assertEquals(nsQuota, subClusterQuota.getQuota()); + assertEquals(ssQuota, subClusterQuota.getSpaceQuota()); + + // Remove mount table + removeMountTable("/setdir"); + updateService.periodicInvoke(); + routerQuota = quotaManager.getQuotaUsage("/setdir"); + subClusterQuota = client.getQuotaUsage("/testdir15"); + + // Verify quota definitions are cleared after removing the mount table + assertNull(routerQuota); + assertEquals(HdfsConstants.QUOTA_RESET, subClusterQuota.getQuota()); + assertEquals(HdfsConstants.QUOTA_RESET, subClusterQuota.getSpaceQuota()); + } } \ No newline at end of file