This is an automated email from the ASF dual-hosted git repository.
yuxia pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fluss.git
The following commit(s) were added to refs/heads/main by this push:
new 221db5e9a [server] Introduce
plugin.classloader.parent-first-patterns.additional configuration (#1222)
221db5e9a is described below
commit 221db5e9a5a0cb2b003f2888b05390173d586c8b
Author: yuxia Luo <[email protected]>
AuthorDate: Mon Sep 22 15:14:26 2025 +0800
[server] Introduce plugin.classloader.parent-first-patterns.additional
configuration (#1222)
---
.../org/apache/fluss/config/ConfigOptions.java | 16 ++++++-
.../java/org/apache/fluss/plugin/PluginConfig.java | 16 +++++--
.../org/apache/fluss/plugin/PluginConfigTest.java | 52 ++++++++++++++++++++++
website/docs/maintenance/configuration.md | 43 +++++++++---------
4 files changed, 101 insertions(+), 26 deletions(-)
diff --git
a/fluss-common/src/main/java/org/apache/fluss/config/ConfigOptions.java
b/fluss-common/src/main/java/org/apache/fluss/config/ConfigOptions.java
index 07de50bfc..8b4664d70 100644
--- a/fluss-common/src/main/java/org/apache/fluss/config/ConfigOptions.java
+++ b/fluss-common/src/main/java/org/apache/fluss/config/ConfigOptions.java
@@ -112,7 +112,21 @@ public class ConfigOptions {
.withDescription(
"A (semicolon-separated) list of patterns that
specifies which classes should always be"
+ " resolved through the plugin parent
ClassLoader first. A pattern is a simple prefix that is checked "
- + " against the fully qualified class
name. This setting should generally not be modified.");
+ + " against the fully qualified class
name. This setting should generally not be modified. To add another "
+ + " pattern we recommend to use
\"plugin.classloader.parent-first-patterns.additional\" instead.");
+
+ public static final ConfigOption<List<String>>
+ PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS_ADDITIONAL =
+ key("plugin.classloader.parent-first-patterns.additional")
+ .stringType()
+ .asList()
+ .defaultValues()
+ .withDescription(
+ "A (semicolon-separated) list of patterns
that specifies which classes should always be"
+ + " resolved through the plugin
parent ClassLoader first. A pattern is a simple prefix that is checked "
+ + " against the fully qualified
class name. These patterns are appended to \""
+ +
PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS.key()
+ + "\".");
public static final ConfigOption<Duration> AUTO_PARTITION_CHECK_INTERVAL =
key("auto-partition.check.interval")
diff --git
a/fluss-common/src/main/java/org/apache/fluss/plugin/PluginConfig.java
b/fluss-common/src/main/java/org/apache/fluss/plugin/PluginConfig.java
index 07cde050a..0f97085d7 100644
--- a/fluss-common/src/main/java/org/apache/fluss/plugin/PluginConfig.java
+++ b/fluss-common/src/main/java/org/apache/fluss/plugin/PluginConfig.java
@@ -17,16 +17,20 @@
package org.apache.fluss.plugin;
-import org.apache.fluss.config.ConfigOptions;
import org.apache.fluss.config.Configuration;
+import org.apache.fluss.shaded.guava32.com.google.common.collect.Iterables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.nio.file.Path;
+import java.util.List;
import java.util.Optional;
+import static
org.apache.fluss.config.ConfigOptions.PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS;
+import static
org.apache.fluss.config.ConfigOptions.PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS_ADDITIONAL;
+
/** Stores the configuration for plugins mechanism. */
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public class PluginConfig {
@@ -62,9 +66,13 @@ public class PluginConfig {
public static PluginConfig fromConfiguration(Configuration configuration) {
return new PluginConfig(
getPluginsDir().map(File::toPath),
- configuration
-
.get(ConfigOptions.PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS)
- .toArray(new String[0]));
+ getPluginParentFirstLoaderPatterns(configuration));
+ }
+
+ private static String[] getPluginParentFirstLoaderPatterns(Configuration
config) {
+ List<String> base =
config.get(PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS);
+ List<String> append =
config.get(PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS_ADDITIONAL);
+ return Iterables.toArray(Iterables.concat(base, append), String.class);
}
public static Optional<File> getPluginsDir() {
diff --git
a/fluss-common/src/test/java/org/apache/fluss/plugin/PluginConfigTest.java
b/fluss-common/src/test/java/org/apache/fluss/plugin/PluginConfigTest.java
new file mode 100644
index 000000000..0510598d2
--- /dev/null
+++ b/fluss-common/src/test/java/org/apache/fluss/plugin/PluginConfigTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.fluss.plugin;
+
+import org.apache.fluss.config.Configuration;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static
org.apache.fluss.config.ConfigOptions.PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS;
+import static
org.apache.fluss.config.ConfigOptions.PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS_ADDITIONAL;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Test for {@link PluginConfig} . */
+class PluginConfigTest {
+
+ @Test
+ void testFromConfig() {
+ // only set parent-first-patterns.default
+ Configuration config = new Configuration();
+ config.set(
+ PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS,
+ Arrays.asList("org.apache.fluss.", "java."));
+ PluginConfig pluginConfig = PluginConfig.fromConfiguration(config);
+ assertThat(pluginConfig.getAlwaysParentFirstPatterns())
+ .isEqualTo(new String[] {"org.apache.fluss.", "java."});
+ // also set parent-first-patterns.additional
+ config.set(
+ PLUGIN_ALWAYS_PARENT_FIRST_LOADER_PATTERNS_ADDITIONAL,
+ Collections.singletonList("org.apache.hadoop."));
+ pluginConfig = PluginConfig.fromConfiguration(config);
+ assertThat(pluginConfig.getAlwaysParentFirstPatterns())
+ .isEqualTo(new String[] {"org.apache.fluss.", "java.",
"org.apache.hadoop."});
+ }
+}
diff --git a/website/docs/maintenance/configuration.md
b/website/docs/maintenance/configuration.md
index d2fad94a1..0737fdf0e 100644
--- a/website/docs/maintenance/configuration.md
+++ b/website/docs/maintenance/configuration.md
@@ -26,27 +26,28 @@ during the Fluss cluster working.
## Common
-| Option | Type | Default
|
Description
[...]
-|--------------------------------------------------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[...]
-| bind.listeners | String | (None) | The network address and port
to which the server binds for accepting connections. This defines the interface
and port where the server will listen for incoming requests. The format is
`{listener_name}://{host}:{port}`, and multiple addresses can be specified,
separated by commas. Use `0.0.0.0` for the `host` to bind to all available
interfaces which is dangerous on production and not suggested for production
usage. The `listener_name` serv [...]
-| advertised.listeners | String | (None) | The externally advertised
address and port for client connections. Required in distributed environments
when the bind address is not publicly reachable. Format matches
`bind.listeners` (`{listener_name}://{host}:{port}`). Defaults to the value of
`bind.listeners` if not explicitly configured.
[...]
-| internal.listener.name | String | FLUSS | The listener for server
internal communication.
[...]
-| security.protocol.map | Map | |
A map defining the authentication protocol for each listener. The format is
`listenerName1:protocol1,listenerName2:protocol2`, e.g.,
`INTERNAL:PLAINTEXT,CLIENT:GSSAPI`. Each listener can be associated with a
specific authentication protocol. Listeners not included in the map will use
PLAINTEXT by default, which does not require authentication.
[...]
-| `security.${protocol}.*` | String | (none)
|
Protocol-specific configuration properties. For example,
security.sasl.jaas.config for SASL authentication settings.
[...]
-| default.bucket.number | Integer | 1
| The
default number of buckets for a table in Fluss cluster. It's a cluster-level
parameter and all the tables without specifying bucket number in the cluster
will use the value as the bucket number.
[...]
-| default.replication.factor | Integer | 1
| The
default replication factor for the log of a table in Fluss cluster. It's a
cluster-level parameter, and all the tables without specifying replication
factor in the cluster will use the value as replication factor.
[...]
-| remote.data.dir | String | (None)
| The
directory used for storing the kv snapshot data files and remote log for log
tiered storage in a Fluss supported filesystem.
[...]
-| remote.fs.write-buffer-size | MemorySize | 4kb
| The
default size of the write buffer for writing the local files to remote file
systems.
[...]
-| plugin.classloader.parent-first-patterns.default | String |
java.,<br/>org.apache.fluss.,<br/>javax.annotation.,<br/>org.slf4j,<br/>org.apache.log4j,<br/>org.apache.logging,<br/>org.apache.commons.logging,<br/>ch.qos.logback
| A (semicolon-separated) list of patterns that specifies which classes should
always be resolved through the plugin parent ClassLoader first. A pattern is a
simple prefix that is checked against the fully qualified class name. This
setting should generally not [...]
-| auto-partition.check.interval | Duration | 10min
| The
interval of auto partition check. The default value is 10 minutes.
[...]
-| allow.create.log.tables | Boolean | true
|
Whether to allow creation of log tables. When set to false, attempts to create
log tables (tables without primary key) will be rejected. The default value is
true.
[...]
-| allow.create.kv.tables | Boolean | true
|
Whether to allow creation of kv tables (primary key tables). When set to false,
attempts to create kv tables (tables with primary key) will be rejected. The
default value is true.
[...]
-| max.partition.num | Integer | 1000
|
Limits the maximum number of partitions that can be created for a partitioned
table to avoid creating too many partitions.
[...]
-| max.bucket.num | Integer | 128000
| The
maximum number of buckets that can be created for a table. The default value is
128000.
[...]
-| acl.notification.expiration-time | Duration | 15min
| The
duration for which ACL notifications are valid before they expire. This
configuration determines the time window during which an ACL notification is
considered active. After this duration, the notification will no longer be
valid and will be discarded. T [...]
-| authorizer.enabled | Boolean | false
|
Specifies whether to enable the authorization feature. If enabled, access
control is enforced based on the authorization rules defined in the
configuration. If disabled, all operations and resources are accessible to all
users. [...]
-| authorizer.type | String | default
|
Specifies the type of authorizer to be used for access control. This value
corresponds to the identifier of the authorization plugin. The default value is
`default`, which indicates the built-in authorizer implementation. Custom
authorizers can be implemente [...]
-| super.users | String | (None)
| A
semicolon-separated list of superusers who have unrestricted access to all
operations and resources. Note that the delimiter is semicolon since SSL user
names may contain comma, and each super user should be specified in the format
`principal_type:principa [...]
+| Option | Type |
Default
| Description
[...]
+|-----------------------------------------------------|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[...]
+| bind.listeners | String |
(None)
| The network address and port to which the server binds for accepting
connections. This defines the interface and port where the server will listen
for incoming requests. The format is `{listener_name}://{host}:{port}`, and
multiple addresses can [...]
+| advertised.listeners | String |
(None)
| The externally advertised address and port for client connections.
Required in distributed environments when the bind address is not publicly
reachable. Format matches `bind.listeners` (`{listener_name}://{host}:{port}`).
Defaults to the value o [...]
+| internal.listener.name | String |
FLUSS
| The listener for server internal communication.
[...]
+| security.protocol.map | Map |
(none)
| A map defining the authentication protocol for each listener. The
format is `listenerName1:protocol1,listenerName2:protocol2`, e.g.,
`INTERNAL:PLAINTEXT,CLIENT:GSSAPI`. Each listener can be associated with a
specific authentication protocol. Lis [...]
+| `security.${protocol}.*` | String |
(none)
| Protocol-specific configuration properties. For example,
security.sasl.jaas.config for SASL authentication settings.
[...]
+| default.bucket.number | Integer | 1
| The default number of buckets for a table in Fluss cluster. It's a
cluster-level parameter and all the tables without specifying bucket number in
the cluster will use the value as the bucket number.
[...]
+| default.replication.factor | Integer | 1
| The default replication factor for the log of a table in Fluss cluster.
It's a cluster-level parameter, and all the tables without specifying
replication factor in the cluster will use the value as replication factor.
[...]
+| remote.data.dir | String |
(None)
| The directory used for storing the kv snapshot data files and remote
log for log tiered storage in a Fluss supported filesystem.
[...]
+| remote.fs.write-buffer-size | MemorySize |
4kb
| The default size of the write buffer for writing the local files to
remote file systems.
[...]
+| plugin.classloader.parent-first-patterns.additional | List<String> |
(None)
| A (semicolon-separated) list of patterns that specifies which classes
should always be resolved through the plugin parent ClassLoader first. A
pattern is a simple prefix that is checked against the fully qualified class
name. These patterns are [...]
+| plugin.classloader.parent-first-patterns.default | String |
java.,<br/>org.apache.fluss.,<br/>javax.annotation.,<br/>org.slf4j,<br/>org.apache.log4j,<br/>org.apache.logging,<br/>org.apache.commons.logging,<br/>ch.qos.logback
| A (semicolon-separated) list of patterns that specifies which classes
should always be resolved through the plugin parent ClassLoader first. A
pattern is a simple prefix that is checked against the fully qualified class
name. This setting should [...]
+| auto-partition.check.interval | Duration |
10min
| The interval of auto partition check. The default value is 10
minutes.
[...]
+| allow.create.log.tables | Boolean |
true
| Whether to allow creation of log tables. When set to false, attempts
to create log tables (tables without primary key) will be rejected. The default
value is true.
[...]
+| allow.create.kv.tables | Boolean |
true
| Whether to allow creation of kv tables (primary key tables). When set
to false, attempts to create kv tables (tables with primary key) will be
rejected. The default value is true.
[...]
+| max.partition.num | Integer |
1000
| Limits the maximum number of partitions that can be created for a
partitioned table to avoid creating too many partitions.
[...]
+| max.bucket.num | Integer |
128000
| The maximum number of buckets that can be created for a table. The
default value is 128000.
[...]
+| acl.notification.expiration-time | Duration |
15min
| The duration for which ACL notifications are valid before they
expire. This configuration determines the time window during which an ACL
notification is considered active. After this duration, the notification will
no longer be valid and will be [...]
+| authorizer.enabled | Boolean |
false
| Specifies whether to enable the authorization feature. If enabled,
access control is enforced based on the authorization rules defined in the
configuration. If disabled, all operations and resources are accessible to all
users. [...]
+| authorizer.type | String |
default
| Specifies the type of authorizer to be used for access control. This
value corresponds to the identifier of the authorization plugin. The default
value is `default`, which indicates the built-in authorizer implementation.
Custom authorizers can [...]
+| super.users | String |
(None)
| A semicolon-separated list of superusers who have unrestricted access
to all operations and resources. Note that the delimiter is semicolon since SSL
user names may contain comma, and each super user should be specified in the
format `principal_ [...]
## CoordinatorServer