Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/docs/maintenance/configurations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import catalogConfigurationHtml from '@site/generated/catalog_configuration.html
import hiveCatalogConfigurationHtml from '@site/generated/hive_catalog_configuration.html';
import hiveConnectorConfigurationHtml from '@site/generated/hive_connector_configuration.html';
import jdbcCatalogConfigurationHtml from '@site/generated/jdbc_catalog_configuration.html';
import zooKeeperCatalogLockConfigurationHtml from '@site/generated/zoo_keeper_catalog_lock_configuration.html';
import flinkCatalogConfigurationHtml from '@site/generated/flink_catalog_configuration.html';
import flinkConnectorConfigurationHtml from '@site/generated/flink_connector_configuration.html';
import sparkCatalogConfigurationHtml from '@site/generated/spark_catalog_configuration.html';
Expand Down Expand Up @@ -66,6 +67,16 @@ Options for Jdbc catalog.

<ConfigTable html={jdbcCatalogConfigurationHtml} />

### ZooKeeperCatalogLockOptions

Options for ZooKeeper catalog locks.

Ownership is validated before snapshot publication, and detected ownership loss fails the commit. Like JDBC locking, this cannot prevent an in-flight non-atomic storage write from completing after ownership expires. Stronger guarantees require storage-side conditional publication or fencing.

Curator and ZooKeeper are `provided` dependencies of Paimon Core, so Paimon does not bundle them in engine artifacts. Spark 3.4.3's unshaded Curator 2.13.0 and ZooKeeper 3.6.3 classpath is tested with this lock. For engines without that classpath, install unshaded `curator-client`, `curator-framework`, and `curator-recipes` 5.6.0 plus `zookeeper` 3.8.4 on the driver and every worker, and ensure older unshaded versions do not take precedence. Flink's relocated Curator classes do not satisfy these dependencies.

<ConfigTable html={zooKeeperCatalogLockConfigurationHtml} />

### FlinkCatalogOptions

