Skip to content

Commit eedfd47

Browse files
feat!: add in-commit timestamps table properties (#558)
Parse: `delta.enableInCommitTimestamps`, `delta.inCommitTimestampEnablementVersion`, and `delta.inCommitTimestampEnablementTimestamp` and expose table property methods to access. ### This PR affects the following public APIs New pub fields in `TableProperties`: - `enable_in_commit_timestamps` - `in_commit_timestamp_enablement_version` - `in_commit_timestamp_enablement_timestamp`
1 parent 68f4790 commit eedfd47

File tree

3 files changed

+59
-10
lines changed

3 files changed

+59
-10
lines changed

ffi/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,8 @@ pub unsafe extern "C" fn set_builder_option(
462462
}
463463

464464
/// Consume the builder and return a `default` engine. After calling, the passed pointer is _no
465-
/// longer valid_.
465+
/// longer valid_. Note that this _consumes_ and frees the builder, so there is no need to
466+
/// drop/free it afterwards.
466467
///
467468
///
468469
/// # Safety

kernel/src/table_properties.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::time::Duration;
1616

1717
use crate::expressions::ColumnName;
1818
use crate::table_features::ColumnMappingMode;
19-
use crate::Error;
19+
use crate::{Error, Version};
2020

2121
use strum::EnumString;
2222

@@ -137,6 +137,20 @@ pub struct TableProperties {
137137
/// whether to enable row tracking during writes.
138138
pub enable_row_tracking: Option<bool>,
139139

140+
/// Whether to enable [In-Commit Timestamps]. The in-commit timestamps writer feature strongly
141+
/// associates a monotonically increasing timestamp with each commit by storing it in the
142+
/// commit's metadata.
143+
///
144+
/// [In-Commit Timestamps]: https://github.com/delta-io/delta/blob/master/PROTOCOL.md#in-commit-timestamps
145+
pub enable_in_commit_timestamps: Option<bool>,
146+
147+
/// The version of the table at which in-commit timestamps were enabled.
148+
pub in_commit_timestamp_enablement_version: Option<Version>,
149+
150+
/// The timestamp of the table at which in-commit timestamps were enabled. This must be the same
151+
/// as the inCommitTimestamp of the commit when this feature was enabled.
152+
pub in_commit_timestamp_enablement_timestamp: Option<i64>,
153+
140154
/// any unrecognized properties are passed through and ignored by the parser
141155
pub unknown_properties: HashMap<String, String>,
142156
}
@@ -268,6 +282,9 @@ mod tests {
268282
("delta.tuneFileSizesForRewrites", "true"),
269283
("delta.checkpointPolicy", "v2"),
270284
("delta.enableRowTracking", "true"),
285+
("delta.enableInCommitTimestamps", "true"),
286+
("delta.inCommitTimestampEnablementVersion", "15"),
287+
("delta.inCommitTimestampEnablementTimestamp", "1612345678"),
271288
];
272289
let actual = TableProperties::from(properties.into_iter());
273290
let expected = TableProperties {
@@ -293,6 +310,9 @@ mod tests {
293310
tune_file_sizes_for_rewrites: Some(true),
294311
checkpoint_policy: Some(CheckpointPolicy::V2),
295312
enable_row_tracking: Some(true),
313+
enable_in_commit_timestamps: Some(true),
314+
in_commit_timestamp_enablement_version: Some(15),
315+
in_commit_timestamp_enablement_timestamp: Some(1_612_345_678),
296316
unknown_properties: HashMap::new(),
297317
};
298318
assert_eq!(actual, expected);

kernel/src/table_properties/deserialize.rs

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ where
3737
// attempt to parse a key-value pair into a `TableProperties` struct. Returns Some(()) if the key
3838
// was successfully parsed, and None otherwise.
3939
fn try_parse(props: &mut TableProperties, k: &str, v: &str) -> Option<()> {
40+
// NOTE!! we do Some(parse(v)?) instead of just parse(v) because we want to return None if the
41+
// parsing fails. If we simply call 'parse(v)', then we would (incorrectly) return Some(()) and
42+
// just set the property to None.
4043
match k {
4144
"delta.appendOnly" => props.append_only = Some(parse_bool(v)?),
4245
"delta.autoOptimize.autoCompact" => props.auto_compact = Some(parse_bool(v)?),
@@ -76,17 +79,36 @@ fn try_parse(props: &mut TableProperties, k: &str, v: &str) -> Option<()> {
7679
}
7780
"delta.checkpointPolicy" => props.checkpoint_policy = CheckpointPolicy::try_from(v).ok(),
7881
"delta.enableRowTracking" => props.enable_row_tracking = Some(parse_bool(v)?),
82+
"delta.enableInCommitTimestamps" => {
83+
props.enable_in_commit_timestamps = Some(parse_bool(v)?)
84+
}
85+
"delta.inCommitTimestampEnablementVersion" => {
86+
props.in_commit_timestamp_enablement_version = Some(parse_non_negative(v)?)
87+
}
88+
"delta.inCommitTimestampEnablementTimestamp" => {
89+
props.in_commit_timestamp_enablement_timestamp = Some(parse_non_negative(v)?)
90+
}
7991
_ => return None,
8092
}
8193
Some(())
8294
}
8395

84-
/// Deserialize a string representing a positive integer into an `Option<u64>`. Returns `Some` if
85-
/// successfully parses, and `None` otherwise.
96+
/// Deserialize a string representing a positive (> 0) integer into an `Option<u64>`. Returns `Some`
97+
/// if successfully parses, and `None` otherwise.
8698
pub(crate) fn parse_positive_int(s: &str) -> Option<NonZero<u64>> {
87-
// parse to i64 (then check n > 0) since java doesn't even allow u64
88-
let n: i64 = s.parse().ok()?;
89-
NonZero::new(n.try_into().ok()?)
99+
// parse as non-negative and verify the result is non-zero
100+
NonZero::new(parse_non_negative(s)?)
101+
}
102+
103+
/// Deserialize a string representing a non-negative integer into an `Option<u64>`. Returns `Some` if
104+
/// successfully parses, and `None` otherwise.
105+
pub(crate) fn parse_non_negative<T>(s: &str) -> Option<T>
106+
where
107+
i64: TryInto<T>,
108+
{
109+
// parse to i64 since java doesn't even allow u64
110+
let n: i64 = s.parse().ok().filter(|&i| i >= 0)?;
111+
n.try_into().ok()
90112
}
91113

92114
/// Deserialize a string representing a boolean into an `Option<bool>`. Returns `Some` if
@@ -199,10 +221,16 @@ mod tests {
199221
}
200222

201223
#[test]
202-
fn test_parse_positive_int() {
203-
assert_eq!(parse_positive_int("123").unwrap().get(), 123);
224+
fn test_parse_int() {
225+
assert_eq!(parse_positive_int("12").unwrap().get(), 12);
204226
assert_eq!(parse_positive_int("0"), None);
205-
assert_eq!(parse_positive_int("-123"), None);
227+
assert_eq!(parse_positive_int("-12"), None);
228+
assert_eq!(parse_non_negative::<u64>("12").unwrap(), 12);
229+
assert_eq!(parse_non_negative::<u64>("0").unwrap(), 0);
230+
assert_eq!(parse_non_negative::<u64>("-12"), None);
231+
assert_eq!(parse_non_negative::<i64>("12").unwrap(), 12);
232+
assert_eq!(parse_non_negative::<i64>("0").unwrap(), 0);
233+
assert_eq!(parse_non_negative::<i64>("-12"), None);
206234
}
207235

208236
#[test]

0 commit comments

Comments
 (0)