This is an automated email from the ASF dual-hosted git repository.
neuyilan pushed a commit to branch multi_tenancy
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/multi_tenancy by this push:
new 06076ebe11 [IOTDB-4836] Add spaceQuotaFrame (#7916)
06076ebe11 is described below
commit 06076ebe11da07c68b1106ba75b4513276bccbd2
Author: 任宇华 <[email protected]>
AuthorDate: Wed Nov 9 11:48:30 2022 +0800
[IOTDB-4836] Add spaceQuotaFrame (#7916)
---
.../org/apache/iotdb/db/qp/sql/IdentifierParser.g4 | 2 +
.../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 | 7 +-
.../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 | 8 ++
.../iotdb/confignode/conf/ConfigNodeConfig.java | 34 +++++++
.../confignode/conf/ConfigNodeStartupCheck.java | 8 ++
.../consensus/request/ConfigPhysicalPlan.java | 4 +
.../consensus/request/ConfigPhysicalPlanType.java | 5 +-
.../request/write/quota/SetSpaceQuotaPlan.java | 101 +++++++++++++++++++++
.../confignode/manager/ClusterQuotaManager.java | 62 +++++++++++++
.../iotdb/confignode/manager/ConfigManager.java | 18 +++-
.../apache/iotdb/confignode/manager/IManager.java | 3 +
.../iotdb/confignode/persistence/QuotaInfo.java | 67 ++++++++++++++
.../persistence/executor/ConfigPlanExecutor.java | 11 ++-
.../thrift/ConfigNodeRPCServiceProcessor.java | 6 ++
.../request/ConfigPhysicalPlanSerDeTest.java | 16 ++++
.../persistence/quota/QuotaInfoTest.java | 23 +++++
.../java/org/apache/iotdb/db/it/IoTDBQuotaIT.java | 58 ++++++++++++
.../resources/conf/iotdb-common.properties | 8 +-
.../apache/iotdb/commons/conf/IoTDBConstant.java | 8 ++
.../apache/iotdb/commons/enums/SpaceQuotaType.java | 26 ++++++
.../commons/utils/BasicStructureSerDeUtil.java | 16 ++++
.../apache/iotdb/db/client/ConfigNodeClient.java | 17 ++++
.../java/org/apache/iotdb/db/conf/IoTDBConfig.java | 50 ++++++++++
.../org/apache/iotdb/db/conf/IoTDBDescriptor.java | 4 +
.../iotdb/db/localconfignode/LocalConfigNode.java | 29 ++++--
.../iotdb/db/mpp/plan/constant/StatementType.java | 2 +
.../plan/execution/config/ConfigTaskVisitor.java | 8 ++
.../config/executor/ClusterConfigTaskExecutor.java | 30 ++++++
.../config/executor/IConfigTaskExecutor.java | 3 +
.../executor/StandaloneConfigTaskExecutor.java | 12 +++
.../config/sys/quota/SetSpaceQuotaTask.java | 42 +++++++++
.../iotdb/db/mpp/plan/parser/ASTVisitor.java | 56 ++++++++++++
.../db/mpp/plan/statement/StatementVisitor.java | 5 +
.../sys/quota/SetSpaceQuotaStatement.java | 100 ++++++++++++++++++++
.../apache/iotdb/db/quotas/DataNodeSizeStore.java | 24 +++++
.../iotdb/db/quotas/DataNodeSpaceQuotaManager.java | 34 +++++++
.../db/quotas/SpaceViolationPolicyEnforcement.java | 23 +++++
.../apache/iotdb/db/utils/EnvironmentUtils.java | 4 +
thrift-commons/src/main/thrift/common.thrift | 7 ++
.../src/main/thrift/confignode.thrift | 10 ++
40 files changed, 939 insertions(+), 12 deletions(-)
diff --git
a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
index fb108cb96e..e72b5f8339 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
@@ -136,6 +136,7 @@ keyWords
| PRUNE
| QUERIES
| QUERY
+ | QUOTA
| RANGE
| READONLY
| REGEXP
@@ -157,6 +158,7 @@ keyWords
| SHOW
| SLIMIT
| SOFFSET
+ | SPACE
| STORAGE
| START
| STARTTIME
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 51cb8f178d..b886dba4a2 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -40,7 +40,7 @@ ddlStatement
| createFunction | createTrigger | createContinuousQuery
| alterTimeseries | deleteStorageGroup | deleteTimeseries |
deletePartition | deleteTimeseriesOfSchemaTemplate
| dropFunction | dropTrigger | dropContinuousQuery | dropSchemaTemplate
- | setTTL | unsetTTL | startTrigger | stopTrigger | setSchemaTemplate |
unsetSchemaTemplate
+ | setTTL | unsetTTL | startTrigger | stopTrigger | setSchemaTemplate |
unsetSchemaTemplate | setSpaceQuota
| showStorageGroup | showDevices | showTimeseries | showChildPaths |
showChildNodes
| showFunctions | showTriggers | showContinuousQueries | showTTL |
showAllTTL | showCluster | showRegion | showDataNodes | showConfigNodes
| showSchemaTemplates | showNodesInSchemaTemplate
@@ -274,6 +274,11 @@ unsetSchemaTemplate
: UNSET SCHEMA? TEMPLATE templateName=identifier FROM prefixPath
;
+// Set Space Quota
+setSpaceQuota
+ : SET SPACE QUOTA attributePair (COMMA attributePair)* ON prefixPath
(COMMA prefixPath)*
+ ;
+
// Start Trigger
startTrigger
: START TRIGGER triggerName=identifier
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
index a6141a614e..da94da2c9f 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
@@ -458,6 +458,10 @@ QUERY
: Q U E R Y
;
+QUOTA
+ : Q U O T A
+ ;
+
RANGE
: R A N G E
;
@@ -546,6 +550,10 @@ SOFFSET
: S O F F S E T
;
+SPACE
+ : S P A C E
+ ;
+
STORAGE
: S T O R A G E
;
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
index 3990b02f48..348b4f57d8 100644
---
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
+++
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
@@ -113,6 +113,22 @@ public class ConfigNodeConfig {
private String temporaryLibDir =
IoTDBConstant.EXT_FOLDER_NAME + File.separator +
IoTDBConstant.UDF_TMP_FOLDER_NAME;
+ /** Space quota directory, stores space quota information of each storage
group */
+ private String spaceQuotaDir =
+ systemDir
+ + File.separator
+ + IoTDBConstant.QUOTA_FOLDER_NAME
+ + File.separator
+ + IoTDBConstant.SPACE_QUOTA_FOLDER_NAME;
+
+ /** Throttle quota directory, stores throttle quota information of each
storage group */
+ private String throttleQuotaDir =
+ systemDir
+ + File.separator
+ + IoTDBConstant.QUOTA_FOLDER_NAME
+ + File.separator
+ + IoTDBConstant.THROTTLE_QUOTA_FOLDER_NAME;
+
/** Time partition interval in milliseconds */
private long timePartitionInterval = 604_800_000;
@@ -238,6 +254,8 @@ public class ConfigNodeConfig {
udfLibDir = addHomeDir(udfLibDir);
temporaryLibDir = addHomeDir(temporaryLibDir);
triggerLibDir = addHomeDir(triggerLibDir);
+ spaceQuotaDir = addHomeDir(spaceQuotaDir);
+ throttleQuotaDir = addHomeDir(throttleQuotaDir);
}
private String addHomeDir(String dir) {
@@ -465,6 +483,22 @@ public class ConfigNodeConfig {
this.temporaryLibDir = temporaryLibDir;
}
+ public String getSpaceQuotaDir() {
+ return spaceQuotaDir;
+ }
+
+ public void setSpaceQuotaDir(String spaceQuotaDir) {
+ this.spaceQuotaDir = spaceQuotaDir;
+ }
+
+ public String getThrottleQuotaDir() {
+ return throttleQuotaDir;
+ }
+
+ public void setThrottleQuotaDir(String throttleQuotaDir) {
+ this.throttleQuotaDir = throttleQuotaDir;
+ }
+
public int getSchemaReplicationFactor() {
return schemaReplicationFactor;
}
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java
index 9b91c9ca84..b23e9f474b 100644
---
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java
+++
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java
@@ -114,6 +114,14 @@ public class ConfigNodeStartupCheck {
// If consensusDir does not exist, create consensusDir
File consensusDir = new File(CONF.getConsensusDir());
createDirIfEmpty(consensusDir);
+
+ // If spaceQuotaDir does not exist, create spaceQuotaDir
+ File spaceQuotaDir = new File(CONF.getSpaceQuotaDir());
+ createDirIfEmpty(spaceQuotaDir);
+
+ // If throttleQuotaDir does not exist, create throttleQuotaDir
+ File throttleQuotaDir = new File(CONF.getThrottleQuotaDir());
+ createDirIfEmpty(throttleQuotaDir);
}
private void createDirIfEmpty(File dir) throws IOException {
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
b/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
index d69b620848..59c0bdb0d9 100644
---
a/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
+++
b/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlan.java
@@ -61,6 +61,7 @@ import
org.apache.iotdb.confignode.consensus.request.write.partition.CreateSchem
import
org.apache.iotdb.confignode.consensus.request.write.partition.UpdateRegionLocationPlan;
import
org.apache.iotdb.confignode.consensus.request.write.procedure.DeleteProcedurePlan;
import
org.apache.iotdb.confignode.consensus.request.write.procedure.UpdateProcedurePlan;
+import
org.apache.iotdb.confignode.consensus.request.write.quota.SetSpaceQuotaPlan;
import
org.apache.iotdb.confignode.consensus.request.write.region.CreateRegionGroupsPlan;
import
org.apache.iotdb.confignode.consensus.request.write.region.OfferRegionMaintainTasksPlan;
import
org.apache.iotdb.confignode.consensus.request.write.region.PollRegionMaintainTaskPlan;
@@ -379,6 +380,9 @@ public abstract class ConfigPhysicalPlan implements
IConsensusRequest {
case GetFunctionJar:
plan = new GetUDFJarPlan();
break;
+ case SET_SPACE_QUOTA:
+ plan = new SetSpaceQuotaPlan();
+ break;
default:
throw new IOException("unknown PhysicalPlan configPhysicalPlanType:
" + planType);
}
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
b/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
index d549ca450c..dd8ffdfdc4 100644
---
a/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
+++
b/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
@@ -136,7 +136,10 @@ public enum ConfigPhysicalPlanType {
ACTIVE_CQ((short) 1101),
ADD_CQ((short) 1102),
UPDATE_CQ_LAST_EXEC_TIME((short) 1103),
- SHOW_CQ((short) 1104);
+ SHOW_CQ((short) 1104),
+
+ /** Quota */
+ SET_SPACE_QUOTA((short) 1200);
private final short planType;
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/quota/SetSpaceQuotaPlan.java
b/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/quota/SetSpaceQuotaPlan.java
new file mode 100644
index 0000000000..0ec2f38a99
--- /dev/null
+++
b/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/quota/SetSpaceQuotaPlan.java
@@ -0,0 +1,101 @@
+/*
+ * 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.iotdb.confignode.consensus.request.write.quota;
+
+import org.apache.iotdb.common.rpc.thrift.TSpaceQuota;
+import org.apache.iotdb.commons.utils.BasicStructureSerDeUtil;
+import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlan;
+import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Objects;
+
+public class SetSpaceQuotaPlan extends ConfigPhysicalPlan {
+
+ private List<String> prefixPathList;
+ private TSpaceQuota spaceLimit;
+
+ public SetSpaceQuotaPlan() {
+ super(ConfigPhysicalPlanType.SET_SPACE_QUOTA);
+ }
+
+ public SetSpaceQuotaPlan(List<String> prefixPathList, TSpaceQuota
spaceLimit) {
+ super(ConfigPhysicalPlanType.SET_SPACE_QUOTA);
+ this.prefixPathList = prefixPathList;
+ this.spaceLimit = spaceLimit;
+ }
+
+ public List<String> getPrefixPathList() {
+ return prefixPathList;
+ }
+
+ public void setPrefixPathList(List<String> prefixPathList) {
+ this.prefixPathList = prefixPathList;
+ }
+
+ public TSpaceQuota getSpaceLimit() {
+ return spaceLimit;
+ }
+
+ public void setSpaceLimit(TSpaceQuota spaceLimit) {
+ this.spaceLimit = spaceLimit;
+ }
+
+ @Override
+ protected void serializeImpl(DataOutputStream stream) throws IOException {
+ stream.writeShort(getType().getPlanType());
+ BasicStructureSerDeUtil.write(prefixPathList, stream);
+ BasicStructureSerDeUtil.write(spaceLimit.getDeviceNum(), stream);
+ BasicStructureSerDeUtil.write(spaceLimit.getTimeserieNum(), stream);
+ BasicStructureSerDeUtil.write(spaceLimit.getDisk(), stream);
+ }
+
+ @Override
+ protected void deserializeImpl(ByteBuffer buffer) throws IOException {
+ List<String> prefixPathList =
BasicStructureSerDeUtil.readStringList(buffer);
+ int deviceNum = BasicStructureSerDeUtil.readInt(buffer);
+ int timeserieNum = BasicStructureSerDeUtil.readInt(buffer);
+ long disk = BasicStructureSerDeUtil.readLong(buffer);
+ this.prefixPathList = prefixPathList;
+ TSpaceQuota spaceLimit = new TSpaceQuota();
+ spaceLimit.setDeviceNum(deviceNum);
+ spaceLimit.setTimeserieNum(timeserieNum);
+ spaceLimit.setDisk(disk);
+ this.spaceLimit = spaceLimit;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
+ SetSpaceQuotaPlan that = (SetSpaceQuotaPlan) o;
+ return Objects.equals(prefixPathList, that.prefixPathList)
+ && Objects.equals(spaceLimit, that.spaceLimit);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), prefixPathList, spaceLimit);
+ }
+}
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterQuotaManager.java
b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterQuotaManager.java
new file mode 100644
index 0000000000..a7c4939ed2
--- /dev/null
+++
b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterQuotaManager.java
@@ -0,0 +1,62 @@
+/*
+ * 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.iotdb.confignode.manager;
+
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import
org.apache.iotdb.confignode.consensus.request.write.quota.SetSpaceQuotaPlan;
+import org.apache.iotdb.confignode.persistence.QuotaInfo;
+import org.apache.iotdb.confignode.rpc.thrift.TSetSpaceQuotaReq;
+import org.apache.iotdb.consensus.common.response.ConsensusWriteResponse;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// TODO: Manage quotas for storage groups
+public class ClusterQuotaManager {
+
+ private static final Logger LOGGER =
LoggerFactory.getLogger(ClusterQuotaManager.class);
+
+ private final IManager configManager;
+ private final QuotaInfo quotaInfo;
+
+ public ClusterQuotaManager(IManager configManager, QuotaInfo quotaInfo) {
+ this.configManager = configManager;
+ this.quotaInfo = quotaInfo;
+ }
+
+ public TSStatus setSpaceQuota(TSetSpaceQuotaReq req) {
+ ConsensusWriteResponse response =
+ configManager
+ .getConsensusManager()
+ .write(new SetSpaceQuotaPlan(req.getStorageGroup(),
req.getSpaceLimit()));
+ if (response.getStatus() != null) {
+ return response.getStatus();
+ } else {
+ LOGGER.warn(
+ "Unexpected error happened while setting space quota on {}: ",
+ req.getStorageGroup().toString(),
+ response.getException());
+ // consensus layer related errors
+ TSStatus res = new
TSStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode());
+ res.setMessage(response.getErrorMessage());
+ return res;
+ }
+ }
+}
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index e2d793958d..ed247ae940 100644
---
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
+++
b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
@@ -82,6 +82,7 @@ import org.apache.iotdb.confignode.manager.node.NodeManager;
import org.apache.iotdb.confignode.manager.partition.PartitionManager;
import org.apache.iotdb.confignode.persistence.AuthorInfo;
import org.apache.iotdb.confignode.persistence.ProcedureInfo;
+import org.apache.iotdb.confignode.persistence.QuotaInfo;
import org.apache.iotdb.confignode.persistence.TriggerInfo;
import org.apache.iotdb.confignode.persistence.UDFInfo;
import org.apache.iotdb.confignode.persistence.cq.CQInfo;
@@ -123,6 +124,7 @@ import
org.apache.iotdb.confignode.rpc.thrift.TSchemaNodeManagementResp;
import org.apache.iotdb.confignode.rpc.thrift.TSchemaPartitionTableResp;
import org.apache.iotdb.confignode.rpc.thrift.TSetDataNodeStatusReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetSchemaTemplateReq;
+import org.apache.iotdb.confignode.rpc.thrift.TSetSpaceQuotaReq;
import org.apache.iotdb.confignode.rpc.thrift.TShowCQResp;
import org.apache.iotdb.confignode.rpc.thrift.TShowClusterResp;
import org.apache.iotdb.confignode.rpc.thrift.TShowConfigNodesResp;
@@ -194,6 +196,9 @@ public class ConfigManager implements IManager {
/** CQ */
private final CQManager cqManager;
+ /** Manage quotas for storage groups */
+ private final ClusterQuotaManager clusterQuotaManager;
+
private final PartitionRegionStateMachine stateMachine;
public ConfigManager() throws IOException {
@@ -207,6 +212,7 @@ public class ConfigManager implements IManager {
TriggerInfo triggerInfo = new TriggerInfo();
ClusterSyncInfo syncInfo = new ClusterSyncInfo();
CQInfo cqInfo = new CQInfo();
+ QuotaInfo quotaInfo = new QuotaInfo();
// Build state machine and executor
ConfigPlanExecutor executor =
@@ -219,7 +225,8 @@ public class ConfigManager implements IManager {
udfInfo,
triggerInfo,
syncInfo,
- cqInfo);
+ cqInfo,
+ quotaInfo);
this.stateMachine = new PartitionRegionStateMachine(this, executor);
// Build the manager module
@@ -233,6 +240,7 @@ public class ConfigManager implements IManager {
this.loadManager = new LoadManager(this);
this.syncManager = new SyncManager(this, syncInfo);
this.cqManager = new CQManager(this);
+ this.clusterQuotaManager = new ClusterQuotaManager(this, quotaInfo);
}
public void initConsensusManager() throws IOException {
@@ -1310,6 +1318,14 @@ public class ConfigManager implements IManager {
: new TShowCQResp(status, Collections.emptyList());
}
+ @Override
+ public TSStatus setSpaceQuota(TSetSpaceQuotaReq req) {
+ TSStatus status = confirmLeader();
+ return status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()
+ ? clusterQuotaManager.setSpaceQuota(req)
+ : status;
+ }
+
/** Get all related schemaRegion which may contains the timeSeries matched
by given patternTree */
public Map<TConsensusGroupId, TRegionReplicaSet> getRelatedSchemaRegionGroup(
PathPatternTree patternTree) {
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java
b/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java
index ac77ab2954..c71a18f043 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java
@@ -82,6 +82,7 @@ import
org.apache.iotdb.confignode.rpc.thrift.TSchemaNodeManagementResp;
import org.apache.iotdb.confignode.rpc.thrift.TSchemaPartitionTableResp;
import org.apache.iotdb.confignode.rpc.thrift.TSetDataNodeStatusReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetSchemaTemplateReq;
+import org.apache.iotdb.confignode.rpc.thrift.TSetSpaceQuotaReq;
import org.apache.iotdb.confignode.rpc.thrift.TShowCQResp;
import org.apache.iotdb.confignode.rpc.thrift.TShowClusterResp;
import org.apache.iotdb.confignode.rpc.thrift.TShowConfigNodesResp;
@@ -531,6 +532,8 @@ public interface IManager {
TShowCQResp showCQ();
+ TSStatus setSpaceQuota(TSetSpaceQuotaReq req);
+
TSStatus checkConfigNodeGlobalConfig(TConfigNodeRegisterReq req);
TSStatus transfer(List<TDataNodeLocation> newUnknownDataList);
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/QuotaInfo.java
b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/QuotaInfo.java
new file mode 100644
index 0000000000..026d11e13d
--- /dev/null
+++
b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/QuotaInfo.java
@@ -0,0 +1,67 @@
+/*
+ * 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.iotdb.confignode.persistence;
+
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.common.rpc.thrift.TSpaceQuota;
+import org.apache.iotdb.commons.snapshot.SnapshotProcessor;
+import
org.apache.iotdb.confignode.consensus.request.write.quota.SetSpaceQuotaPlan;
+import org.apache.iotdb.rpc.RpcUtils;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.apache.thrift.TException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+// TODO: Store quota information of each sg
+public class QuotaInfo implements SnapshotProcessor {
+
+ private static final Logger logger =
LoggerFactory.getLogger(QuotaInfo.class);
+ private final Map<String, TSpaceQuota> spaceQuotaLimit;
+ private final Map<String, TSpaceQuota> useSpaceQuota;
+ private final Map<Integer, Integer> regionDisk;
+
+ public QuotaInfo() {
+ spaceQuotaLimit = new HashMap<>();
+ useSpaceQuota = new HashMap<>();
+ regionDisk = new HashMap<>();
+ }
+
+ public TSStatus setSpaceQuota(SetSpaceQuotaPlan setSpaceQuotaPlan) {
+ for (String storageGroup : setSpaceQuotaPlan.getPrefixPathList()) {
+ spaceQuotaLimit.put(storageGroup, setSpaceQuotaPlan.getSpaceLimit());
+ }
+ return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS);
+ }
+
+ // TODO: add Snapshot
+ @Override
+ public boolean processTakeSnapshot(File snapshotDir) throws TException,
IOException {
+ return false;
+ }
+
+ @Override
+ public void processLoadSnapshot(File snapshotDir) throws TException,
IOException {}
+}
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
index b08e4059ef..886362b284 100644
---
a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
+++
b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
@@ -60,6 +60,7 @@ import
org.apache.iotdb.confignode.consensus.request.write.partition.CreateSchem
import
org.apache.iotdb.confignode.consensus.request.write.partition.UpdateRegionLocationPlan;
import
org.apache.iotdb.confignode.consensus.request.write.procedure.DeleteProcedurePlan;
import
org.apache.iotdb.confignode.consensus.request.write.procedure.UpdateProcedurePlan;
+import
org.apache.iotdb.confignode.consensus.request.write.quota.SetSpaceQuotaPlan;
import
org.apache.iotdb.confignode.consensus.request.write.region.CreateRegionGroupsPlan;
import
org.apache.iotdb.confignode.consensus.request.write.region.OfferRegionMaintainTasksPlan;
import
org.apache.iotdb.confignode.consensus.request.write.storagegroup.AdjustMaxRegionGroupCountPlan;
@@ -92,6 +93,7 @@ import
org.apache.iotdb.confignode.consensus.response.SchemaNodeManagementResp;
import
org.apache.iotdb.confignode.exception.physical.UnknownPhysicalPlanTypeException;
import org.apache.iotdb.confignode.persistence.AuthorInfo;
import org.apache.iotdb.confignode.persistence.ProcedureInfo;
+import org.apache.iotdb.confignode.persistence.QuotaInfo;
import org.apache.iotdb.confignode.persistence.TriggerInfo;
import org.apache.iotdb.confignode.persistence.UDFInfo;
import org.apache.iotdb.confignode.persistence.cq.CQInfo;
@@ -145,6 +147,8 @@ public class ConfigPlanExecutor {
private final CQInfo cqInfo;
+ private final QuotaInfo quotaInfo;
+
public ConfigPlanExecutor(
NodeInfo nodeInfo,
ClusterSchemaInfo clusterSchemaInfo,
@@ -154,7 +158,8 @@ public class ConfigPlanExecutor {
UDFInfo udfInfo,
TriggerInfo triggerInfo,
ClusterSyncInfo syncInfo,
- CQInfo cqInfo) {
+ CQInfo cqInfo,
+ QuotaInfo quotaInfo) {
this.snapshotProcessorList = new ArrayList<>();
@@ -183,6 +188,8 @@ public class ConfigPlanExecutor {
this.snapshotProcessorList.add(cqInfo);
this.procedureInfo = procedureInfo;
+
+ this.quotaInfo = quotaInfo;
}
public DataSet executeQueryPlan(ConfigPhysicalPlan req)
@@ -365,6 +372,8 @@ public class ConfigPlanExecutor {
return cqInfo.activeCQ((ActiveCQPlan) physicalPlan);
case UPDATE_CQ_LAST_EXEC_TIME:
return cqInfo.updateCQLastExecutionTime((UpdateCQLastExecTimePlan)
physicalPlan);
+ case SET_SPACE_QUOTA:
+ return quotaInfo.setSpaceQuota((SetSpaceQuotaPlan) physicalPlan);
default:
throw new UnknownPhysicalPlanTypeException(physicalPlan.getType());
}
diff --git
a/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
b/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
index 383d413e31..37ea98aa2c 100644
---
a/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
+++
b/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
@@ -124,6 +124,7 @@ import
org.apache.iotdb.confignode.rpc.thrift.TSetDataNodeStatusReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetDataReplicationFactorReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetSchemaReplicationFactorReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetSchemaTemplateReq;
+import org.apache.iotdb.confignode.rpc.thrift.TSetSpaceQuotaReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetStorageGroupReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetTimePartitionIntervalReq;
import org.apache.iotdb.confignode.rpc.thrift.TShowCQResp;
@@ -765,4 +766,9 @@ public class ConfigNodeRPCServiceProcessor implements
IConfigNodeRPCService.Ifac
public TShowCQResp showCQ() {
return configManager.showCQ();
}
+
+ @Override
+ public TSStatus setSpaceQuota(TSetSpaceQuotaReq req) throws TException {
+ return configManager.setSpaceQuota(req);
+ }
}
diff --git
a/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java
b/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java
index 66a9a60350..bb4901a819 100644
---
a/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java
+++
b/confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanSerDeTest.java
@@ -27,6 +27,7 @@ import org.apache.iotdb.common.rpc.thrift.TEndPoint;
import org.apache.iotdb.common.rpc.thrift.TNodeResource;
import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
import org.apache.iotdb.common.rpc.thrift.TSeriesPartitionSlot;
+import org.apache.iotdb.common.rpc.thrift.TSpaceQuota;
import org.apache.iotdb.common.rpc.thrift.TTimePartitionSlot;
import org.apache.iotdb.commons.auth.AuthException;
import org.apache.iotdb.commons.auth.entity.PrivilegeType;
@@ -76,6 +77,7 @@ import
org.apache.iotdb.confignode.consensus.request.write.partition.CreateDataP
import
org.apache.iotdb.confignode.consensus.request.write.partition.CreateSchemaPartitionPlan;
import
org.apache.iotdb.confignode.consensus.request.write.procedure.DeleteProcedurePlan;
import
org.apache.iotdb.confignode.consensus.request.write.procedure.UpdateProcedurePlan;
+import
org.apache.iotdb.confignode.consensus.request.write.quota.SetSpaceQuotaPlan;
import
org.apache.iotdb.confignode.consensus.request.write.region.CreateRegionGroupsPlan;
import
org.apache.iotdb.confignode.consensus.request.write.region.OfferRegionMaintainTasksPlan;
import
org.apache.iotdb.confignode.consensus.request.write.region.PollRegionMaintainTaskPlan;
@@ -1304,4 +1306,18 @@ public class ConfigPhysicalPlanSerDeTest {
Assert.assertEquals(plan.getTemplateId(),
deserializedPlan.getTemplateId());
Assert.assertEquals(plan.getPath(), deserializedPlan.getPath());
}
+
+ @Test
+ public void setSpaceQuotaPlanTest() throws IOException {
+ TSpaceQuota spaceQuota = new TSpaceQuota();
+ spaceQuota.setDeviceNum(2);
+ spaceQuota.setTimeserieNum(3);
+ spaceQuota.setDisk(1024);
+ SetSpaceQuotaPlan plan =
+ new SetSpaceQuotaPlan(Collections.singletonList("root.sg"),
spaceQuota);
+ SetSpaceQuotaPlan deserializedPlan =
+ (SetSpaceQuotaPlan)
ConfigPhysicalPlan.Factory.create(plan.serializeToByteBuffer());
+ Assert.assertEquals(plan.getPrefixPathList(),
deserializedPlan.getPrefixPathList());
+ Assert.assertEquals(plan.getSpaceLimit(),
deserializedPlan.getSpaceLimit());
+ }
}
diff --git
a/confignode/src/test/java/org/apache/iotdb/confignode/persistence/quota/QuotaInfoTest.java
b/confignode/src/test/java/org/apache/iotdb/confignode/persistence/quota/QuotaInfoTest.java
new file mode 100644
index 0000000000..7c77a358e5
--- /dev/null
+++
b/confignode/src/test/java/org/apache/iotdb/confignode/persistence/quota/QuotaInfoTest.java
@@ -0,0 +1,23 @@
+/*
+ * 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.iotdb.confignode.persistence.quota;
+
+// TODO: Add snapshot test
+public class QuotaInfoTest {}
diff --git
a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBQuotaIT.java
b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBQuotaIT.java
new file mode 100644
index 0000000000..b35f9e4ce3
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBQuotaIT.java
@@ -0,0 +1,58 @@
+/*
+ * 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.iotdb.db.it;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBQuotaIT {
+
+ @Before
+ public void setUp() throws Exception {
+ EnvFactory.getEnv().initBeforeTest();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ EnvFactory.getEnv().cleanAfterTest();
+ }
+
+ @Test
+ public void setSpaceQuotaTest() throws SQLException {
+ try (Connection adminCon = EnvFactory.getEnv().getConnection();
+ Statement adminStmt = adminCon.createStatement()) {
+ adminStmt.execute("set space quota devices=5,timeseries=10,disk=100g on
root.sg1;");
+ }
+ }
+}
diff --git a/node-commons/src/assembly/resources/conf/iotdb-common.properties
b/node-commons/src/assembly/resources/conf/iotdb-common.properties
index 13a36b72b7..7b0d25fb7a 100644
--- a/node-commons/src/assembly/resources/conf/iotdb-common.properties
+++ b/node-commons/src/assembly/resources/conf/iotdb-common.properties
@@ -1134,4 +1134,10 @@
# enable_influxdb_rpc_service=false
# Datatype: int
-# influxdb_rpc_port=8086
\ No newline at end of file
+
+####################
+### Quota Configuration
+####################
+# If enabled, we can set different quotas for storage groups
+# Datatype: boolean
+# quota_enable=false
diff --git
a/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
b/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
index 32adf711ca..03a2f98262 100644
---
a/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
+++
b/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
@@ -235,6 +235,11 @@ public class IoTDBConstant {
public static final String WAL_FOLDER_NAME = "wal";
public static final String EXT_PIPE_FOLDER_NAME = "extPipe";
+ // quota folder name
+ public static final String QUOTA_FOLDER_NAME = "quota";
+ public static final String SPACE_QUOTA_FOLDER_NAME = "space";
+ public static final String THROTTLE_QUOTA_FOLDER_NAME = "throttle";
+
// mqtt
public static final String ENABLE_MQTT = "enable_mqtt_service";
public static final String MQTT_HOST_NAME = "mqtt_host";
@@ -288,6 +293,9 @@ public class IoTDBConstant {
public static final String IOTDB_FOREGROUND = "iotdb-foreground";
public static final String IOTDB_PIDFILE = "iotdb-pidfile";
+ // quota
+ public static final String SPACE_QUOTA_DISK = "disk";
+
// client version number
public enum ClientVersion {
V_0_12,
diff --git
a/node-commons/src/main/java/org/apache/iotdb/commons/enums/SpaceQuotaType.java
b/node-commons/src/main/java/org/apache/iotdb/commons/enums/SpaceQuotaType.java
new file mode 100644
index 0000000000..36b23e4b0e
--- /dev/null
+++
b/node-commons/src/main/java/org/apache/iotdb/commons/enums/SpaceQuotaType.java
@@ -0,0 +1,26 @@
+/*
+ * 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.iotdb.commons.enums;
+
+public enum SpaceQuotaType {
+ DISK,
+ DEVICE_NUMBER,
+ TIMESERIES_NUMBER
+}
diff --git
a/node-commons/src/main/java/org/apache/iotdb/commons/utils/BasicStructureSerDeUtil.java
b/node-commons/src/main/java/org/apache/iotdb/commons/utils/BasicStructureSerDeUtil.java
index 49669553ab..e3832dba28 100644
---
a/node-commons/src/main/java/org/apache/iotdb/commons/utils/BasicStructureSerDeUtil.java
+++
b/node-commons/src/main/java/org/apache/iotdb/commons/utils/BasicStructureSerDeUtil.java
@@ -29,6 +29,7 @@ import java.util.Map;
public class BasicStructureSerDeUtil {
public static final int INT_LEN = 4;
+ public static final int LONG_LEN = 8;
private BasicStructureSerDeUtil() {}
@@ -63,6 +64,11 @@ public class BasicStructureSerDeUtil {
return buffer.getInt();
}
+ /** read a long var from byteBuffer. */
+ public static long readLong(ByteBuffer buffer) {
+ return buffer.getLong();
+ }
+
/**
* write string to byteBuffer.
*
@@ -135,6 +141,16 @@ public class BasicStructureSerDeUtil {
return INT_LEN;
}
+ /**
+ * write a long n to dataOutputStream.
+ *
+ * @return The number of bytes used to represent n.
+ */
+ public static int write(long n, DataOutputStream stream) throws IOException {
+ stream.writeLong(n);
+ return LONG_LEN;
+ }
+
/**
* write a map to buffer
*
diff --git
a/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java
b/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java
index 45db274090..61da2934b8 100644
--- a/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java
+++ b/server/src/main/java/org/apache/iotdb/db/client/ConfigNodeClient.java
@@ -91,6 +91,7 @@ import
org.apache.iotdb.confignode.rpc.thrift.TSetDataNodeStatusReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetDataReplicationFactorReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetSchemaReplicationFactorReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetSchemaTemplateReq;
+import org.apache.iotdb.confignode.rpc.thrift.TSetSpaceQuotaReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetStorageGroupReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetTimePartitionIntervalReq;
import org.apache.iotdb.confignode.rpc.thrift.TShowCQResp;
@@ -1731,6 +1732,22 @@ public class ConfigNodeClient
throw new TException(MSG_RECONNECTION_FAIL);
}
+ @Override
+ public TSStatus setSpaceQuota(TSetSpaceQuotaReq req) throws TException {
+ for (int i = 0; i < RETRY_NUM; i++) {
+ try {
+ TSStatus status = client.setSpaceQuota(req);
+ if (!updateConfigNodeLeader(status)) {
+ return status;
+ }
+ } catch (TException e) {
+ configLeader = null;
+ }
+ reconnect();
+ }
+ throw new TException(MSG_RECONNECTION_FAIL);
+ }
+
public static class Factory extends BaseClientFactory<PartitionRegionId,
ConfigNodeClient> {
public Factory(
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
index 94a6703709..0ba80a1ca9 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
@@ -298,6 +298,26 @@ public class IoTDBConfig {
private String schemaRegionConsensusDir = consensusDir + File.separator +
"schema_region";
+ /** Space quota directory, stores space quota information of each storage
group */
+ private String spaceQuotaDir =
+ IoTDBConstant.DEFAULT_BASE_DIR
+ + File.separator
+ + IoTDBConstant.SYSTEM_FOLDER_NAME
+ + File.separator
+ + IoTDBConstant.QUOTA_FOLDER_NAME
+ + File.separator
+ + IoTDBConstant.SPACE_QUOTA_FOLDER_NAME;
+
+ /** Throttle quota directory, stores throttle quota information of each
storage group */
+ private String throttleQuotaDir =
+ IoTDBConstant.DEFAULT_BASE_DIR
+ + File.separator
+ + IoTDBConstant.SYSTEM_FOLDER_NAME
+ + File.separator
+ + IoTDBConstant.QUOTA_FOLDER_NAME
+ + File.separator
+ + IoTDBConstant.THROTTLE_QUOTA_FOLDER_NAME;
+
/** Maximum MemTable number. Invalid when enableMemControl is true. */
private int maxMemtableNumber = 0;
@@ -1048,6 +1068,9 @@ public class IoTDBConfig {
private long ratisFirstElectionTimeoutMinMs = 50L;
private long ratisFirstElectionTimeoutMaxMs = 150L;
+ /** Enable quotas */
+ private boolean quotaEnable = false;
+
// customizedProperties, this should be empty by default.
private Properties customizedProperties = new Properties();
@@ -1174,6 +1197,9 @@ public class IoTDBConfig {
extPipeDir = addDataHomeDir(extPipeDir);
+ spaceQuotaDir = addDataHomeDir(spaceQuotaDir);
+ throttleQuotaDir = addDataHomeDir(throttleQuotaDir);
+
if
(TSFileDescriptor.getInstance().getConfig().getTSFileStorageFs().equals(FSType.HDFS))
{
String hdfsDir = getHdfsDir();
queryDir = hdfsDir + File.separatorChar + queryDir;
@@ -1435,6 +1461,22 @@ public class IoTDBConfig {
this.mqttDir = mqttDir;
}
+ public String getSpaceQuotaDir() {
+ return spaceQuotaDir;
+ }
+
+ public void setSpaceQuotaDir(String spaceQuotaDir) {
+ this.spaceQuotaDir = spaceQuotaDir;
+ }
+
+ public String getThrottleQuotaDir() {
+ return throttleQuotaDir;
+ }
+
+ public void setThrottleQuotaDir(String throttleQuotaDir) {
+ this.throttleQuotaDir = throttleQuotaDir;
+ }
+
public String getMultiDirStrategyClassName() {
return multiDirStrategyClassName;
}
@@ -3577,4 +3619,12 @@ public class IoTDBConfig {
public void setRatisFirstElectionTimeoutMaxMs(long
ratisFirstElectionTimeoutMaxMs) {
this.ratisFirstElectionTimeoutMaxMs = ratisFirstElectionTimeoutMaxMs;
}
+
+ public boolean isQuotaEnable() {
+ return quotaEnable;
+ }
+
+ public void setQuotaEnable(boolean quotaEnable) {
+ this.quotaEnable = quotaEnable;
+ }
}
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
index 814bf550e2..e1724821c7 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
@@ -1005,6 +1005,10 @@ public class IoTDBDescriptor {
if (!conf.isClusterMode()) {
conf.setTimePartitionIntervalForRouting(conf.getTimePartitionIntervalForStorage());
}
+
+ conf.setQuotaEnable(
+ Boolean.parseBoolean(
+ properties.getProperty("quota_enable",
String.valueOf(conf.isQuotaEnable()))));
}
private void loadAuthorCache(Properties properties) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/localconfignode/LocalConfigNode.java
b/server/src/main/java/org/apache/iotdb/db/localconfignode/LocalConfigNode.java
index 998c900c02..5b0b31e567 100644
---
a/server/src/main/java/org/apache/iotdb/db/localconfignode/LocalConfigNode.java
+++
b/server/src/main/java/org/apache/iotdb/db/localconfignode/LocalConfigNode.java
@@ -153,15 +153,19 @@ public class LocalConfigNode {
private IAuthorizer iAuthorizer;
private LocalConfigNode() {
+ // create schema dir
String schemaDir = config.getSchemaDir();
File schemaFolder = SystemFileFactory.INSTANCE.getFile(schemaDir);
- if (!schemaFolder.exists()) {
- if (schemaFolder.mkdirs()) {
- logger.info("create system folder {}", schemaFolder.getAbsolutePath());
- } else {
- logger.error("create system folder {} failed.",
schemaFolder.getAbsolutePath());
- }
- }
+ createFolder(schemaFolder);
+
+ // create space quota dir
+ File spaceQuotaFolder =
SystemFileFactory.INSTANCE.getFile(config.getSpaceQuotaDir());
+ createFolder(spaceQuotaFolder);
+
+ // create throttle quota dir
+ File throttleQuotaFolder =
SystemFileFactory.INSTANCE.getFile(config.getThrottleQuotaDir());
+ createFolder(throttleQuotaFolder);
+
try {
iAuthorizer = BasicAuthorizer.getInstance();
} catch (AuthException e) {
@@ -169,6 +173,17 @@ public class LocalConfigNode {
}
}
+ /** Create system folders based on paths */
+ private void createFolder(File fileFolder) {
+ if (!fileFolder.exists()) {
+ if (fileFolder.mkdirs()) {
+ logger.info("create system folder {}", fileFolder.getAbsolutePath());
+ } else {
+ logger.error("create system folder {} failed.",
fileFolder.getAbsolutePath());
+ }
+ }
+ }
+
// region LocalSchemaConfigManager SingleTone
private static class LocalSchemaConfigManagerHolder {
private static final LocalConfigNode INSTANCE = new LocalConfigNode();
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/constant/StatementType.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/constant/StatementType.java
index 411fbc5bbd..88203199f1 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/constant/StatementType.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/constant/StatementType.java
@@ -152,4 +152,6 @@ public enum StatementType {
SHOW_TRIGGERS,
DEACTIVATE_TEMPLATE,
+
+ SET_SPACE_QUOTA,
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java
index 1e6aa6f61e..0fd36c18e3 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/ConfigTaskVisitor.java
@@ -57,6 +57,7 @@ import
org.apache.iotdb.db.mpp.plan.execution.config.sys.FlushTask;
import org.apache.iotdb.db.mpp.plan.execution.config.sys.LoadConfigurationTask;
import org.apache.iotdb.db.mpp.plan.execution.config.sys.MergeTask;
import org.apache.iotdb.db.mpp.plan.execution.config.sys.SetSystemStatusTask;
+import
org.apache.iotdb.db.mpp.plan.execution.config.sys.quota.SetSpaceQuotaTask;
import
org.apache.iotdb.db.mpp.plan.execution.config.sys.sync.CreatePipeSinkTask;
import org.apache.iotdb.db.mpp.plan.execution.config.sys.sync.CreatePipeTask;
import org.apache.iotdb.db.mpp.plan.execution.config.sys.sync.DropPipeSinkTask;
@@ -106,6 +107,7 @@ import
org.apache.iotdb.db.mpp.plan.statement.sys.FlushStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.LoadConfigurationStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.MergeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.SetSystemStatusStatement;
+import org.apache.iotdb.db.mpp.plan.statement.sys.quota.SetSpaceQuotaStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeSinkStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.DropPipeSinkStatement;
@@ -295,6 +297,12 @@ public class ConfigTaskVisitor
return new DropSchemaTemplateTask(dropSchemaTemplateStatement);
}
+ @Override
+ public IConfigTask visitSetSpaceQuota(
+ SetSpaceQuotaStatement setSpaceQuotaStatement, TaskContext context) {
+ return new SetSpaceQuotaTask(setSpaceQuotaStatement);
+ }
+
@Override
public IConfigTask visitShowDataNodes(
ShowDataNodesStatement showDataNodesStatement, TaskContext context) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/ClusterConfigTaskExecutor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/ClusterConfigTaskExecutor.java
index 10df3d09c3..a8a8b0180a 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/ClusterConfigTaskExecutor.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/ClusterConfigTaskExecutor.java
@@ -22,6 +22,7 @@ package
org.apache.iotdb.db.mpp.plan.execution.config.executor;
import org.apache.iotdb.common.rpc.thrift.TFlushReq;
import org.apache.iotdb.common.rpc.thrift.TSStatus;
import org.apache.iotdb.common.rpc.thrift.TSetTTLReq;
+import org.apache.iotdb.common.rpc.thrift.TSpaceQuota;
import org.apache.iotdb.commons.client.IClientManager;
import org.apache.iotdb.commons.cluster.NodeStatus;
import org.apache.iotdb.commons.consensus.PartitionRegionId;
@@ -57,6 +58,7 @@ import
org.apache.iotdb.confignode.rpc.thrift.TGetTimeSlotListResp;
import org.apache.iotdb.confignode.rpc.thrift.TGetTriggerTableResp;
import org.apache.iotdb.confignode.rpc.thrift.TGetUDFTableResp;
import org.apache.iotdb.confignode.rpc.thrift.TPipeSinkInfo;
+import org.apache.iotdb.confignode.rpc.thrift.TSetSpaceQuotaReq;
import org.apache.iotdb.confignode.rpc.thrift.TSetStorageGroupReq;
import org.apache.iotdb.confignode.rpc.thrift.TShowCQResp;
import org.apache.iotdb.confignode.rpc.thrift.TShowClusterResp;
@@ -121,6 +123,7 @@ import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowNodesInSchem
import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowPathSetTemplateStatement;
import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowSchemaTemplateStatement;
import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.UnsetSchemaTemplateStatement;
+import org.apache.iotdb.db.mpp.plan.statement.sys.quota.SetSpaceQuotaStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeSinkStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.DropPipeSinkStatement;
@@ -1069,6 +1072,33 @@ public class ClusterConfigTaskExecutor implements
IConfigTaskExecutor {
return future;
}
+ @Override
+ public SettableFuture<ConfigTaskResult> setSpaceQuota(
+ SetSpaceQuotaStatement setSpaceQuotaStatement) {
+ SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+ TSStatus tsStatus = new TSStatus();
+ TSetSpaceQuotaReq req = new TSetSpaceQuotaReq();
+ req.setStorageGroup(setSpaceQuotaStatement.getPrefixPathList());
+ TSpaceQuota spaceQuota = new TSpaceQuota();
+ spaceQuota.setDeviceNum(setSpaceQuotaStatement.getDeviceNum());
+ spaceQuota.setTimeserieNum(setSpaceQuotaStatement.getTimeSeriesNum());
+ spaceQuota.setDisk(setSpaceQuotaStatement.getDiskSize());
+ req.setSpaceLimit(spaceQuota);
+ try (ConfigNodeClient client =
+
CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.partitionRegionId)) {
+ // Send request to some API server
+ tsStatus = client.setSpaceQuota(req);
+ } catch (IOException | TException e) {
+ future.setException(e);
+ }
+ if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+ future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS));
+ } else {
+ future.setException(new IoTDBException(tsStatus.message, tsStatus.code));
+ }
+ return future;
+ }
+
@Override
public SettableFuture<ConfigTaskResult> createPipeSink(
CreatePipeSinkStatement createPipeSinkStatement) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/IConfigTaskExecutor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/IConfigTaskExecutor.java
index dc79335224..ae9f0dd0ca 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/IConfigTaskExecutor.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/IConfigTaskExecutor.java
@@ -45,6 +45,7 @@ import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowNodesInSchem
import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowPathSetTemplateStatement;
import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowSchemaTemplateStatement;
import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.UnsetSchemaTemplateStatement;
+import org.apache.iotdb.db.mpp.plan.statement.sys.quota.SetSpaceQuotaStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeSinkStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.DropPipeSinkStatement;
@@ -128,6 +129,8 @@ public interface IConfigTaskExecutor {
SettableFuture<ConfigTaskResult> dropSchemaTemplate(
DropSchemaTemplateStatement dropSchemaTemplateStatement);
+ SettableFuture<ConfigTaskResult> setSpaceQuota(SetSpaceQuotaStatement
setSpaceQuotaStatement);
+
SettableFuture<ConfigTaskResult> createPipeSink(CreatePipeSinkStatement
createPipeSinkStatement);
SettableFuture<ConfigTaskResult> dropPipeSink(DropPipeSinkStatement
dropPipeSinkStatement);
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/StandaloneConfigTaskExecutor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/StandaloneConfigTaskExecutor.java
index a0c59d4d8b..fd8ca382f6 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/StandaloneConfigTaskExecutor.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/executor/StandaloneConfigTaskExecutor.java
@@ -63,6 +63,7 @@ import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowNodesInSchem
import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowPathSetTemplateStatement;
import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowSchemaTemplateStatement;
import
org.apache.iotdb.db.mpp.plan.statement.metadata.template.UnsetSchemaTemplateStatement;
+import org.apache.iotdb.db.mpp.plan.statement.sys.quota.SetSpaceQuotaStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeSinkStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.DropPipeSinkStatement;
@@ -527,6 +528,17 @@ public class StandaloneConfigTaskExecutor implements
IConfigTaskExecutor {
return future;
}
+ @Override
+ public SettableFuture<ConfigTaskResult> setSpaceQuota(
+ SetSpaceQuotaStatement setSpaceQuotaStatement) {
+ SettableFuture<ConfigTaskResult> future = SettableFuture.create();
+ future.setException(
+ new IoTDBException(
+ "Executing unset schema template is not supported",
+ TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode()));
+ return future;
+ }
+
@Override
public SettableFuture<ConfigTaskResult> createPipeSink(
CreatePipeSinkStatement createPipeSinkStatement) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/sys/quota/SetSpaceQuotaTask.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/sys/quota/SetSpaceQuotaTask.java
new file mode 100644
index 0000000000..bb80bc4d9b
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/sys/quota/SetSpaceQuotaTask.java
@@ -0,0 +1,42 @@
+/*
+ * 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.iotdb.db.mpp.plan.execution.config.sys.quota;
+
+import org.apache.iotdb.db.mpp.plan.execution.config.ConfigTaskResult;
+import org.apache.iotdb.db.mpp.plan.execution.config.IConfigTask;
+import
org.apache.iotdb.db.mpp.plan.execution.config.executor.IConfigTaskExecutor;
+import org.apache.iotdb.db.mpp.plan.statement.sys.quota.SetSpaceQuotaStatement;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class SetSpaceQuotaTask implements IConfigTask {
+
+ private final SetSpaceQuotaStatement setSpaceQuotaStatement;
+
+ public SetSpaceQuotaTask(SetSpaceQuotaStatement setSpaceQuotaStatement) {
+ this.setSpaceQuotaStatement = setSpaceQuotaStatement;
+ }
+
+ @Override
+ public ListenableFuture<ConfigTaskResult> execute(IConfigTaskExecutor
configTaskExecutor)
+ throws InterruptedException {
+ return configTaskExecutor.setSpaceQuota(setSpaceQuotaStatement);
+ }
+}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index a10c09e2c4..f41423c998 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -145,6 +145,7 @@ import
org.apache.iotdb.db.mpp.plan.statement.sys.LoadConfigurationStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.MergeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.SetSystemStatusStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.ShowVersionStatement;
+import org.apache.iotdb.db.mpp.plan.statement.sys.quota.SetSpaceQuotaStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeSinkStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.DropPipeSinkStatement;
@@ -2164,6 +2165,61 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
return privileges.toArray(new String[0]);
}
+ // Quota
+
+ @Override
+ public Statement visitSetSpaceQuota(IoTDBSqlParser.SetSpaceQuotaContext ctx)
{
+ SetSpaceQuotaStatement setSpaceQuotaStatement = new
SetSpaceQuotaStatement();
+ List<IoTDBSqlParser.PrefixPathContext> prefixPathContexts =
ctx.prefixPath();
+ List<String> paths = new ArrayList<>();
+ for (IoTDBSqlParser.PrefixPathContext prefixPathContext :
prefixPathContexts) {
+ paths.add(parsePrefixPath(prefixPathContext).getFullPath());
+ }
+ setSpaceQuotaStatement.setPrefixPathList(paths);
+
+ Map<String, String> quotas = new HashMap<>();
+ for (IoTDBSqlParser.AttributePairContext attributePair :
ctx.attributePair()) {
+ quotas.put(
+ parseAttributeKey(attributePair.attributeKey()),
+ parseAttributeValue(attributePair.attributeValue()));
+ }
+
+ if (quotas.containsKey(IoTDBConstant.COLUMN_DEVICES)) {
+ setSpaceQuotaStatement.setDeviceNum(
+ Integer.parseInt(quotas.get(IoTDBConstant.COLUMN_DEVICES)));
+ }
+ if (quotas.containsKey(IoTDBConstant.COLUMN_TIMESERIES)) {
+ setSpaceQuotaStatement.setTimeSeriesNum(
+ Integer.parseInt(quotas.get(IoTDBConstant.COLUMN_TIMESERIES)));
+ }
+ if (quotas.containsKey(IoTDBConstant.SPACE_QUOTA_DISK)) {
+
setSpaceQuotaStatement.setDiskSize(parseUnit(quotas.get(IoTDBConstant.SPACE_QUOTA_DISK)));
+ }
+ return setSpaceQuotaStatement;
+ }
+
+ private long parseUnit(String data) {
+ String unit = data.substring(data.length() - 1);
+ long disk = Long.parseLong(data.substring(0, data.length() - 1));
+ switch (unit) {
+ case "M":
+ case "m":
+ return disk * 1024;
+ case "G":
+ case "g":
+ return disk * 1024 * 1024;
+ case "T":
+ case "t":
+ return disk * 1024 * 1024 * 1024;
+ case "P":
+ case "p":
+ return disk * 1024 * 1024 * 1024 * 1024;
+ default:
+ throw new SQLParserException(
+ "When setting the disk size, the unit is incorrect. Please use
'M', 'G', 'P', 'T' as the unit");
+ }
+ }
+
// Create Storage Group
@Override
public Statement
visitCreateStorageGroup(IoTDBSqlParser.CreateStorageGroupContext ctx) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/StatementVisitor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/StatementVisitor.java
index bd1d02330a..29ac69a2b1 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/StatementVisitor.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/StatementVisitor.java
@@ -84,6 +84,7 @@ import
org.apache.iotdb.db.mpp.plan.statement.sys.LoadConfigurationStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.MergeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.SetSystemStatusStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.ShowVersionStatement;
+import org.apache.iotdb.db.mpp.plan.statement.sys.quota.SetSpaceQuotaStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeSinkStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.DropPipeSinkStatement;
@@ -445,4 +446,8 @@ public abstract class StatementVisitor<R, C> {
DropSchemaTemplateStatement dropSchemaTemplateStatement, C context) {
return visitStatement(dropSchemaTemplateStatement, context);
}
+
+ public R visitSetSpaceQuota(SetSpaceQuotaStatement setSpaceQuotaStatement, C
context) {
+ return visitStatement(setSpaceQuotaStatement, context);
+ }
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/sys/quota/SetSpaceQuotaStatement.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/sys/quota/SetSpaceQuotaStatement.java
new file mode 100644
index 0000000000..318d7a28f3
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/sys/quota/SetSpaceQuotaStatement.java
@@ -0,0 +1,100 @@
+/*
+ * 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.iotdb.db.mpp.plan.statement.sys.quota;
+
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.mpp.plan.analyze.QueryType;
+import org.apache.iotdb.db.mpp.plan.constant.StatementType;
+import org.apache.iotdb.db.mpp.plan.statement.IConfigStatement;
+import org.apache.iotdb.db.mpp.plan.statement.Statement;
+import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
+
+import java.util.Collections;
+import java.util.List;
+
+public class SetSpaceQuotaStatement extends Statement implements
IConfigStatement {
+
+ private int timeSeriesNum;
+ private int deviceNum;
+ private long diskSize;
+ private String policy;
+ private List<String> prefixPathList;
+
+ /** QuotaOperator Constructor with OperatorType. */
+ public SetSpaceQuotaStatement() {
+ super();
+ statementType = StatementType.SET_SPACE_QUOTA;
+ }
+
+ public int getTimeSeriesNum() {
+ return timeSeriesNum;
+ }
+
+ public void setTimeSeriesNum(int timeSeriesNum) {
+ this.timeSeriesNum = timeSeriesNum;
+ }
+
+ public int getDeviceNum() {
+ return deviceNum;
+ }
+
+ public void setDeviceNum(int deviceNum) {
+ this.deviceNum = deviceNum;
+ }
+
+ public long getDiskSize() {
+ return diskSize;
+ }
+
+ public void setDiskSize(long diskSize) {
+ this.diskSize = diskSize;
+ }
+
+ public String getPolicy() {
+ return policy;
+ }
+
+ public void setPolicy(String policy) {
+ this.policy = policy;
+ }
+
+ public List<String> getPrefixPathList() {
+ return prefixPathList;
+ }
+
+ public void setPrefixPathList(List<String> prefixPathList) {
+ this.prefixPathList = prefixPathList;
+ }
+
+ @Override
+ public QueryType getQueryType() {
+ return QueryType.WRITE;
+ }
+
+ @Override
+ public List<PartialPath> getPaths() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
+ return visitor.visitSetSpaceQuota(this, context);
+ }
+}
diff --git
a/server/src/main/java/org/apache/iotdb/db/quotas/DataNodeSizeStore.java
b/server/src/main/java/org/apache/iotdb/db/quotas/DataNodeSizeStore.java
new file mode 100644
index 0000000000..41061e7f87
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/quotas/DataNodeSizeStore.java
@@ -0,0 +1,24 @@
+/*
+ * 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.iotdb.db.quotas;
+
+// TODO: Regularly count the disk sizes of all regions included in this
DataNode. Save in its
+// memory.
+public class DataNodeSizeStore {}
diff --git
a/server/src/main/java/org/apache/iotdb/db/quotas/DataNodeSpaceQuotaManager.java
b/server/src/main/java/org/apache/iotdb/db/quotas/DataNodeSpaceQuotaManager.java
new file mode 100644
index 0000000000..776080b0af
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/quotas/DataNodeSpaceQuotaManager.java
@@ -0,0 +1,34 @@
+/*
+ * 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.iotdb.db.quotas;
+
+import org.apache.iotdb.common.rpc.thrift.TSpaceQuota;
+
+import java.util.Map;
+
+// TODO: Store quota information of each sg
+public class DataNodeSpaceQuotaManager {
+
+ private Map<String, TSpaceQuota> spaceQuotaLimit;
+ private Map<String, TSpaceQuota> useSpaceQuota;
+ private Map<Integer, Integer> regionDisk;
+
+ public DataNodeSpaceQuotaManager() {}
+}
diff --git
a/server/src/main/java/org/apache/iotdb/db/quotas/SpaceViolationPolicyEnforcement.java
b/server/src/main/java/org/apache/iotdb/db/quotas/SpaceViolationPolicyEnforcement.java
new file mode 100644
index 0000000000..91b2407371
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/quotas/SpaceViolationPolicyEnforcement.java
@@ -0,0 +1,23 @@
+/*
+ * 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.iotdb.db.quotas;
+
+// TODO: Store the policies to be used by each sg after exceeding the quota
+public class SpaceViolationPolicyEnforcement {}
diff --git
a/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
b/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
index a97a58a74f..b98b1dc550 100644
--- a/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
+++ b/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
@@ -384,6 +384,10 @@ public class EnvironmentUtils {
logger.error("create user and role folders failed", e);
fail(e.getMessage());
}
+ // create space quota
+ createDir(config.getSpaceQuotaDir());
+ // create throttle quota
+ createDir(config.getThrottleQuotaDir());
}
private static void createDir(String dir) {
diff --git a/thrift-commons/src/main/thrift/common.thrift
b/thrift-commons/src/main/thrift/common.thrift
index e71978c6aa..94e6212511 100644
--- a/thrift-commons/src/main/thrift/common.thrift
+++ b/thrift-commons/src/main/thrift/common.thrift
@@ -122,3 +122,10 @@ struct TFilesResp {
1: required TSStatus status
2: required list<TFile> files
}
+
+// quota
+struct TSpaceQuota {
+ 1: optional i64 disk
+ 2: optional i32 deviceNum
+ 3: optional i32 timeserieNum
+}
diff --git a/thrift-confignode/src/main/thrift/confignode.thrift
b/thrift-confignode/src/main/thrift/confignode.thrift
index fe7ca6215a..501c52e453 100644
--- a/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/thrift-confignode/src/main/thrift/confignode.thrift
@@ -556,6 +556,14 @@ struct TDeleteTimeSeriesReq{
2: required binary pathPatternTree
}
+// ====================================================
+// Quota
+// ====================================================
+struct TSetSpaceQuotaReq {
+ 1: required list<string> storageGroup
+ 2: required common.TSpaceQuota spaceLimit
+}
+
// ====================================================
// CQ
// ====================================================
@@ -1050,5 +1058,7 @@ service IConfigNodeRPCService {
* Return the trigger table of config leader
*/
TShowCQResp showCQ()
+
+ common.TSStatus setSpaceQuota(TSetSpaceQuotaReq req)
}