Skip to content

Commit 0cdf4e7

Browse files
ICT support
1 parent 8b71117 commit 0cdf4e7

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

kernel/src/table_configuration.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,63 @@ impl TableConfiguration {
263263
version => (2..=6).contains(&version),
264264
}
265265
}
266+
267+
/// Returns `true` if the table supports writing in-commit timestamps.
268+
///
269+
/// To support this feature the table must:
270+
/// - Have a min_writer_version of 7
271+
/// - Have the [`WriterFeature::InCommitTimestamps`] writer feature.
272+
#[allow(unused)]
273+
pub(crate) fn is_in_commit_timestamps_supported(&self) -> bool {
274+
self.protocol().min_writer_version() == 7
275+
&& self
276+
.protocol()
277+
.has_writer_feature(&WriterFeature::InCommitTimestamps)
278+
}
279+
280+
/// Returns `true` if in-commit timestamps is supported and it is enabled. In-commit timestamps
281+
/// is enabled when the `delta.enableInCommitTimestamps` configuration is set to `true`.
282+
#[allow(unused)]
283+
pub(crate) fn is_in_commit_timestamps_enabled(&self) -> bool {
284+
self.is_in_commit_timestamps_supported()
285+
&& self
286+
.table_properties()
287+
.enable_in_commit_timestamps
288+
.unwrap_or(false)
289+
}
290+
291+
/// If in-commit timestamps is enabled, this retrieves the in-commit timestamp enablement version
292+
/// and timestamps.
293+
///
294+
/// If in-commit timestamps is not supported, or not enabled, this returns `None`.
295+
/// If in-commit timestams is enabled, but the enablement version or timestamp is not present,
296+
/// this returns an error.
297+
#[allow(unused)]
298+
pub(crate) fn in_commit_timestamp_enablement(&self) -> DeltaResult<Option<(Version, i64)>> {
299+
if !self.is_in_commit_timestamps_enabled() {
300+
return Ok(None);
301+
}
302+
let enablement_version = self
303+
.table_properties()
304+
.in_commit_timestamp_enablement_version;
305+
let enablement_timestamp = self
306+
.table_properties()
307+
.in_commit_timestamp_enablement_timestamp;
308+
309+
let ict_error = |err: &str| {
310+
Error::generic(format!(
311+
"In-commit timestamp enabled, but missing Enablement version or timestamp. {err}"
312+
))
313+
};
314+
match (enablement_version, enablement_timestamp) {
315+
(Some(version), Some(timestamp)) => Ok(Some((version, timestamp))),
316+
(Some(version), None) => Err(ict_error("Enablement timestamp is not present")),
317+
(None, Some(timestmap)) => Err(ict_error("Enablement version is not present")),
318+
(None, None) => Err(ict_error(
319+
"Enablement version and timestamp are not present.",
320+
)),
321+
}
322+
}
266323
}
267324

