From 09eb40e3560bd23ed2609f1878cb7fb33aa8b94e Mon Sep 17 00:00:00 2001 From: xy720 <22125576+xy720@users.noreply.github.com> Date: Thu, 23 Apr 2020 21:58:09 +0800 Subject: [PATCH] [New Stmt] Alter replication number for table (#3360) This CL add new command to set replication number of table in one time. ``` alter table test_tbl set ("replication_num" = "3"); ``` It changes replication num of a unpartitioned table. and ``` alter table test_tbl set ("default.replication_num" = "3"); ``` It changes default replication num of the specified table. --- .../cn/administrator-guide/index.rst | 1 + .../load-data/delete-manual.md | 38 +++++++------- .../administrator-guide/load-data/index.rst | 1 + .../Data Definition/ALTER TABLE.md | 11 +++- .../load-data/delete-manual_EN.md | 51 +++++++++---------- .../administrator-guide/load-data/index.rst | 1 + .../Data Definition/ALTER TABLE_EN.md | 11 +++- .../doris/alter/SchemaChangeHandler.java | 4 ++ .../analysis/ModifyTablePropertiesClause.java | 10 ++-- .../org/apache/doris/catalog/Catalog.java | 47 ++++++++++++++++- .../doris/common/util/PropertyAnalyzer.java | 14 +++++ .../org/apache/doris/alter/AlterTest.java | 26 ++++++++++ 12 files changed, 158 insertions(+), 57 deletions(-) diff --git a/docs/documentation/cn/administrator-guide/index.rst b/docs/documentation/cn/administrator-guide/index.rst index 31e06b6db6..21c1bffc60 100644 --- a/docs/documentation/cn/administrator-guide/index.rst +++ b/docs/documentation/cn/administrator-guide/index.rst @@ -7,6 +7,7 @@ load-data/index alter-table/index + materialized-view/index http-actions/index operation/index config/index diff --git a/docs/documentation/cn/administrator-guide/load-data/delete-manual.md b/docs/documentation/cn/administrator-guide/load-data/delete-manual.md index c3da18d7bb..cc5404ec32 100644 --- a/docs/documentation/cn/administrator-guide/load-data/delete-manual.md +++ b/docs/documentation/cn/administrator-guide/load-data/delete-manual.md @@ -17,32 +17,30 @@ specific language governing permissions and limitations under the License. --> -#Delete +# Delete Delete不同于其他导入方式,它是一个同步过程。和Insert into相似,所有的Delete操作在Doris中是一个独立的导入作业,一般Delete语句需要指定表和分区以及删除的条件来筛选要删除的数据,并将会同时删除base表和rollup表的数据。 -##语法 +## 语法 主要的Delete语法如下: ``` DELETE FROM table_name [PARTITION partition_name] - WHERE - column_name1 op value[ AND column_name2 op value ...]; +WHERE +column_name1 op value[ AND column_name2 op value ...]; ``` 示例1: ``` -DELETE FROM my_table PARTITION p1 - WHERE k1 = 3; +DELETE FROM my_table PARTITION p1 WHERE k1 = 3; ``` 示例2: ``` -DELETE FROM my_table PARTITION p1 - WHERE k1 < 3 AND k2 = "abc"; +DELETE FROM my_table PARTITION p1 WHERE k1 < 3 AND k2 = "abc"; ``` 下面介绍删除语句中使用到的参数: @@ -64,7 +62,7 @@ DELETE FROM my_table PARTITION p1 5. 如果指定表为RANGE分区表,则必须指定 `PARTITION`。如果是单分区表,可以不指定。 6. 不同于Insert into命令,delete不能手动指定`label`,有关label的概念可以查看[Insert Into文档] (./insert-into-manual.md) -##返回结果 +## 返回结果 Delete命令是一个SQL命令,返回结果是同步的,分为以下几种: @@ -74,8 +72,8 @@ Delete命令是一个SQL命令,返回结果是同步的,分为以下几种 ``` mysql> delete from test_tbl PARTITION p1 where k1 = 1; -Query OK, 0 rows affected (0.04 sec) -{'label':'delete_e7830c72-eb14-4cb9-bbb6-eebd4511d251', 'status':'VISIBLE', 'txnId':'4005'} + Query OK, 0 rows affected (0.04 sec) + {'label':'delete_e7830c72-eb14-4cb9-bbb6-eebd4511d251', 'status':'VISIBLE', 'txnId':'4005'} ``` 2. 提交成功,但未可见 @@ -84,11 +82,11 @@ Query OK, 0 rows affected (0.04 sec) ``` mysql> delete from test_tbl PARTITION p1 where k1 = 1; -Query OK, 0 rows affected (0.04 sec) -{'label':'delete_e7830c72-eb14-4cb9-bbb6-eebd4511d251', 'status':'VISIBLE', 'txnId':'4005', 'err':'delete job is committed but may be taking effect later' } + Query OK, 0 rows affected (0.04 sec) + {'label':'delete_e7830c72-eb14-4cb9-bbb6-eebd4511d251', 'status':'VISIBLE', 'txnId':'4005', 'err':'delete job is committed but may be taking effect later' } ``` - 结果会同时返回一个json字符串: + 结果会同时返回一个json字符串: `affected rows`表示此次删除影响的行,由于Doris的删除目前是逻辑删除,因此对于这个值是恒为0。 @@ -106,7 +104,7 @@ Query OK, 0 rows affected (0.04 sec) ``` mysql> delete from test_tbl partition p1 where k1 > 80; -ERROR 1064 (HY000): errCode = 2, detailMessage = {错误原因} + ERROR 1064 (HY000): errCode = 2, detailMessage = {错误原因} ``` 示例: @@ -115,7 +113,7 @@ ERROR 1064 (HY000): errCode = 2, detailMessage = {错误原因} ``` mysql> delete from test_tbl partition p1 where k1 > 80; -ERROR 1064 (HY000): errCode = 2, detailMessage = failed to delete replicas from job: 4005, Unfinished replicas:10000=60000, 10001=60000, 10002=60000 + ERROR 1064 (HY000): errCode = 2, detailMessage = failed to delete replicas from job: 4005, Unfinished replicas:10000=60000, 10001=60000, 10002=60000 ``` **综上,对于Delete操作返回结果的正确处理逻辑为:** @@ -127,9 +125,9 @@ ERROR 1064 (HY000): errCode = 2, detailMessage = failed to delete replicas from 1. 如果`status`为`COMMITTED`,表示数据仍不可见,用户可以稍等一段时间再用`show delete`命令查看结果 2. 如果`status`为`VISIBLE`,表示数据删除成功。 -##可配置项 +## 可配置项 -###FE配置 +### FE配置 **TIMEOUT配置** @@ -153,11 +151,11 @@ ERROR 1064 (HY000): errCode = 2, detailMessage = failed to delete replicas from 因为delete本身是一个SQL命令,因此删除语句也会受session限制,timeout还受Session中的`query_timeout`值影响,可以通过`SET query_timeout = xxx`来增加超时时间,单位是秒。 -##查看历史记录 +## 查看历史记录 1. 用户可以通过show delete语句查看历史上已执行完成的删除记录 - ###语法 + 语法 ``` SHOW DELETE [FROM db_name] diff --git a/docs/documentation/cn/administrator-guide/load-data/index.rst b/docs/documentation/cn/administrator-guide/load-data/index.rst index f4807d1df8..b5aad9ff85 100644 --- a/docs/documentation/cn/administrator-guide/load-data/index.rst +++ b/docs/documentation/cn/administrator-guide/load-data/index.rst @@ -10,3 +10,4 @@ stream-load-manual.md routine-load-manual.md insert-into-manual.md + delete-manual.md diff --git a/docs/documentation/cn/sql-reference/sql-statements/Data Definition/ALTER TABLE.md b/docs/documentation/cn/sql-reference/sql-statements/Data Definition/ALTER TABLE.md index 2f1ba92886..0e2ac88f54 100644 --- a/docs/documentation/cn/sql-reference/sql-statements/Data Definition/ALTER TABLE.md +++ b/docs/documentation/cn/sql-reference/sql-statements/Data Definition/ALTER TABLE.md @@ -166,7 +166,7 @@ under the License. 1) index 中的所有列都要写出来 2) value 列在 key 列之后 - 6. 修改table的属性,目前支持修改bloom filter列, colocate_with 属性和dynamic_partition属性 + 6. 修改table的属性,目前支持修改bloom filter列, colocate_with 属性和dynamic_partition属性,replication_num和default.replication_num属性 语法: PROPERTIES ("key"="value") 注意: @@ -198,6 +198,15 @@ under the License. ## example + [table] + 1. 修改表的默认副本数量, 新建分区副本数量默认使用此值 + ATLER TABLE example_db.my_table + SET ("default.replication_num" = "2"); + + 2. 修改单分区表的实际副本数量(只限单分区表) + ALTER TABLE example_db.my_table + SET ("replication_num" = "3"); + [partition] 1. 增加分区, 现有分区 [MIN, 2013-01-01),增加分区 [2013-01-01, 2014-01-01),使用默认分桶方式 ALTER TABLE example_db.my_table diff --git a/docs/documentation/en/administrator-guide/load-data/delete-manual_EN.md b/docs/documentation/en/administrator-guide/load-data/delete-manual_EN.md index bfd782d08d..04c980e359 100644 --- a/docs/documentation/en/administrator-guide/load-data/delete-manual_EN.md +++ b/docs/documentation/en/administrator-guide/load-data/delete-manual_EN.md @@ -17,33 +17,31 @@ specific language governing permissions and limitations under the License. --> -#Delete +# Delete Unlike other import methods, delete is a synchronization process. Similar to insert into, all delete operations are an independent import job in Doris. Generally, delete statements need to specify tables, partitions and delete conditions to tell which data to be deleted, and the data on base index and rollup index will be deleted at the same time. -##Syntax +## Syntax The delete statement's syntax is as follows: ``` DELETE FROM table_name [PARTITION partition_name] - WHERE - column_name1 op value[ AND column_name2 op value ...]; +WHERE +column_name1 op value[ AND column_name2 op value ...]; ``` example 1: ``` -DELETE FROM my_table PARTITION p1 - WHERE k1 = 3; +DELETE FROM my_table PARTITION p1 WHERE k1 = 3; ``` example 2: ``` -DELETE FROM my_table PARTITION p1 - WHERE k1 < 3 AND k2 = "abc"; +DELETE FROM my_table PARTITION p1 WHERE k1 < 3 AND k2 = "abc"; ``` The following describes the parameters used in the delete statement: @@ -52,7 +50,6 @@ The following describes the parameters used in the delete statement: The target partition of the delete statement. If not specified, the table must be a single partition table, otherwise it cannot be deleted - * WHERE The conditiona of the delete statement. All delete statements must specify a where condition. @@ -66,7 +63,7 @@ The following describes the parameters used in the delete statement: 5. If the specified table is a range partitioned table, `PARTITION` must be specified unless the table is a single partition table,. 6. Unlike the insert into command, delete statement cannot specify `label` manually. You can view the concept of `label` in [Insert Into] (./insert-into-manual.md) -##Delete Result +## Delete Result The delete command is an SQL command, and the returned results are synchronous. It can be divided into the following types: @@ -76,8 +73,8 @@ The delete command is an SQL command, and the returned results are synchronous. ``` mysql> delete from test_tbl PARTITION p1 where k1 = 1; -Query OK, 0 rows affected (0.04 sec) -{'label':'delete_e7830c72-eb14-4cb9-bbb6-eebd4511d251', 'status':'VISIBLE', 'txnId':'4005'} + Query OK, 0 rows affected (0.04 sec) + {'label':'delete_e7830c72-eb14-4cb9-bbb6-eebd4511d251', 'status':'VISIBLE', 'txnId':'4005'} ``` 2. Submitted successfully, but not visible @@ -87,8 +84,8 @@ Query OK, 0 rows affected (0.04 sec) ``` mysql> delete from test_tbl PARTITION p1 where k1 = 1; -Query OK, 0 rows affected (0.04 sec) -{'label':'delete_e7830c72-eb14-4cb9-bbb6-eebd4511d251', 'status':'VISIBLE', 'txnId':'4005', 'err':'delete job is committed but may be taking effect later' } + Query OK, 0 rows affected (0.04 sec) + {'label':'delete_e7830c72-eb14-4cb9-bbb6-eebd4511d251', 'status':'VISIBLE', 'txnId':'4005', 'err':'delete job is committed but may be taking effect later' } ``` The result will return a JSON string at the same time: @@ -111,7 +108,7 @@ Query OK, 0 rows affected (0.04 sec) ``` mysql> delete from test_tbl partition p1 where k1 > 80; -ERROR 1064 (HY000): errCode = 2, detailMessage = {错误原因} + ERROR 1064 (HY000): errCode = 2, detailMessage = {错误原因} ``` example: @@ -121,7 +118,7 @@ ERROR 1064 (HY000): errCode = 2, detailMessage = {错误原因} ``` mysql> delete from test_tbl partition p1 where k1 > 80; -ERROR 1064 (HY000): errCode = 2, detailMessage = failed to delete replicas from job: 4005, Unfinished replicas:10000=60000, 10001=60000, 10002=60000 + ERROR 1064 (HY000): errCode = 2, detailMessage = failed to delete replicas from job: 4005, Unfinished replicas:10000=60000, 10001=60000, 10002=60000 ``` **The correct processing logic for the returned results of the delete operation is as follows:** @@ -133,9 +130,9 @@ ERROR 1064 (HY000): errCode = 2, detailMessage = failed to delete replicas from 1. If `status` is `committed`, the data deletion is committed and will be eventually invisible. Users can wait for a while and then use the `show delete` command to view the results. 2. If `status` is `visible`, the data have been deleted successfully. -##Relevant Configuration +## Relevant Configuration -###FE configuration +### FE configuration **TIMEOUT configuration** @@ -143,33 +140,33 @@ In general, Doris's deletion timeout is limited from 30 seconds to 5 minutes. Th * tablet\_delete\_timeout\_second - The timeout of delete itself can be elastically changed by the number of tablets in the specified partition. This configuration represents the average timeout contributed by a tablet. The default value is 2. + The timeout of delete itself can be elastically changed by the number of tablets in the specified partition. This configuration represents the average timeout contributed by a tablet. The default value is 2. - Assuming that there are 5 tablets under the specified partition for this deletion, the timeout time available for the deletion is 10 seconds. Because the minimum timeout is 30 seconds which is higher than former timeout time, the final timeout is 30 seconds. + Assuming that there are 5 tablets under the specified partition for this deletion, the timeout time available for the deletion is 10 seconds. Because the minimum timeout is 30 seconds which is higher than former timeout time, the final timeout is 30 seconds. * load\_straggler\_wait\_second - If the user estimates a large amount of data, so that the upper limit of 5 minutes is insufficient, the user can adjust the upper limit of timeout through this item, and the default value is 300. + If the user estimates a large amount of data, so that the upper limit of 5 minutes is insufficient, the user can adjust the upper limit of timeout through this item, and the default value is 300. - **The specific calculation rule of timeout(seconds)** + **The specific calculation rule of timeout(seconds)** - `TIMEOUT = MIN(load_straggler_wait_second, MAX(30, tablet_delete_timeout_second * tablet_num))` + `TIMEOUT = MIN(load_straggler_wait_second, MAX(30, tablet_delete_timeout_second * tablet_num))` * query_timeout - Because delete itself is an SQL command, the deletion statement is also limited by the session variables, and the timeout is also affected by the session value `query'timeout`. You can increase the value by `set query'timeout = xxx`. + Because delete itself is an SQL command, the deletion statement is also limited by the session variables, and the timeout is also affected by the session value `query'timeout`. You can increase the value by `set query'timeout = xxx`. -##Show delete history +## Show delete history 1. The user can view the deletion completed in history through the show delete statement. - ###Syntax + Syntax ``` SHOW DELETE [FROM db_name] ``` - ###example + example ``` mysql> show delete from test_db; diff --git a/docs/documentation/en/administrator-guide/load-data/index.rst b/docs/documentation/en/administrator-guide/load-data/index.rst index 159b0d2315..eb02840886 100644 --- a/docs/documentation/en/administrator-guide/load-data/index.rst +++ b/docs/documentation/en/administrator-guide/load-data/index.rst @@ -10,3 +10,4 @@ Load Data stream-load-manual_EN.md routine-load-manual_EN.md insert-into-manual_EN.md + delete-manual_EN.md diff --git a/docs/documentation/en/sql-reference/sql-statements/Data Definition/ALTER TABLE_EN.md b/docs/documentation/en/sql-reference/sql-statements/Data Definition/ALTER TABLE_EN.md index 35712b29b3..faf4da0086 100644 --- a/docs/documentation/en/sql-reference/sql-statements/Data Definition/ALTER TABLE_EN.md +++ b/docs/documentation/en/sql-reference/sql-statements/Data Definition/ALTER TABLE_EN.md @@ -167,7 +167,7 @@ under the License. 1) All columns in index must be written 2) value is listed after the key column - 6. Modify the properties of the table, currently supports modifying the bloom filter column, the colocate_with attribute and the dynamic_partition attribute. + 6. Modify the properties of the table, currently supports modifying the bloom filter column, the colocate_with attribute and the dynamic_partition attribute, the replication_num and default.replication_num. grammar: PROPERTIES ("key"="value") note: @@ -200,6 +200,15 @@ under the License. ## example + [table] + 1. Modify the default number of replications of the table, which is used as default number of replications while creating new partition. + ATLER TABLE example_db.my_table + SET ("default.replication_num" = "2"); + + 2. Modify the actual number of replications of a unpartitioned table (unpartitioned table only) + ALTER TABLE example_db.my_table + SET ("replication_num" = "3"); + [partition] 1. Add partition, existing partition [MIN, 2013-01-01), add partition [2013-01-01, 2014-01-01), use default bucket mode ALTER TABLE example_db.my_table diff --git a/fe/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java b/fe/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java index 278366699a..1f1c6e1487 100644 --- a/fe/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java +++ b/fe/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java @@ -1394,6 +1394,10 @@ public class SchemaChangeHandler extends AlterHandler { } else if (DynamicPartitionUtil.checkDynamicPartitionPropertiesExist(properties)) { Catalog.getCurrentCatalog().modifyTableDynamicPartition(db, olapTable, properties); return; + } else if (properties.containsKey("default." + PropertyAnalyzer.PROPERTIES_REPLICATION_NUM)) { + Preconditions.checkNotNull(properties.get(PropertyAnalyzer.PROPERTIES_REPLICATION_NUM)); + Catalog.getCurrentCatalog().modifyTableDefaultReplicationNum(db, olapTable, properties); + return; } else if (properties.containsKey(PropertyAnalyzer.PROPERTIES_REPLICATION_NUM)) { Catalog.getCurrentCatalog().modifyTableReplicationNum(db, olapTable, properties); return; diff --git a/fe/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java b/fe/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java index 63de337758..c363c6a46f 100644 --- a/fe/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java +++ b/fe/src/main/java/org/apache/doris/analysis/ModifyTablePropertiesClause.java @@ -79,14 +79,10 @@ public class ModifyTablePropertiesClause extends AlterTableClause { } else if (DynamicPartitionUtil.checkDynamicPartitionPropertiesExist(properties)) { // do nothing, dynamic properties will be analyzed in SchemaChangeHandler.process } else if (properties.containsKey(PropertyAnalyzer.PROPERTIES_REPLICATION_NUM)) { - String defaultReplicationNumName = "default." + PropertyAnalyzer.PROPERTIES_REPLICATION_NUM; - throw new AnalysisException("Please use " + defaultReplicationNumName + - " instead of " + PropertyAnalyzer.PROPERTIES_REPLICATION_NUM + " config to escape misleading, this operation" + - " doesn't support changing the replication_num of the table data"); + PropertyAnalyzer.analyzeReplicationNum(properties, false); } else if (properties.containsKey("default." + PropertyAnalyzer.PROPERTIES_REPLICATION_NUM)) { - String defaultReplicationNumName = "default." + PropertyAnalyzer.PROPERTIES_REPLICATION_NUM; - properties.put(PropertyAnalyzer.PROPERTIES_REPLICATION_NUM, properties.get(defaultReplicationNumName)); - properties.remove(defaultReplicationNumName); + short defaultReplicationNum = PropertyAnalyzer.analyzeReplicationNum(properties, true); + properties.put(PropertyAnalyzer.PROPERTIES_REPLICATION_NUM, Short.toString(defaultReplicationNum)); } else if (properties.containsKey(PropertyAnalyzer.PROPERTIES_INMEMORY)) { this.needTableStable = false; this.opType = AlterOpType.MODIFY_TABLE_PROPERTY_SYNC; diff --git a/fe/src/main/java/org/apache/doris/catalog/Catalog.java b/fe/src/main/java/org/apache/doris/catalog/Catalog.java index 6bbc643373..df754a6f13 100644 --- a/fe/src/main/java/org/apache/doris/catalog/Catalog.java +++ b/fe/src/main/java/org/apache/doris/catalog/Catalog.java @@ -5160,8 +5160,50 @@ public class Catalog { editLog.logDynamicPartition(info); } + /** + * Set replication number for unpartitioned table. + * @param db + * @param table + * @param properties + * @throws DdlException + */ // The caller need to hold the db write lock - public void modifyTableReplicationNum(Database db, OlapTable table, Map properties) { + public void modifyTableReplicationNum(Database db, OlapTable table, Map properties) throws DdlException { + Preconditions.checkArgument(db.isWriteLockHeldByCurrentThread()); + String defaultReplicationNumName = "default."+ PropertyAnalyzer.PROPERTIES_REPLICATION_NUM; + PartitionInfo partitionInfo = table.getPartitionInfo(); + if (partitionInfo.getType() == PartitionType.RANGE) { + throw new DdlException("This is a range partitioned table, you should specify partitions with MODIFY PARTITION clause." + + " If you want to set default replication number, please use '" + defaultReplicationNumName + + "' instead of '" + PropertyAnalyzer.PROPERTIES_REPLICATION_NUM + "' to escape misleading."); + } + String partitionName = table.getName(); + Partition partition = table.getPartition(partitionName); + if (partition == null) { + throw new DdlException("Partition does not exist. name: " + partitionName); + } + + short replicationNum = Short.valueOf(properties.get(PropertyAnalyzer.PROPERTIES_REPLICATION_NUM)); + boolean isInMemory = partitionInfo.getIsInMemory(partition.getId()); + DataProperty newDataProperty = partitionInfo.getDataProperty(partition.getId()); + partitionInfo.setReplicationNum(partition.getId(), replicationNum); + // log + ModifyPartitionInfo info = new ModifyPartitionInfo(db.getId(), table.getId(), partition.getId(), + newDataProperty, replicationNum, isInMemory); + editLog.logModifyPartition(info); + LOG.debug("modify partition[{}-{}-{}] replication num to {}", db.getId(), table.getId(), partition.getName(), + replicationNum); + } + + /** + * Set default replication number for a specified table. + * You can see the default replication number by Show Create Table stmt. + * @param db + * @param table + * @param properties + */ + // The caller need to hold the db write lock + public void modifyTableDefaultReplicationNum(Database db, OlapTable table, Map properties) { Preconditions.checkArgument(db.isWriteLockHeldByCurrentThread()); TableProperty tableProperty = table.getTableProperty(); if (tableProperty == null) { @@ -5170,8 +5212,11 @@ public class Catalog { tableProperty.modifyTableProperties(properties); } tableProperty.buildReplicationNum(); + // log ModifyTablePropertyOperationLog info = new ModifyTablePropertyOperationLog(db.getId(), table.getId(), properties); editLog.logModifyReplicationNum(info); + LOG.debug("modify table[{}] replication num to {}", table.getName(), + properties.get(PropertyAnalyzer.PROPERTIES_REPLICATION_NUM)); } // The caller need to hold the db write lock diff --git a/fe/src/main/java/org/apache/doris/common/util/PropertyAnalyzer.java b/fe/src/main/java/org/apache/doris/common/util/PropertyAnalyzer.java index 49129bb780..2a8f2a0962 100644 --- a/fe/src/main/java/org/apache/doris/common/util/PropertyAnalyzer.java +++ b/fe/src/main/java/org/apache/doris/common/util/PropertyAnalyzer.java @@ -184,6 +184,20 @@ public class PropertyAnalyzer { return replicationNum; } + public static Short analyzeReplicationNum(Map properties, boolean isDefault) throws AnalysisException { + String key = "default."; + if (isDefault) { + key += PropertyAnalyzer.PROPERTIES_REPLICATION_NUM; + } else { + key = PropertyAnalyzer.PROPERTIES_REPLICATION_NUM; + } + short replicationNum = Short.valueOf(properties.get(key)); + if (replicationNum <= 0) { + throw new AnalysisException("Replication num should larger than 0. (suggested 3)"); + } + return replicationNum; + } + public static String analyzeColumnSeparator(Map properties, String oldColumnSeparator) { String columnSeparator = oldColumnSeparator; if (properties != null && properties.containsKey(PROPERTIES_COLUMN_SEPARATOR)) { diff --git a/fe/src/test/java/org/apache/doris/alter/AlterTest.java b/fe/src/test/java/org/apache/doris/alter/AlterTest.java index a129162af9..7636b46801 100644 --- a/fe/src/test/java/org/apache/doris/alter/AlterTest.java +++ b/fe/src/test/java/org/apache/doris/alter/AlterTest.java @@ -23,6 +23,7 @@ import org.apache.doris.analysis.CreateTableStmt; import org.apache.doris.catalog.Catalog; import org.apache.doris.catalog.Database; import org.apache.doris.catalog.OlapTable; +import org.apache.doris.catalog.Partition; import org.apache.doris.common.Config; import org.apache.doris.common.FeConstants; import org.apache.doris.qe.ConnectContext; @@ -70,6 +71,14 @@ public class AlterTest { ")\n" + "DISTRIBUTED BY HASH(k2) BUCKETS 3\n" + "PROPERTIES('replication_num' = '1');"); + + createTable("CREATE TABLE test.tbl2\n" + + "(\n" + + " k1 date,\n" + + " v1 int sum\n" + + ")\n" + + "DISTRIBUTED BY HASH (k1) BUCKETS 3\n" + + "PROPERTIES('replication_num' = '1');"); } @AfterClass @@ -164,6 +173,21 @@ public class AlterTest { alterTable(stmt, false); Assert.assertEquals(Short.valueOf("3"), tbl.getDefaultReplicationNum()); + // set range table's real replication num + Partition p1 = tbl.getPartition("p1"); + Assert.assertEquals(Short.valueOf("1"), Short.valueOf(tbl.getPartitionInfo().getReplicationNum(p1.getId()))); + stmt = "alter table test.tbl1 set ('replication_num' = '3');"; + alterTable(stmt, true); + Assert.assertEquals(Short.valueOf("1"), Short.valueOf(tbl.getPartitionInfo().getReplicationNum(p1.getId()))); + + // set un-partitioned table's real replication num + OlapTable tbl2 = (OlapTable)db.getTable("tbl2"); + Partition partition = tbl2.getPartition(tbl2.getName()); + Assert.assertEquals(Short.valueOf("1"), Short.valueOf(tbl2.getPartitionInfo().getReplicationNum(partition.getId()))); + stmt = "alter table test.tbl2 set ('replication_num' = '3');"; + alterTable(stmt, false); + Assert.assertEquals(Short.valueOf("3"), Short.valueOf(tbl2.getPartitionInfo().getReplicationNum(partition.getId()))); + // add partition without set replication num stmt = "alter table test.tbl1 add partition p4 values less than('2020-05-01')"; alterTable(stmt, true); @@ -173,6 +197,8 @@ public class AlterTest { alterTable(stmt, false); } + + private void waitSchemaChangeJobDone(boolean rollupJob) throws InterruptedException { Map alterJobs = Catalog.getCurrentCatalog().getSchemaChangeHandler().getAlterJobsV2(); if (rollupJob) {