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 @@ -20,6 +20,8 @@
import org.apache.fluss.annotation.VisibleForTesting;
import org.apache.fluss.config.AutoPartitionTimeUnit;
import org.apache.fluss.config.ConfigOptions;
import org.apache.fluss.config.Configuration;
import org.apache.fluss.config.TableConfig;
import org.apache.fluss.exception.InvalidConfigException;
import org.apache.fluss.exception.InvalidTableException;
import org.apache.fluss.lake.paimon.source.FlussRowAsPaimonRow;
Expand Down Expand Up @@ -397,6 +399,15 @@ public static Schema toPaimonSchema(TableDescriptor tableDescriptor) {
options.set(
CoreOptions.CHANGELOG_PRODUCER.key(),
CoreOptions.ChangelogProducer.INPUT.toString());
TableConfig tableConfig =
new TableConfig(Configuration.fromMap(tableDescriptor.getProperties()));
if (tableConfig.isHistoricalPartitionEnabled()
&& !tableConfig.isDataLakeAutoCompaction()) {
// Use the snapshot's maximum sequence number to avoid repeated manifest scans
// when historical splits write to multiple partitions and buckets.
// Use a literal key because Paimon 1.4 does not define this option.
options.set("write.sequence-number-init-mode", "snapshot");
}
}

// set partition keys
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,26 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import javax.annotation.Nullable;

import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import static org.apache.fluss.config.ConfigOptions.TABLE_DATALAKE_AUTO_COMPACTION;
import static org.apache.fluss.config.ConfigOptions.TABLE_DATALAKE_ENABLED;
import static org.apache.fluss.config.ConfigOptions.TABLE_DATALAKE_FORMAT;
import static org.apache.fluss.config.ConfigOptions.TABLE_DATALAKE_HISTORICAL_PARTITION_ENABLED;
import static org.apache.fluss.lake.paimon.utils.PaimonConversions.LAKESTREAM_ENABLED_OPTION_KEY;
import static org.apache.fluss.lake.paimon.utils.PaimonConversions.PARTITION_GENERATE_LEGACY_NAME_OPTION_KEY;
import static org.apache.fluss.lake.paimon.utils.PaimonConversions.toPaimon;
import static org.apache.fluss.lake.paimon.utils.PaimonTableValidation.isPaimonSchemaCompatible;
import static org.apache.paimon.CoreOptions.WRITE_SEQUENCE_NUMBER_INIT_MODE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

Expand Down Expand Up @@ -836,20 +843,64 @@ void testAlterTableAddColumnWhenPaimonSchemaNotMatch() throws Exception {
changes));
}

@Test
void testCreateTableSetsLakeStreamEnabledForCleanTable() throws Exception {
String database = "test_create_lakestream_db";
String tableName = "test_create_lakestream_table";
TablePath tablePath = TablePath.of(database, tableName);
Identifier identifier = Identifier.create(database, tableName);

// getTableDescriptor sets table.datalake.enabled=true, so the clean table advertises its
// LakeStream state to Paimon
flussPaimonCatalog.createTable(
tablePath, getTableDescriptor(FLUSS_SCHEMA), LAKE_CATALOG_CONTEXT);
@ParameterizedTest
@CsvSource({
"true,true,,,snapshot",
"true,true,false,,snapshot",
"true,true,true,,",
"true,false,false,,",
"false,true,false,,",
"false,true,true,,",
"true,true,false,scan,scan",
"true,true,true,snapshot,snapshot"
})
void testCreateTableOptions(
boolean primaryKey,
boolean historicalPartition,
@Nullable Boolean autoCompaction,
@Nullable String sequenceMode,
@Nullable String expectedSequenceMode)
throws Exception {
TablePath tablePath = TablePath.of("test_db", "test_create_options");

Schema.Builder schema = Schema.newBuilder().fromSchema(FLUSS_SCHEMA);
if (primaryKey) {
schema.primaryKey("id", "address");
}
TableDescriptor.Builder builder =
TableDescriptor.builder()
.schema(schema.build())
.partitionedBy("address")
.distributedBy(3)
.property(TABLE_DATALAKE_ENABLED, true)
.property(TABLE_DATALAKE_FORMAT.key(), "paimon")
.property(TABLE_DATALAKE_HISTORICAL_PARTITION_ENABLED, historicalPartition);
if (autoCompaction != null) {
builder.property(TABLE_DATALAKE_AUTO_COMPACTION, autoCompaction);
}
String option = "paimon." + WRITE_SEQUENCE_NUMBER_INIT_MODE.key();
if (sequenceMode != null) {
builder.customProperty(option, sequenceMode);
}
TableDescriptor descriptor = builder.build();
TestingLakeCatalogContext context = new TestingLakeCatalogContext(descriptor);
flussPaimonCatalog.createTable(tablePath, descriptor, context);

Table table = flussPaimonCatalog.getPaimonCatalog().getTable(identifier);
Table table = flussPaimonCatalog.getPaimonCatalog().getTable(toPaimon(tablePath));
assertThat(table.options()).containsEntry(LAKESTREAM_ENABLED_OPTION_KEY, "true");
assertThat(table.options().get(WRITE_SEQUENCE_NUMBER_INIT_MODE.key()))
.isEqualTo(expectedSequenceMode);

if ("snapshot".equals(expectedSequenceMode)) {
flussPaimonCatalog.alterTable(
tablePath, Collections.singletonList(TableChange.set(option, "scan")), context);
assertThat(
flussPaimonCatalog
.getPaimonCatalog()
.getTable(toPaimon(tablePath))
.options())
.containsEntry(WRITE_SEQUENCE_NUMBER_INIT_MODE.key(), "scan");
}
}

@Test
Expand Down
Loading
Loading