|
25 | 25 | import org.apache.flink.table.annotation.ProcedureHint; |
26 | 26 | import org.apache.flink.table.procedure.ProcedureContext; |
27 | 27 |
|
28 | | -import javax.annotation.Nullable; |
29 | | - |
30 | | -import java.util.Collections; |
| 28 | +import java.util.ArrayList; |
| 29 | +import java.util.List; |
31 | 30 |
|
32 | 31 | /** |
33 | 32 | * Procedure to set or delete cluster configuration dynamically. |
|
45 | 44 | * |
46 | 45 | * <pre> |
47 | 46 | * -- Set a configuration |
48 | | - * CALL sys.set_cluster_config('kv.rocksdb.shared-rate-limiter.bytes-per-sec', '200MB'); |
49 | | - * CALL sys.set_cluster_config('datalake.format', 'paimon'); |
| 47 | + * CALL sys.set_cluster_configs('kv.rocksdb.shared-rate-limiter.bytes-per-sec', '200MB'); |
| 48 | + * CALL sys.set_cluster_configs('datalake.format', 'paimon'); |
| 49 | + * |
| 50 | + * -- Set multiple configurations at one time |
| 51 | + * CALL sys.set_cluster_configs('kv.rocksdb.shared-rate-limiter.bytes-per-sec', '200MB','datalake.format', 'paimon'); |
50 | 52 | * |
51 | 53 | * -- Delete a configuration (reset to default) |
52 | | - * CALL sys.set_cluster_config('kv.rocksdb.shared-rate-limiter.bytes-per-sec', NULL); |
53 | | - * CALL sys.set_cluster_config('kv.rocksdb.shared-rate-limiter.bytes-per-sec', ''); |
| 54 | + * CALL sys.set_cluster_configs('kv.rocksdb.shared-rate-limiter.bytes-per-sec', ''); |
54 | 55 | * </pre> |
55 | 56 | * |
56 | 57 | * <p><b>Note:</b> Not all configurations support dynamic changes. The server will validate the |
57 | 58 | * change and reject it if the configuration cannot be modified dynamically or if the new value is |
58 | 59 | * invalid. |
59 | 60 | */ |
60 | | -public class SetClusterConfigProcedure extends ProcedureBase { |
61 | | - |
62 | | - @ProcedureHint(argument = {@ArgumentHint(name = "config_key", type = @DataTypeHint("STRING"))}) |
63 | | - public String[] call(ProcedureContext context, String configKey) throws Exception { |
64 | | - return performSet(configKey, null); |
65 | | - } |
| 61 | +public class SetClusterConfigsProcedure extends ProcedureBase { |
66 | 62 |
|
67 | 63 | @ProcedureHint( |
68 | | - argument = { |
69 | | - @ArgumentHint(name = "config_key", type = @DataTypeHint("STRING")), |
70 | | - @ArgumentHint(name = "config_value", type = @DataTypeHint("STRING")) |
71 | | - }) |
72 | | - public String[] call(ProcedureContext context, String configKey, String configValue) |
73 | | - throws Exception { |
74 | | - return performSet(configKey, configValue); |
75 | | - } |
76 | | - |
77 | | - private String[] performSet(String configKey, @Nullable String configValue) throws Exception { |
78 | | - |
| 64 | + argument = {@ArgumentHint(name = "config_pairs", type = @DataTypeHint("STRING"))}, |
| 65 | + isVarArgs = true) |
| 66 | + public String[] call(ProcedureContext context, String... configPairs) throws Exception { |
79 | 67 | try { |
80 | 68 | // Validate config key |
81 | | - if (configKey == null || configKey.trim().isEmpty()) { |
| 69 | + if (configPairs.length == 0) { |
82 | 70 | throw new IllegalArgumentException( |
83 | | - "Config key cannot be null or empty. " |
84 | | - + "Please specify a valid configuration key."); |
| 71 | + "config_pairs cannot be null or empty. " |
| 72 | + + "Please specify a valid configuration pairs."); |
85 | 73 | } |
86 | 74 |
|
87 | | - configKey = configKey.trim(); |
88 | | - |
89 | | - // Determine operation type |
90 | | - AlterConfigOpType opType; |
91 | | - String operationDesc; |
92 | | - |
93 | | - if (configValue == null || configValue.trim().isEmpty()) { |
94 | | - // Delete operation - reset to default |
95 | | - opType = AlterConfigOpType.DELETE; |
96 | | - operationDesc = "deleted (reset to default)"; |
97 | | - } else { |
98 | | - // Set operation |
99 | | - opType = AlterConfigOpType.SET; |
100 | | - operationDesc = String.format("set to '%s'", configValue); |
| 75 | + if (configPairs.length % 2 != 0) { |
| 76 | + throw new IllegalArgumentException( |
| 77 | + "config_pairs must be set in pairs. " |
| 78 | + + "Please specify a valid configuration pairs."); |
| 79 | + } |
| 80 | + List<AlterConfig> configList = new ArrayList<>(); |
| 81 | + StringBuilder resultMessage = new StringBuilder(); |
| 82 | + |
| 83 | + for (int i = 0; i < configPairs.length; i += 2) { |
| 84 | + String configKey = configPairs[i].trim(); |
| 85 | + if (configKey.isEmpty()) { |
| 86 | + throw new IllegalArgumentException( |
| 87 | + "Config key cannot be null or empty. " |
| 88 | + + "Please specify a valid configuration key."); |
| 89 | + } |
| 90 | + String configValue = configPairs[i + 1]; |
| 91 | + |
| 92 | + String operationDesc = String.format("set to '%s'", configValue); |
| 93 | + |
| 94 | + // Construct configuration modification operation. |
| 95 | + AlterConfig alterConfig = |
| 96 | + new AlterConfig(configKey, configValue, AlterConfigOpType.SET); |
| 97 | + configList.add(alterConfig); |
| 98 | + resultMessage.append( |
| 99 | + String.format( |
| 100 | + "Successfully %s configuration '%s'. ", operationDesc, configKey)); |
101 | 101 | } |
102 | | - |
103 | | - // Construct configuration modification operation. |
104 | | - AlterConfig alterConfig = new AlterConfig(configKey, configValue, opType); |
105 | 102 |
|
106 | 103 | // Call Admin API to modify cluster configuration |
107 | 104 | // This will trigger validation on CoordinatorServer before persistence |
108 | | - admin.alterClusterConfigs(Collections.singletonList(alterConfig)).get(); |
| 105 | + admin.alterClusterConfigs(configList).get(); |
109 | 106 |
|
110 | 107 | return new String[] { |
111 | | - String.format( |
112 | | - "Successfully %s configuration '%s'. " |
113 | | - + "The change is persisted in ZooKeeper and applied to all servers.", |
114 | | - operationDesc, configKey) |
| 108 | + resultMessage + "The change is persisted in ZooKeeper and applied to all servers." |
115 | 109 | }; |
116 | | - |
117 | 110 | } catch (IllegalArgumentException e) { |
118 | 111 | // Re-throw validation errors with original message |
119 | 112 | throw e; |
120 | 113 | } catch (Exception e) { |
121 | 114 | // Wrap other exceptions with more context |
122 | 115 | throw new RuntimeException( |
123 | | - String.format( |
124 | | - "Failed to set cluster config '%s': %s", configKey, e.getMessage()), |
125 | | - e); |
| 116 | + String.format("Failed to set cluster config: %s", e.getMessage()), e); |
126 | 117 | } |
127 | 118 | } |
128 | 119 | } |
0 commit comments