268325
#[cfg(test)]
@@ -274,6 +331,7 @@ mod test {
274331
use crate::actions::{Metadata, Protocol};
275332
use crate::table_features::{ReaderFeature, WriterFeature};
276333
use crate::table_properties::TableProperties;
334+
use crate::Error;
277335

278336
use super::TableConfiguration;
279337

@@ -326,6 +384,75 @@ mod test {
326384
assert!(table_config.is_deletion_vector_enabled());
327385
}
328386
#[test]
387+
fn ict_supported_and_enabled() {
388+
let metadata = Metadata {
389+
schema_string: r#"{"type":"struct","fields":[{"name":"value","type":"integer","nullable":true,"metadata":{}}]}"#.to_string(),
390+
configuration: HashMap::from_iter([(
391+
"delta.enableInCommitTimestamps".to_string(),
392+
"true".to_string(),
393+
),
394+
("delta.inCommitTimestampEnablementVersion".to_string(), "5".to_string()),
395+
("delta.inCommitTimestampEnablementTimestamp".to_string(), "100".to_string())]),
396+
..Default::default()
397+
};
398+
let protocol = Protocol::try_new(
399+
3,
400+
7,
401+
Some::<Vec<String>>(vec![]),
402+
Some([WriterFeature::InCommitTimestamps]),
403+
)
404+
.unwrap();
405+
let table_root = Url::try_from("file:///").unwrap();
406+
let table_config = TableConfiguration::try_new(metadata, protocol, table_root, 0).unwrap();
407+
assert!(table_config.is_in_commit_timestamps_supported());
408+
assert!(table_config.is_in_commit_timestamps_enabled());
409+
let enablement = table_config.in_commit_timestamp_enablement().unwrap();
410+
assert_eq!(enablement, Some((5, 100)))
411+
}
412+
#[test]
413+
fn ict_supported_and_enabled_without_enablement_info() {
414+
let metadata = Metadata {
415+
schema_string: r#"{"type":"struct","fields":[{"name":"value","type":"integer","nullable":true,"metadata":{}}]}"#.to_string(),
416+
configuration: HashMap::from_iter([(
417+
"delta.enableInCommitTimestamps".to_string(),
418+
"true".to_string(),
419+
)]),
420+
..Default::default()
421+
};
422+
let protocol = Protocol::try_new(
423+
3,
424+
7,
425+
Some::<Vec<String>>(vec![]),
426+
Some([WriterFeature::InCommitTimestamps]),
427+
)
428+
.unwrap();
429+
let table_root = Url::try_from("file:///").unwrap();
430+
let table_config = TableConfiguration::try_new(metadata, protocol, table_root, 0).unwrap();
431+
assert!(table_config.is_in_commit_timestamps_supported());
432+
assert!(table_config.is_in_commit_timestamps_enabled());
433+
assert!(matches!(
434+
table_config.in_commit_timestamp_enablement(),
435+
Err(Error::Generic(msg)) if msg.contains("Enablement version and timestamp are not present.")));
436+
}
437+
#[test]
438+
fn ict_supported_and_not_enabled() {
439+
let metadata = Metadata {
440+
schema_string: r#"{"type":"struct","fields":[{"name":"value","type":"integer","nullable":true,"metadata":{}}]}"#.to_string(),
441+
..Default::default()
442+
};
443+
let protocol = Protocol::try_new(
444+
3,
445+
7,
446+
Some::<Vec<String>>(vec![]),
447+
Some([WriterFeature::InCommitTimestamps]),
448+
)
449+
.unwrap();
450+
let table_root = Url::try_from("file:///").unwrap();
451+
let table_config = TableConfiguration::try_new(metadata, protocol, table_root, 0).unwrap();
452+
assert!(table_config.is_in_commit_timestamps_supported());
453+
assert!(!table_config.is_in_commit_timestamps_enabled());
454+
}
455+
#[test]
329456
fn fails_on_unsupported_feature() {
330457
let metadata = Metadata {
331458
schema_string: r#"{"type":"struct","fields":[{"name":"value","type":"integer","nullable":true,"metadata":{}}]}"#.to_string(),

kernel/src/table_features/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ pub enum WriterFeature {
9090
ColumnMapping,
9191
/// ID Columns
9292
IdentityColumns,
93+
/// Monotonically increasing timestamps in the CommitInfo
94+
InCommitTimestamps,
9395
/// Deletion vectors for merge, update, delete
9496
DeletionVectors,
9597
/// Row tracking on tables
@@ -244,6 +246,7 @@ mod tests {
244246
(WriterFeature::GeneratedColumns, "generatedColumns"),
245247
(WriterFeature::ColumnMapping, "columnMapping"),
246248
(WriterFeature::IdentityColumns, "identityColumns"),
249+
(WriterFeature::InCommitTimestamps, "inCommitTimestamps"),
247250
(WriterFeature::DeletionVectors, "deletionVectors"),
248251
(WriterFeature::RowTracking, "rowTracking"),
249252
(WriterFeature::TimestampWithoutTimezone, "timestampNtz"),

0 commit comments

Comments
 (0)