mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-24 13:16:28 +00:00
feat(table-catalog): add parquet compaction commit (#3487)
Co-authored-by: Henry Guo <marshawcoco@users.noreply.github.com>
This commit is contained in:
@@ -241,6 +241,8 @@ struct TableMetadataMaintenanceRequest {
|
|||||||
commit_snapshot_expiration: bool,
|
commit_snapshot_expiration: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
compaction: Option<crate::table_catalog::TableCompactionPlanningConfig>,
|
compaction: Option<crate::table_catalog::TableCompactionPlanningConfig>,
|
||||||
|
#[serde(default, rename = "commit-compaction")]
|
||||||
|
commit_compaction: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@@ -2626,11 +2628,30 @@ where
|
|||||||
"snapshot expiration commit cannot be combined with metadata deletion"
|
"snapshot expiration commit cannot be combined with metadata deletion"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if request.delete && request.commit_compaction {
|
||||||
|
return Err(s3_error!(InvalidRequest, "compaction commit cannot be combined with metadata deletion"));
|
||||||
|
}
|
||||||
|
if request.commit_snapshot_expiration && request.commit_compaction {
|
||||||
|
return Err(s3_error!(
|
||||||
|
InvalidRequest,
|
||||||
|
"compaction commit cannot be combined with snapshot expiration commit"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if request.commit_compaction && request.compaction.is_none() {
|
||||||
|
return Err(s3_error!(InvalidRequest, "commit-compaction requires a compaction request"));
|
||||||
|
}
|
||||||
|
|
||||||
let snapshot_expiration_request = request.snapshot_expiration;
|
let snapshot_expiration_request = request.snapshot_expiration;
|
||||||
let commit_snapshot_expiration = request.commit_snapshot_expiration;
|
let commit_snapshot_expiration = request.commit_snapshot_expiration;
|
||||||
let compaction_request = request.compaction;
|
let compaction_request = request.compaction;
|
||||||
|
let commit_compaction = request.commit_compaction;
|
||||||
let compaction = match compaction_request {
|
let compaction = match compaction_request {
|
||||||
|
Some(config) if commit_compaction => Some(
|
||||||
|
store
|
||||||
|
.commit_table_compaction(bucket, &namespace.public_name(), table, config)
|
||||||
|
.await
|
||||||
|
.map_err(catalog_store_error)?,
|
||||||
|
),
|
||||||
Some(config) => Some(
|
Some(config) => Some(
|
||||||
store
|
store
|
||||||
.plan_table_compaction(bucket, &namespace.public_name(), table, config)
|
.plan_table_compaction(bucket, &namespace.public_name(), table, config)
|
||||||
@@ -2673,15 +2694,19 @@ where
|
|||||||
.snapshot_expiration
|
.snapshot_expiration
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|snapshot_expiration| snapshot_expiration.committed_metadata_location.is_some());
|
.is_some_and(|snapshot_expiration| snapshot_expiration.committed_metadata_location.is_some());
|
||||||
|
let committed_compaction = report
|
||||||
|
.compaction
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|compaction| compaction.committed_metadata_location.is_some());
|
||||||
match store.put_table_metadata_maintenance_report(&report).await {
|
match store.put_table_metadata_maintenance_report(&report).await {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(err) if committed_snapshot_expiration => {
|
Err(err) if committed_snapshot_expiration || committed_compaction => {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
error = %err,
|
error = %err,
|
||||||
warehouse = bucket,
|
warehouse = bucket,
|
||||||
namespace = namespace.public_name(),
|
namespace = namespace.public_name(),
|
||||||
table,
|
table,
|
||||||
"failed to persist table maintenance report after snapshot expiration commit"
|
"failed to persist table maintenance report after catalog maintenance commit"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(err) => return Err(catalog_store_error(err)),
|
Err(err) => return Err(catalog_store_error(err)),
|
||||||
@@ -3895,6 +3920,7 @@ mod tests {
|
|||||||
assert!(request.snapshot_expiration.is_none());
|
assert!(request.snapshot_expiration.is_none());
|
||||||
assert!(!request.commit_snapshot_expiration);
|
assert!(!request.commit_snapshot_expiration);
|
||||||
assert!(request.compaction.is_none());
|
assert!(request.compaction.is_none());
|
||||||
|
assert!(!request.commit_compaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -3910,6 +3936,7 @@ mod tests {
|
|||||||
assert!(request.snapshot_expiration.is_none());
|
assert!(request.snapshot_expiration.is_none());
|
||||||
assert!(!request.commit_snapshot_expiration);
|
assert!(!request.commit_snapshot_expiration);
|
||||||
assert!(request.compaction.is_none());
|
assert!(request.compaction.is_none());
|
||||||
|
assert!(!request.commit_compaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -3920,6 +3947,7 @@ mod tests {
|
|||||||
"min-snapshots-to-keep": 2,
|
"min-snapshots-to-keep": 2,
|
||||||
"max-snapshot-age-ms": 3600000
|
"max-snapshot-age-ms": 3600000
|
||||||
},
|
},
|
||||||
|
"commit-compaction": true,
|
||||||
"compaction": {
|
"compaction": {
|
||||||
"target-file-size-bytes": 536870912,
|
"target-file-size-bytes": 536870912,
|
||||||
"small-file-threshold-bytes": 67108864,
|
"small-file-threshold-bytes": 67108864,
|
||||||
@@ -3935,6 +3963,7 @@ mod tests {
|
|||||||
assert_eq!(snapshot_expiration.min_snapshots_to_keep, 2);
|
assert_eq!(snapshot_expiration.min_snapshots_to_keep, 2);
|
||||||
assert_eq!(snapshot_expiration.max_snapshot_age_ms, 3_600_000);
|
assert_eq!(snapshot_expiration.max_snapshot_age_ms, 3_600_000);
|
||||||
assert!(request.commit_snapshot_expiration);
|
assert!(request.commit_snapshot_expiration);
|
||||||
|
assert!(request.commit_compaction);
|
||||||
let compaction = request.compaction.expect("compaction config should be present");
|
let compaction = request.compaction.expect("compaction config should be present");
|
||||||
assert_eq!(compaction.target_file_size_bytes, 536_870_912);
|
assert_eq!(compaction.target_file_size_bytes, 536_870_912);
|
||||||
assert_eq!(compaction.small_file_threshold_bytes, 67_108_864);
|
assert_eq!(compaction.small_file_threshold_bytes, 67_108_864);
|
||||||
@@ -4909,6 +4938,7 @@ mod tests {
|
|||||||
min_input_files: 2,
|
min_input_files: 2,
|
||||||
max_rewrite_bytes_per_job: 1024 * 1024 * 1024,
|
max_rewrite_bytes_per_job: 1024 * 1024 * 1024,
|
||||||
}),
|
}),
|
||||||
|
commit_compaction: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -4955,6 +4985,7 @@ mod tests {
|
|||||||
snapshot_expiration: None,
|
snapshot_expiration: None,
|
||||||
commit_snapshot_expiration: false,
|
commit_snapshot_expiration: false,
|
||||||
compaction: None,
|
compaction: None,
|
||||||
|
commit_compaction: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -5046,6 +5077,7 @@ mod tests {
|
|||||||
}),
|
}),
|
||||||
commit_snapshot_expiration: true,
|
commit_snapshot_expiration: true,
|
||||||
compaction: None,
|
compaction: None,
|
||||||
|
commit_compaction: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -5164,6 +5196,7 @@ mod tests {
|
|||||||
}),
|
}),
|
||||||
commit_snapshot_expiration: true,
|
commit_snapshot_expiration: true,
|
||||||
compaction: None,
|
compaction: None,
|
||||||
|
commit_compaction: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@@ -5283,6 +5316,7 @@ mod tests {
|
|||||||
}),
|
}),
|
||||||
commit_snapshot_expiration: true,
|
commit_snapshot_expiration: true,
|
||||||
compaction: None,
|
compaction: None,
|
||||||
|
commit_compaction: false,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
+1520
-75
File diff suppressed because it is too large
Load Diff
@@ -153,7 +153,7 @@ current unsupported inventory is:
|
|||||||
- manifest/data reachability cleanup: metadata maintenance reads manifest-list and manifest Avro references, reports manifest/data/delete reachability, and deletes only unreferenced table objects that pass the safety window
|
- manifest/data reachability cleanup: metadata maintenance reads manifest-list and manifest Avro references, reports manifest/data/delete reachability, and deletes only unreferenced table objects that pass the safety window
|
||||||
- snapshot expiration dry-run planning and manual catalog commit: supported through metadata maintenance reports
|
- snapshot expiration dry-run planning and manual catalog commit: supported through metadata maintenance reports
|
||||||
- automatic maintenance scheduling: external scheduler hook supported through the worker run endpoint; built-in periodic scheduling is not claimed
|
- automatic maintenance scheduling: external scheduler hook supported through the worker run endpoint; built-in periodic scheduling is not claimed
|
||||||
- compaction rewrite: unsupported; planning reports fail closed until data file rewrite support is implemented
|
- compaction rewrite: controlled run-once support for unpartitioned Parquet binpack through metadata maintenance; built-in periodic scheduling, sort compaction, delete-file rewrite, and row-level compaction are not claimed
|
||||||
- Iceberg views: stable unsupported routes are registered and return explicit unsupported JSON
|
- Iceberg views: stable unsupported routes are registered and return explicit unsupported JSON
|
||||||
- external catalog bridges: metadata import/register is supported, but Polaris/Glue/DLF/Hive synchronization is unsupported
|
- external catalog bridges: metadata import/register is supported, but Polaris/Glue/DLF/Hive synchronization is unsupported
|
||||||
- multi-table transactions: not a short-term production claim
|
- multi-table transactions: not a short-term production claim
|
||||||
|
|||||||
@@ -152,9 +152,9 @@ UNSUPPORTED_INVENTORY: list[dict[str, str]] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"capability": "compaction-rewrite",
|
"capability": "compaction-rewrite",
|
||||||
"status": "planning-only",
|
"status": "controlled-run-once-supported",
|
||||||
"roadmap_area": "snapshot-maintenance",
|
"roadmap_area": "snapshot-maintenance",
|
||||||
"expected_behavior": "compaction planning fails closed until data file rewrite support is implemented; no data file rewrite or automatic compaction is claimed",
|
"expected_behavior": "metadata maintenance can plan binpack candidates and commit a safe unpartitioned Parquet rewrite through the catalog; built-in periodic scheduling, sort compaction, delete-file rewrite, and row-level compaction are not claimed",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"capability": "iceberg-views",
|
"capability": "iceberg-views",
|
||||||
|
|||||||
Reference in New Issue
Block a user