Flink catalog options for paimon.
Expand Down
18 changes: 18 additions & 0 deletions docs/generated/catalog_configuration.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,24 @@
<td>String</td>
<td>Comma-separated list of file types to cache. Supported values: meta, global-index, bucket-index, data, file-index, or * for all of them.</td>
</tr>
<tr>
<td><h5>lock-acquire-timeout</h5></td>
<td style="word-wrap: break-word;">8 min</td>
<td>Duration</td>
<td>The maximum time to wait for acquiring the lock.</td>
</tr>
<tr>
<td><h5>lock.enabled</h5></td>
<td style="word-wrap: break-word;">(none)</td>
<td>Boolean</td>
<td>Enable catalog locking. Defaults to enabled on object stores.</td>
</tr>
<tr>
<td><h5>lock.type</h5></td>
<td style="word-wrap: break-word;">(none)</td>
<td>String</td>
<td>The catalog lock factory identifier. Defaults to the catalog's built-in lock factory.</td>
</tr>
<tr>
<td><h5>metastore</h5></td>
<td style="word-wrap: break-word;">"filesystem"</td>
Expand Down
72 changes: 72 additions & 0 deletions docs/generated/zoo_keeper_catalog_lock_configuration.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!--
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.
-->
<table class="configuration table table-bordered">
<thead>
<tr>
<th class="text-left" style="width: 20%">Key</th>
<th class="text-left" style="width: 15%">Default</th>
<th class="text-left" style="width: 10%">Type</th>
<th class="text-left" style="width: 55%">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><h5>lock-acquire-timeout</h5></td>
<td style="word-wrap: break-word;">8 min</td>
<td>Duration</td>
<td>The maximum time to wait for acquiring the lock.</td>
</tr>
<tr>
<td><h5>lock.zookeeper.connection-timeout</h5></td>
<td style="word-wrap: break-word;">15 s</td>
<td>Duration</td>
<td>ZooKeeper connection timeout.</td>
</tr>
<tr>
<td><h5>lock.zookeeper.quorum</h5></td>
<td style="word-wrap: break-word;">(none)</td>
<td>String</td>
<td>ZooKeeper connect string, e.g. 'host1:2181,host2:2181'. Required.</td>
</tr>
<tr>
<td><h5>lock.zookeeper.retry-base-sleep</h5></td>
<td style="word-wrap: break-word;">1 s</td>
<td>Duration</td>
<td>Initial backoff between ZooKeeper connection retries.</td>
</tr>
<tr>
<td><h5>lock.zookeeper.retry-max-attempts</h5></td>
<td style="word-wrap: break-word;">5</td>
<td>Integer</td>
<td>Maximum ZooKeeper connection retry attempts.</td>
</tr>
<tr>
<td><h5>lock.zookeeper.root</h5></td>
<td style="word-wrap: break-word;">"paimon/locks"</td>
<td>String</td>
<td>Root znode namespace for Paimon catalog locks.</td>
</tr>
<tr>
<td><h5>lock.zookeeper.session-timeout</h5></td>
<td style="word-wrap: break-word;">30 s</td>
<td>Duration</td>
<td>ZooKeeper session timeout.</td>
</tr>
</tbody>
</table>
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,26 @@ public class CatalogOptions {
.defaultValue(CatalogTableType.MANAGED)
.withDescription("Type of table.");

public static final ConfigOption<Boolean> LOCK_ENABLED =
ConfigOptions.key("lock.enabled")
.booleanType()
.noDefaultValue()
.withDescription(
"Enable catalog locking. Defaults to enabled on object stores.");

public static final ConfigOption<String> LOCK_TYPE =
ConfigOptions.key("lock.type")
.stringType()
.noDefaultValue()
.withDescription(
"The catalog lock factory identifier. Defaults to the catalog's built-in lock factory.");

public static final ConfigOption<Duration> LOCK_ACQUIRE_TIMEOUT =
ConfigOptions.key("lock-acquire-timeout")
.durationType()
.defaultValue(Duration.ofMinutes(8))
.withDescription("The maximum time to wait for acquiring the lock.");

public static final ConfigOption<Integer> CLIENT_POOL_SIZE =
key("client-pool-size")
.intType()
Expand Down
47 changes: 47 additions & 0 deletions paimon-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,55 @@ under the License.
</exclusions>
</dependency>

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
<scope>provided</scope>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Make the compatible Curator runtime available to engine users

These new dependencies are provided, so the published engine artifacts neither include nor transitively supply the Curator version used by the new lock. Supported Spark 3.4.3 supplies curator-recipes 2.13.0 (the default Hadoop 2.8.5 stack also has 2.7.1); isOwnedByCurrentThread is package-private in those versions, whereas this implementation invokes it from outside that package. Against the same real ZooKeeper server, the production factory/runWithLock probe succeeds with the PR test classpath (Curator 5.6.0) but fails with the Curator client/framework/recipes 2.13.0 set: IllegalAccessError at runWithLock:154 and again at close:247. Core tests pin the newer libraries and do not exercise that engine runtime. Flink relocated classes also cannot satisfy these unrelocated imports. Please ship an isolated compatible dependency set, or provide explicit compatible-library installation requirements and engine-classpath tests, so enabling lock.type=zookeeper on a supported distribution actually works.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lock no longer calls isOwnedByCurrentThread(); it uses getLockPath() and checks the session epoch and lock node. A Spark 3.4 test exercises the production reentrant path with Curator 2.13.0. The docs also state which unshaded dependencies engines must provide; Flink’s relocated Curator alone is insufficient.

</dependency>

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>

<!--
Same nearest-declaration-wins concern as zookeeper above: hadoop-common pulls in
curator-client 2.7.1 at a shallower depth than curator-recipes's own transitive
curator-client, so it would otherwise win and mismatch curator-recipes/curator-framework.
-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>${curator.version}</version>
<scope>provided</scope>
</dependency>

<!-- test dependencies -->

<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-test</artifactId>
<version>${curator.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.paimon</groupId>
<artifactId>paimon-arrow</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;

import static org.apache.paimon.options.CatalogOptions.CASE_SENSITIVE;
import static org.apache.paimon.options.CatalogOptions.LOCK_ENABLED;
import static org.apache.paimon.options.CatalogOptions.LOCK_TYPE;

/** A catalog implementation for {@link FileIO}. */
public class FileSystemCatalog extends AbstractCatalog {
Expand Down Expand Up @@ -145,6 +148,20 @@ public <T> T runWithLock(Identifier identifier, Callable<T> callable) throws Exc
}
}

@Override
public Optional<CatalogLockFactory> lockFactory() {
if (!lockEnabled()) {
return Optional.empty();
}
String type = context.options().get(LOCK_TYPE);
return type == null ? defaultLockFactory() : Optional.of(CatalogLockFactory.discover(type));
}

@Override
protected boolean lockEnabled() {
return context.options().getOptional(LOCK_ENABLED).orElse(fileIO.isObjectStore());
}

private SchemaManager schemaManager(Identifier identifier) {
Path path = getTableLocation(identifier);
return new FileSystemSchemaManager(fileIO, path, identifier.getBranchNameOrDefault());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package org.apache.paimon.jdbc;

import org.apache.paimon.options.CatalogOptions;
import org.apache.paimon.options.ConfigOption;
import org.apache.paimon.options.ConfigOptions;
import org.apache.paimon.options.Options;
Expand All @@ -27,19 +28,9 @@
/** Options for jdbc catalog. */
public final class JdbcCatalogOptions {

public static final ConfigOption<Boolean> LOCK_ENABLED =
ConfigOptions.key("lock.enabled")
.booleanType()
.noDefaultValue()
.withDescription(
"Enable catalog locking. Defaults to enabled on object stores.");
public static final ConfigOption<Boolean> LOCK_ENABLED = CatalogOptions.LOCK_ENABLED;

public static final ConfigOption<String> LOCK_TYPE =
ConfigOptions.key("lock.type")
.stringType()
.noDefaultValue()
.withDescription(
"The catalog lock factory identifier. Defaults to the catalog's built-in lock factory.");
public static final ConfigOption<String> LOCK_TYPE = CatalogOptions.LOCK_TYPE;

public static final ConfigOption<Duration> LOCK_CHECK_MAX_SLEEP =
ConfigOptions.key("lock-check-max-sleep")
Expand All @@ -48,10 +39,7 @@ public final class JdbcCatalogOptions {
.withDescription("The maximum sleep time when retrying to check the lock.");

public static final ConfigOption<Duration> LOCK_ACQUIRE_TIMEOUT =
ConfigOptions.key("lock-acquire-timeout")
.durationType()
.defaultValue(Duration.ofMinutes(8))
.withDescription("The maximum time to wait for acquiring the lock.");
CatalogOptions.LOCK_ACQUIRE_TIMEOUT;

public static final ConfigOption<String> CATALOG_KEY =
ConfigOptions.key("catalog-key")
Expand Down
Loading
Loading