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
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,15 @@ private void doSend(WriteRecord record, WriteCallback callback) {

TableInfo tableInfo = record.getTableInfo();
PhysicalTablePath physicalTablePath = record.getPhysicalTablePath();
dynamicPartitionCreator.checkAndCreatePartitionAsync(
physicalTablePath,
tableInfo.getPartitionKeys(),
tableInfo.getTableConfig().getAutoPartitionStrategy());
// Skip on non-partitioned tables: the callee returns immediately when
// partitionName is null, but the expensive AutoPartitionStrategy argument
// would still be evaluated per record without this guard.
if (tableInfo.isPartitioned()) {
dynamicPartitionCreator.checkAndCreatePartitionAsync(
physicalTablePath,
tableInfo.getPartitionKeys(),
tableInfo.getTableConfig().getAutoPartitionStrategy());

@fresh-borzoni fresh-borzoni Jun 25, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder if instead of caching we can do a bit different.
The strategy is only actually used when a partition gets created, on the common "already exists" path it's built and thrown away.

Instead of caching it, you could pass tableInfo into checkAndCreatePartitionAsync and resolve getAutoPartitionStrategy() inside the create branch.? Then the cached field + its thread-safety reasoning aren't needed at all

WDYT?

@binary-signal binary-signal Jun 27, 2026

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.

That makes sense, I will provide a revised version later today or tomorrow

}

// maybe create bucket assigner.
Cluster cluster = metadataUpdater.getCluster();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public class TableConfig {
// the table properties configuration
private final Configuration config;

// Cached, lazily-built strategy. Safe because TableConfig is immutable after construction
// and AutoPartitionStrategy itself is fully immutable. A benign race on first call
// produces the same value, so a plain volatile is sufficient.
private volatile AutoPartitionStrategy autoPartitionStrategy;

/**
* Creates a new table config.
*
Expand Down Expand Up @@ -156,9 +161,19 @@ public ArrowCompressionInfo getArrowCompressionInfo() {
return ArrowCompressionInfo.fromConf(config);
}

/** Gets the auto partition strategy of the table. */
/**
* Gets the auto partition strategy of the table.
*
* <p>The result is cached on first access; this assumes the underlying config is not mutated
* after this {@code TableConfig} is constructed.
*/
public AutoPartitionStrategy getAutoPartitionStrategy() {
Comment thread
binary-signal marked this conversation as resolved.
return AutoPartitionStrategy.from(config);
AutoPartitionStrategy s = autoPartitionStrategy;
if (s == null) {
s = AutoPartitionStrategy.from(config);
autoPartitionStrategy = s;
}
return s;
}

/** Gets the number of auto-increment IDs cached per segment. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,13 @@ void testDeleteBehavior() {
TableConfig tableConfig3 = new TableConfig(conf);
assertThat(tableConfig3.getDeleteBehavior()).hasValue(DeleteBehavior.IGNORE);
}

@Test
void testAutoPartitionStrategyIsCached() {
TableConfig tableConfig = new TableConfig(new Configuration());

// the strategy is memoized, so repeated calls return the same instance
assertThat(tableConfig.getAutoPartitionStrategy())
.isSameAs(tableConfig.getAutoPartitionStrategy());
}
}
Loading