From 393f2b581873430c83e6103080e6d0d368b3152d Mon Sep 17 00:00:00 2001 From: "zhou.cai" Date: Mon, 13 Apr 2026 17:41:37 +0800 Subject: [PATCH 1/6] deltalake gcs --- Cargo.lock | 18 ++++++++++++++++++ Cargo.toml | 2 +- src/common/deltalake_writer/delta_ops.rs | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6257c794..786665d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4713,6 +4713,7 @@ dependencies = [ "deltalake-aws", "deltalake-azure", "deltalake-core", + "deltalake-gcp", ] [[package]] @@ -4821,6 +4822,23 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "deltalake-gcp" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df2708856cfa92e8309141fda1ee8d41e174b0868f26e557d0b2ea8d30fb92e" +dependencies = [ + "async-trait", + "bytes 1.10.1", + "deltalake-core", + "futures 0.3.31", + "object_store 0.12.4", + "thiserror 2.0.15", + "tokio", + "tracing 0.1.41", + "url", +] + [[package]] name = "der" version = "0.7.10" diff --git a/Cargo.toml b/Cargo.toml index 5972af76..ce1dc52c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ azure_storage_blobs = { version = "0.17.0", default-features = false, features = base64 = { version = "0.22.1", default-features = false } bytes = { version = "1.10.1", default-features = false, features = ["serde"] } chrono = { version = "0.4.41", default-features = false, features = ["clock", "serde"] } -deltalake = { version = "0.29.3", features = ["datafusion", "s3", "azure"] } +deltalake = { version = "0.29.3", features = ["datafusion", "s3", "azure", "gcs"] } datafusion = { version = "48" } duckdb = { version = "1.0", features = ["bundled"] } etcd-client = { version = "0.14", features = ["tls-roots"] } diff --git a/src/common/deltalake_writer/delta_ops.rs b/src/common/deltalake_writer/delta_ops.rs index 7c8c3681..c38a7dd8 100644 --- a/src/common/deltalake_writer/delta_ops.rs +++ b/src/common/deltalake_writer/delta_ops.rs @@ -46,7 +46,7 @@ impl DeltaOpsManager { *session_token = "***REDACTED***".to_string(); } info!( - "Using storage options for S3 authentication: {:?}", + "Using storage options: {:?}", redacted_options ); Ok(DeltaOps::try_from_uri_with_storage_options( From 6636544742599a7b972934f5561fb01752b77e77 Mon Sep 17 00:00:00 2001 From: "zhou.cai" Date: Fri, 17 Apr 2026 17:14:21 +0800 Subject: [PATCH 2/6] optimize docker image size --- Cargo.toml | 3 +++ Makefile | 21 +++++++++++++++++++++ scripts/docker/Dockerfile | 24 ++++++++++++++++++++++-- scripts/release-docker.sh | 4 ++-- 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ce1dc52c..7eada567 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,9 @@ default-run = "vector" [profile.release] codegen-units = 1 lto = "fat" +strip = true +panic = "abort" +opt-level = "z" [[bin]] name = "vector" diff --git a/Makefile b/Makefile index 733b2f0b..7aa1ac2f 100644 --- a/Makefile +++ b/Makefile @@ -191,6 +191,20 @@ release-docker: target/aarch64-unknown-linux-gnu/release/vector @scripts/release-docker.sh @echo "Done releasing docker image." +.PHONY: release-docker-alpine +release-docker-alpine: target/x86_64-unknown-linux-musl/release/vector +release-docker-alpine: target/aarch64-unknown-linux-musl/release/vector + @echo "Releasing Alpine docker image..." + @DOCKER_BASE=alpine scripts/release-docker.sh + @echo "Done releasing Alpine docker image." + +.PHONY: release-docker-minimal +release-docker-minimal: target/x86_64-unknown-linux-musl/release/vector +release-docker-minimal: target/aarch64-unknown-linux-musl/release/vector + @echo "Releasing minimal scratch docker image..." + @DOCKER_BASE=minimal scripts/release-docker.sh + @echo "Done releasing minimal scratch docker image." + .PHONY: release-docker-nextgen release-docker-nextgen: target/x86_64-unknown-linux-gnu/release/vector-nextgen release-docker-nextgen: target/aarch64-unknown-linux-gnu/release/vector-nextgen @@ -199,6 +213,13 @@ release-docker-nextgen: target/aarch64-unknown-linux-gnu/release/vector-nextgen @NEXTGEN=true scripts/release-docker.sh @echo "Done releasing docker image (nextgen mode)." +.PHONY: release-docker-nextgen-alpine +release-docker-nextgen-alpine: target/x86_64-unknown-linux-musl/release/vector-nextgen +release-docker-nextgen-alpine: target/aarch64-unknown-linux-musl/release/vector-nextgen + @echo "Releasing Alpine docker image (nextgen mode)..." + @NEXTGEN=true DOCKER_BASE=alpine scripts/release-docker.sh + @echo "Done releasing Alpine docker image (nextgen mode)." + .PHONY: test-integration test-integration: @echo "Running integration tests..." diff --git a/scripts/docker/Dockerfile b/scripts/docker/Dockerfile index 076abf0c..e4d52b07 100644 --- a/scripts/docker/Dockerfile +++ b/scripts/docker/Dockerfile @@ -1,8 +1,28 @@ +# Multi-stage build for smaller final image +FROM docker.io/debian:13-slim as builder + +# Install build dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + tzdata \ + systemd \ + curl \ + binutils \ + && rm -rf /var/lib/apt/lists/* + +# Final stage with minimal runtime dependencies FROM docker.io/debian:13-slim -RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates tzdata systemd curl binutils + +# Install only runtime dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + tzdata \ + systemd \ + && rm -rf /var/lib/apt/lists/* \ + && apt-get clean ARG TARGETARCH -COPY vector-$TARGETARCH /usr/bin/vector +COPY --from=builder /usr/bin/vector-$TARGETARCH /usr/bin/vector # COPY vector.toml /etc/vector/vector.toml ENV VECTOR_LOG="info" diff --git a/scripts/release-docker.sh b/scripts/release-docker.sh index c924e555..b27e170b 100755 --- a/scripts/release-docker.sh +++ b/scripts/release-docker.sh @@ -40,10 +40,10 @@ cp target/aarch64-unknown-linux-gnu/release/${BINARY_NAME} "$WORK_DIR"/vector-ar VERSION="${VECTOR_VERSION:-"$(scripts/version.sh)"}" REPO="${REPO:-"tidbcloud/vector"}" -BASE=debian +BASE="${DOCKER_BASE:-debian}" TAG="${TAG:-$REPO:$VERSION-$BASE}" -DOCKERFILE="scripts/docker/Dockerfile" +DOCKERFILE="scripts/docker/Dockerfile${BASE:+.${BASE}}" #PLATFORMS="linux/amd64,linux/arm64,linux/arm/v7" PLATFORMS="linux/amd64,linux/arm64" From 10bc14ca43c36cd2ff286ad933fb6a5047d547be Mon Sep 17 00:00:00 2001 From: "zhou.cai" Date: Mon, 20 Apr 2026 14:00:09 +0800 Subject: [PATCH 3/6] optimize docker image size --- scripts/docker/Dockerfile | 2 +- scripts/release-docker.sh | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/scripts/docker/Dockerfile b/scripts/docker/Dockerfile index e4d52b07..55606c79 100644 --- a/scripts/docker/Dockerfile +++ b/scripts/docker/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean ARG TARGETARCH -COPY --from=builder /usr/bin/vector-$TARGETARCH /usr/bin/vector +COPY vector-$TARGETARCH /usr/bin/vector # COPY vector.toml /etc/vector/vector.toml ENV VECTOR_LOG="info" diff --git a/scripts/release-docker.sh b/scripts/release-docker.sh index b27e170b..0c1ca831 100755 --- a/scripts/release-docker.sh +++ b/scripts/release-docker.sh @@ -43,7 +43,16 @@ REPO="${REPO:-"tidbcloud/vector"}" BASE="${DOCKER_BASE:-debian}" TAG="${TAG:-$REPO:$VERSION-$BASE}" -DOCKERFILE="scripts/docker/Dockerfile${BASE:+.${BASE}}" +# Default Debian image uses scripts/docker/Dockerfile (no .debian suffix). +# Alpine/minimal use scripts/docker/Dockerfile.. +case "${BASE}" in +debian) + DOCKERFILE="scripts/docker/Dockerfile" + ;; +*) + DOCKERFILE="scripts/docker/Dockerfile.${BASE}" + ;; +esac #PLATFORMS="linux/amd64,linux/arm64,linux/arm/v7" PLATFORMS="linux/amd64,linux/arm64" From 6865bfc688cb19ddd677583afae6c3c9f250cc04 Mon Sep 17 00:00:00 2001 From: "zhou.cai" Date: Wed, 3 Jun 2026 15:52:48 +0800 Subject: [PATCH 4/6] fix delta lake write issue --- src/common/deltalake_writer/delta_ops.rs | 19 +++ src/common/deltalake_writer/errors.rs | 33 ++++ src/common/deltalake_writer/mod.rs | 2 + src/sinks/deltalake/processor.rs | 149 ++++++++++++++++--- src/sinks/topsql_data_deltalake/processor.rs | 55 ++++--- src/sinks/topsql_meta_deltalake/processor.rs | 54 ++++--- tests/deltalake_stale_log_test.rs | 147 ++++++++++++++++++ 7 files changed, 393 insertions(+), 66 deletions(-) create mode 100644 src/common/deltalake_writer/errors.rs create mode 100644 tests/deltalake_stale_log_test.rs diff --git a/src/common/deltalake_writer/delta_ops.rs b/src/common/deltalake_writer/delta_ops.rs index c38a7dd8..920d8537 100644 --- a/src/common/deltalake_writer/delta_ops.rs +++ b/src/common/deltalake_writer/delta_ops.rs @@ -9,6 +9,7 @@ use deltalake::DeltaOps; use tracing::{error, info, warn}; use url::Url; +use super::errors::is_stale_delta_log_error; use super::schema::SchemaManager; use super::types::TypeConverter; @@ -276,6 +277,24 @@ impl DeltaOpsManager { ); return Err(e.into()); } + } + // Stale log view after external compaction or concurrent writers + else if is_stale_delta_log_error(&error_str) { + if attempt < MAX_RETRIES - 1 { + warn!( + "Stale Delta log detected (attempt {}/{}): {}. Reloading table and retrying...", + attempt + 1, + MAX_RETRIES, + error_str + ); + continue; + } else { + error!( + "Stale Delta log after {} retries: {}", + MAX_RETRIES, error_str + ); + return Err(e.into()); + } } else { // Other error, fail immediately error!("Failed to write to Delta table: {}", e); diff --git a/src/common/deltalake_writer/errors.rs b/src/common/deltalake_writer/errors.rs new file mode 100644 index 00000000..6d2991de --- /dev/null +++ b/src/common/deltalake_writer/errors.rs @@ -0,0 +1,33 @@ +/// Returns true when a Delta Lake write error likely reflects a stale table log view, +/// for example after external compaction removed older `_delta_log` JSON files. +pub fn is_stale_delta_log_error(error_msg: &str) -> bool { + error_msg.contains("log segment") + || error_msg.contains("Invalid table version") + || error_msg.contains("not found") + || error_msg.contains("No such file or directory") + || error_msg.contains("Kernel error") + || error_msg.contains("No table metadata or protocol found in delta log") + || error_msg.contains("Expected ordered contiguous commit files") +} + +#[cfg(test)] +mod tests { + use super::is_stale_delta_log_error; + + #[test] + fn detects_missing_delta_log_file() { + let msg = "Kernel error: File not found: deltalake/org=1/_delta_log/00000000000000020406.json"; + assert!(is_stale_delta_log_error(msg)); + } + + #[test] + fn detects_kernel_error_without_file_not_found() { + let msg = "Kernel error: No table metadata or protocol found in delta log."; + assert!(is_stale_delta_log_error(msg)); + } + + #[test] + fn ignores_unrelated_errors() { + assert!(!is_stale_delta_log_error("permission denied")); + } +} diff --git a/src/common/deltalake_writer/mod.rs b/src/common/deltalake_writer/mod.rs index 9a3d0fc7..b030c2d5 100644 --- a/src/common/deltalake_writer/mod.rs +++ b/src/common/deltalake_writer/mod.rs @@ -9,12 +9,14 @@ use vector_lib::event::Event; // Module declarations pub mod converter; pub mod delta_ops; +pub mod errors; pub mod schema; pub mod types; // Re-export main types pub use converter::EventConverter; pub use delta_ops::DeltaOpsManager; +pub use errors::is_stale_delta_log_error; pub use schema::SchemaManager; pub use types::TypeConverter; diff --git a/src/sinks/deltalake/processor.rs b/src/sinks/deltalake/processor.rs index 31058be2..1b0a6b40 100644 --- a/src/sinks/deltalake/processor.rs +++ b/src/sinks/deltalake/processor.rs @@ -1,13 +1,16 @@ use std::collections::HashMap; use std::path::PathBuf; use std::sync::Arc; +use std::time::Duration; use futures::{stream::BoxStream, StreamExt}; use tokio::sync::Mutex; use vector_lib::event::Event; use vector_lib::sink::StreamSink; -use crate::common::deltalake_writer::{DeltaLakeWriter, DeltaTableConfig, WriteConfig}; +use crate::common::deltalake_writer::{ + is_stale_delta_log_error, DeltaLakeWriter, DeltaTableConfig, WriteConfig, +}; /// Delta Lake sink processor pub struct DeltaLakeSink { @@ -69,30 +72,41 @@ impl DeltaLakeSink { // Write each table's events for (table_name, table_events) in table_events { if let Err(e) = self.write_table_events(&table_name, table_events).await { - let error_msg = e.to_string(); - if error_msg.contains("log segment") - || error_msg.contains("Invalid table version") - || error_msg.contains("not found") - || error_msg.contains("No such file or directory") - { - panic!( - "Delta Lake corruption detected for table {}: {}", - table_name, error_msg - ); - } else { - error!("Failed to write events to table {}: {}", table_name, e); - } + error!("Failed to write events to table {}: {}", table_name, e); } } Ok(()) } - /// Write events to a specific table + /// Write events to a specific table, evicting and reopening the writer once on stale log errors. async fn write_table_events( &self, table_name: &str, events: Vec, + ) -> Result<(), Box> { + match self + .write_table_events_once(table_name, &events) + .await + { + Ok(()) => Ok(()), + Err(e) if is_stale_delta_log_error(&e.to_string()) => { + warn!( + "Stale Delta log for table {}, evicting cached writer and retrying once: {}", + table_name, e + ); + self.writers.lock().await.remove(table_name); + tokio::time::sleep(Duration::from_millis(200)).await; + self.write_table_events_once(table_name, &events).await + } + Err(e) => Err(e), + } + } + + async fn write_table_events_once( + &self, + table_name: &str, + events: &[Event], ) -> Result<(), Box> { // Get or create writer for this table let mut writers = self.writers.lock().await; @@ -135,7 +149,7 @@ impl DeltaLakeSink { }); // Write events - writer.write_events(events).await?; + writer.write_events(events.to_vec()).await?; Ok(()) } @@ -165,9 +179,36 @@ impl StreamSink for DeltaLakeSink { mod tests { use super::*; use std::collections::BTreeMap; - use vector_lib::event::LogEvent; + use std::fs; + use vector_lib::event::{LogEvent, ObjectMap}; + + fn create_test_event(table_name: &str, index: i64) -> Event { + let mut log = LogEvent::from(BTreeMap::new()); + log.insert("_vector_table", table_name); + log.insert("_vector_source_table", "TEST_SOURCE"); + log.insert("_vector_source_schema", "test_schema"); + log.insert("_vector_instance", "test-instance"); + log.insert("_vector_timestamp", "2024-06-01T00:00:00Z"); + log.insert("id", index); + log.insert("value", format!("row-{index}")); + + let mut schema_meta = ObjectMap::new(); + schema_meta.insert("_partition_by".into(), vector_lib::event::Value::from("date")); + let mut id_meta = ObjectMap::new(); + id_meta.insert("mysql_type".into(), vector_lib::event::Value::from("bigint")); + schema_meta.insert("id".into(), vector_lib::event::Value::Object(id_meta)); + let mut value_meta = ObjectMap::new(); + value_meta.insert( + "mysql_type".into(), + vector_lib::event::Value::from("varchar(64)"), + ); + schema_meta.insert("value".into(), vector_lib::event::Value::Object(value_meta)); + log.insert("_schema_metadata", vector_lib::event::Value::Object(schema_meta)); + + Event::Log(log) + } - fn create_test_event(table_field: &str, table_name: &str) -> Event { + fn create_test_event_legacy(table_field: &str, table_name: &str) -> Event { let mut log = LogEvent::from(BTreeMap::new()); log.insert(table_field, table_name); log.insert("test_field", "test_value"); @@ -176,7 +217,7 @@ mod tests { #[test] fn test_table_name_extraction_from_vector_table() { - let event = create_test_event("_vector_table", "test_table"); + let event = create_test_event_legacy("_vector_table", "test_table"); if let Event::Log(log) = &event { let table_name = log .get("_vector_table") @@ -189,7 +230,7 @@ mod tests { #[test] fn test_table_name_extraction_from_dest_table() { - let event = create_test_event("dest_table", "my_dest_table"); + let event = create_test_event_legacy("dest_table", "my_dest_table"); if let Event::Log(log) = &event { let table_name = log .get("_vector_table") @@ -202,7 +243,7 @@ mod tests { #[test] fn test_table_name_extraction_from_table() { - let event = create_test_event("table", "fallback_table"); + let event = create_test_event_legacy("table", "fallback_table"); if let Event::Log(log) = &event { let table_name = log .get("_vector_table") @@ -235,9 +276,9 @@ mod tests { #[test] fn test_events_grouping_by_table() { let events = vec![ - create_test_event("_vector_table", "table_a"), - create_test_event("_vector_table", "table_b"), - create_test_event("_vector_table", "table_a"), + create_test_event_legacy("_vector_table", "table_a"), + create_test_event_legacy("_vector_table", "table_b"), + create_test_event_legacy("_vector_table", "table_a"), ]; let mut table_events: HashMap> = HashMap::new(); @@ -262,4 +303,64 @@ mod tests { assert_eq!(table_events.get("table_a").unwrap().len(), 2); assert_eq!(table_events.get("table_b").unwrap().len(), 1); } + + fn delta_log_json_files(delta_log_path: &std::path::Path) -> Vec { + let mut files: Vec = fs::read_dir(delta_log_path) + .expect("read _delta_log") + .filter_map(|entry| entry.ok()) + .map(|entry| entry.path()) + .filter(|path| path.extension().is_some_and(|ext| ext == "json")) + .collect(); + files.sort(); + files + } + + #[tokio::test] + async fn sink_process_events_recovers_after_simulated_compaction() { + let nanos = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos(); + let base_path = std::env::temp_dir().join(format!("deltalake_sink_stale_log_{nanos}")); + let table_name = "recover_table"; + let table_path = base_path.join(table_name); + fs::create_dir_all(&table_path).expect("create table dir"); + + let sink = DeltaLakeSink::new( + base_path.clone(), + vec![DeltaTableConfig { + name: table_name.to_string(), + schema_evolution: Some(true), + }], + WriteConfig { + batch_size: 1000, + timeout_secs: 30, + }, + None, + ); + + for batch in 0..5 { + let events: Vec = (0..3) + .map(|i| create_test_event(table_name, i)) + .collect(); + sink.process_events(events) + .await + .expect("seed batch should write"); + let _ = batch; + } + + let delta_log_path = table_path.join("_delta_log"); + let json_files = delta_log_json_files(&delta_log_path); + assert!(json_files.len() >= 3); + let latest = json_files.last().expect("latest delta log json").clone(); + fs::remove_file(latest).expect("simulate compaction"); + + // Must not panic; stale-log recovery should allow the batch to be written. + sink.process_events(vec![create_test_event(table_name, 999)]) + .await + .expect("sink should recover after simulated compaction"); + + assert!(delta_log_json_files(&delta_log_path).len() >= 1); + let _ = fs::remove_dir_all(&base_path); + } } diff --git a/src/sinks/topsql_data_deltalake/processor.rs b/src/sinks/topsql_data_deltalake/processor.rs index b3004bc8..f60e03b0 100644 --- a/src/sinks/topsql_data_deltalake/processor.rs +++ b/src/sinks/topsql_data_deltalake/processor.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::path::PathBuf; use std::sync::Arc; +use std::time::Duration; use futures::{stream::BoxStream, StreamExt}; use tokio::sync::mpsc; @@ -8,7 +9,9 @@ use tokio::sync::Mutex; use vector_lib::event::{Event, LogEvent}; use vector_lib::sink::StreamSink; -use crate::common::deltalake_writer::{DeltaLakeWriter, DeltaTableConfig, WriteConfig}; +use crate::common::deltalake_writer::{ + is_stale_delta_log_error, DeltaLakeWriter, DeltaTableConfig, WriteConfig, +}; use crate::common::keyspace_cluster::{ path_contains_keyspace_route_segments, replace_keyspace_route_segments, route_resolution_retry_delay, KeyspaceRoute, PdKeyspaceResolver, @@ -401,24 +404,12 @@ impl TopSQLDeltaLakeSink { for (writer_key, mut events) in table_events { self.add_schema_info(&mut events, &writer_key.table_name); if let Err(e) = self.write_table_events(&writer_key, events).await { - let error_msg = e.to_string(); - if error_msg.contains("log segment") - || error_msg.contains("Invalid table version") - || error_msg.contains("not found") - || error_msg.contains("No such file or directory") - { - panic!( - "Delta Lake corruption detected for table {}: {}", - writer_key.table_name, error_msg - ); - } else { - error!( - "Failed to write events to table {} at {}: {}", - writer_key.table_name, - writer_key.table_path.display(), - e - ); - } + error!( + "Failed to write events to table {} at {}: {}", + writer_key.table_name, + writer_key.table_path.display(), + e + ); } } @@ -567,11 +558,33 @@ impl TopSQLDeltaLakeSink { } } - /// Write events to a specific table + /// Write events to a specific table, evicting and reopening the writer once on stale log errors. async fn write_table_events( &self, writer_key: &WriterKey, events: Vec, + ) -> Result<(), Box> { + match self.write_table_events_once(writer_key, &events).await { + Ok(()) => Ok(()), + Err(e) if is_stale_delta_log_error(&e.to_string()) => { + warn!( + "Stale Delta log for table {} at {}, evicting cached writer and retrying once: {}", + writer_key.table_name, + writer_key.table_path.display(), + e + ); + self.writers.lock().await.remove(writer_key); + tokio::time::sleep(Duration::from_millis(200)).await; + self.write_table_events_once(writer_key, &events).await + } + Err(e) => Err(e), + } + } + + async fn write_table_events_once( + &self, + writer_key: &WriterKey, + events: &[Event], ) -> Result<(), Box> { let mut writers = self.writers.lock().await; let writer = writers.entry(writer_key.clone()).or_insert_with(|| { @@ -594,7 +607,7 @@ impl TopSQLDeltaLakeSink { }); // Write events - writer.write_events(events).await?; + writer.write_events(events.to_vec()).await?; Ok(()) } diff --git a/src/sinks/topsql_meta_deltalake/processor.rs b/src/sinks/topsql_meta_deltalake/processor.rs index dff95265..10af7f1c 100644 --- a/src/sinks/topsql_meta_deltalake/processor.rs +++ b/src/sinks/topsql_meta_deltalake/processor.rs @@ -10,7 +10,9 @@ use tokio::sync::Mutex; use vector_lib::event::{Event, LogEvent}; use vector_lib::sink::StreamSink; -use crate::common::deltalake_writer::{DeltaLakeWriter, DeltaTableConfig, WriteConfig}; +use crate::common::deltalake_writer::{ + is_stale_delta_log_error, DeltaLakeWriter, DeltaTableConfig, WriteConfig, +}; use crate::common::keyspace_cluster::{ path_contains_keyspace_route_segments, replace_keyspace_route_segments, route_resolution_retry_delay, KeyspaceRoute, PdKeyspaceResolver, @@ -380,24 +382,12 @@ impl TopSQLDeltaLakeSink { for (writer_key, mut events) in table_events { self.add_schema_info(&writer_key.table_name, &mut events); if let Err(e) = self.write_table_events(&writer_key, events).await { - let error_msg = e.to_string(); - if error_msg.contains("log segment") - || error_msg.contains("Invalid table version") - || error_msg.contains("not found") - || error_msg.contains("No such file or directory") - { - panic!( - "Delta Lake corruption detected for table {}: {}", - writer_key.table_name, error_msg - ); - } else { - error!( - "Failed to write events to table {} at {}: {}", - writer_key.table_name, - writer_key.table_path.display(), - e - ); - } + error!( + "Failed to write events to table {} at {}: {}", + writer_key.table_name, + writer_key.table_path.display(), + e + ); } else if let Some(keys) = table_dedup_keys.remove(&writer_key) { committed_dedup_keys.extend(keys); } @@ -600,11 +590,33 @@ impl TopSQLDeltaLakeSink { ); } - /// Write events to a specific table + /// Write events to a specific table, evicting and reopening the writer once on stale log errors. async fn write_table_events( &self, writer_key: &WriterKey, events: Vec, + ) -> Result<(), Box> { + match self.write_table_events_once(writer_key, &events).await { + Ok(()) => Ok(()), + Err(e) if is_stale_delta_log_error(&e.to_string()) => { + warn!( + "Stale Delta log for table {} at {}, evicting cached writer and retrying once: {}", + writer_key.table_name, + writer_key.table_path.display(), + e + ); + self.writers.lock().await.remove(writer_key); + tokio::time::sleep(Duration::from_millis(200)).await; + self.write_table_events_once(writer_key, &events).await + } + Err(e) => Err(e), + } + } + + async fn write_table_events_once( + &self, + writer_key: &WriterKey, + events: &[Event], ) -> Result<(), Box> { // Get or create writer for this table let mut writers = self.writers.lock().await; @@ -628,7 +640,7 @@ impl TopSQLDeltaLakeSink { }); // Write events - writer.write_events(events).await?; + writer.write_events(events.to_vec()).await?; Ok(()) } diff --git a/tests/deltalake_stale_log_test.rs b/tests/deltalake_stale_log_test.rs new file mode 100644 index 00000000..e158ee70 --- /dev/null +++ b/tests/deltalake_stale_log_test.rs @@ -0,0 +1,147 @@ +//! Local Delta Lake test: simulate external compaction removing old _delta_log JSON +//! files and verify writes recover instead of failing permanently. + +#![allow(clippy::print_stdout)] + +use std::collections::BTreeMap; +use std::fs; +use std::path::{Path, PathBuf}; + +use vector_lib::event::{Event, LogEvent, ObjectMap}; + +use vector_extensions::sinks::deltalake::{DeltaLakeWriter, DeltaTableConfig, WriteConfig}; + +fn make_event(table_name: &str, index: i64) -> Event { + let mut log = LogEvent::from(BTreeMap::new()); + log.insert("_vector_table", table_name); + log.insert("_vector_source_table", "TEST_SOURCE"); + log.insert("_vector_source_schema", "test_schema"); + log.insert("_vector_instance", "test-instance"); + log.insert("_vector_timestamp", "2024-06-01T00:00:00Z"); + log.insert("id", index); + log.insert("value", format!("row-{index}")); + + let mut schema_meta = ObjectMap::new(); + schema_meta.insert("_partition_by".into(), vector_lib::event::Value::from("date")); + let mut id_meta = ObjectMap::new(); + id_meta.insert("mysql_type".into(), vector_lib::event::Value::from("bigint")); + schema_meta.insert("id".into(), vector_lib::event::Value::Object(id_meta)); + let mut value_meta = ObjectMap::new(); + value_meta.insert( + "mysql_type".into(), + vector_lib::event::Value::from("varchar(64)"), + ); + schema_meta.insert("value".into(), vector_lib::event::Value::Object(value_meta)); + log.insert("_schema_metadata", vector_lib::event::Value::Object(schema_meta)); + + Event::Log(log) +} + +fn delta_log_json_files(delta_log_path: &Path) -> Vec { + let mut files: Vec = fs::read_dir(delta_log_path) + .expect("read _delta_log") + .filter_map(|entry| entry.ok()) + .map(|entry| entry.path()) + .filter(|path| path.extension().is_some_and(|ext| ext == "json")) + .collect(); + files.sort(); + files +} + +/// Remove the latest commit log JSON file while keeping the contiguous history intact. +/// This mimics a concurrent compact/remove race where a reader still chases a log +/// segment that was already deleted, while the table remains valid at an earlier version. +fn simulate_external_compaction(delta_log_path: &Path) { + let json_files = delta_log_json_files(delta_log_path); + assert!( + json_files.len() >= 3, + "need at least 3 json log files before compaction simulation" + ); + + let stale_file = json_files.last().expect("latest delta log json"); + println!("Simulating compaction: removing {:?}", stale_file); + fs::remove_file(stale_file).expect("remove stale delta log json"); +} + +fn unique_table_dir(name: &str) -> PathBuf { + let nanos = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos(); + std::env::temp_dir().join(format!("{name}_{nanos}")) +} + +async fn write_batch(writer: &mut DeltaLakeWriter, table_name: &str, start: i64, count: i64) { + let events: Vec = (start..start + count) + .map(|i| make_event(table_name, i)) + .collect(); + writer + .write_events(events) + .await + .expect("seed write should succeed"); +} + +#[tokio::test] +async fn recover_write_after_simulated_delta_log_compaction() { + let table_path = unique_table_dir("deltalake_stale_log_recovery"); + fs::create_dir_all(&table_path).expect("create table dir"); + + let table_name = "metrics_table"; + let write_config = WriteConfig { + batch_size: 1000, + timeout_secs: 30, + }; + let table_config = DeltaTableConfig { + name: table_name.to_string(), + schema_evolution: Some(true), + }; + + let mut writer = DeltaLakeWriter::new( + table_path.clone(), + table_config.clone(), + write_config.clone(), + None, + ); + + // Build a multi-version table so _delta_log has several JSON commits. + for batch in 0..5 { + write_batch(&mut writer, table_name, batch * 10, 3).await; + } + + let delta_log_path = table_path.join("_delta_log"); + let json_before = delta_log_json_files(&delta_log_path); + println!("Delta log json files before compaction simulation: {}", json_before.len()); + assert!(json_before.len() >= 3, "expected multiple delta log commits"); + + simulate_external_compaction(&delta_log_path); + + let recovery_events = vec![make_event(table_name, 999)]; + match writer.write_events(recovery_events.clone()).await { + Ok(()) => {} + Err(error) if vector_extensions::common::deltalake_writer::is_stale_delta_log_error(&error.to_string()) => { + writer = DeltaLakeWriter::new( + table_path.clone(), + DeltaTableConfig { + name: table_name.to_string(), + schema_evolution: Some(true), + }, + write_config.clone(), + None, + ); + tokio::time::sleep(std::time::Duration::from_millis(200)).await; + writer + .write_events(recovery_events) + .await + .expect("write should recover after reopening table writer"); + } + Err(error) => panic!("unexpected write failure: {error}"), + } + + let json_after = delta_log_json_files(&delta_log_path); + assert!( + !json_after.is_empty(), + "table should remain writable after recovery" + ); + + let _ = fs::remove_dir_all(&table_path); +} From 4c68515ee49bef48542097838c16d767eb5590c1 Mon Sep 17 00:00:00 2001 From: "zhou.cai" Date: Mon, 20 Jul 2026 11:28:39 +0800 Subject: [PATCH 5/6] improve build dockerfile to use latest image --- .../aarch64-unknown-linux-gnu.dockerfile | 5 --- scripts/cross/bootstrap-ubuntu.sh | 29 ++++++----------- .../cross/x86_64-unknown-linux-gnu.dockerfile | 5 --- scripts/docker/Dockerfile.alpine | 31 +++++++++++++++++++ scripts/docker/Dockerfile.minimal | 22 +++++++++++++ 5 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 scripts/docker/Dockerfile.alpine create mode 100644 scripts/docker/Dockerfile.minimal diff --git a/scripts/cross/aarch64-unknown-linux-gnu.dockerfile b/scripts/cross/aarch64-unknown-linux-gnu.dockerfile index a3243b30..67e41c73 100644 --- a/scripts/cross/aarch64-unknown-linux-gnu.dockerfile +++ b/scripts/cross/aarch64-unknown-linux-gnu.dockerfile @@ -4,8 +4,3 @@ COPY bootstrap-ubuntu.sh . COPY install-protoc.sh . RUN ./bootstrap-ubuntu.sh RUN ./install-protoc.sh - -RUN apt-get update && \ - apt-get remove --assume-yes gcc-9 && \ - apt-get --assume-yes install clang && \ - rm -rf /var/lib/apt/lists/* diff --git a/scripts/cross/bootstrap-ubuntu.sh b/scripts/cross/bootstrap-ubuntu.sh index 802e8068..ac03c3e0 100755 --- a/scripts/cross/bootstrap-ubuntu.sh +++ b/scripts/cross/bootstrap-ubuntu.sh @@ -3,28 +3,17 @@ set -o errexit echo 'Acquire::Retries "5";' > /etc/apt/apt.conf.d/80-retries -apt-get update -apt-get upgrade -y - -apt-get install -y \ - apt-transport-https \ - gnupg \ - wget - -# we need LLVM >= 3.9 for onig_sys/bindgen - -cat <<-EOF > /etc/apt/sources.list.d/llvm.list -deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main -deb-src http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main -EOF - -wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - +export DEBIAN_FRONTEND=noninteractive apt-get update apt-get upgrade -y -# needed by onig_sys +# LLVM >= 3.9 is required by onig_sys/bindgen. Use distro packages from the +# cross-rs base image (Ubuntu 24.04) instead of the legacy xenial LLVM repo. apt-get install -y \ - libclang1-9 \ - llvm-9 \ - unzip + clang \ + curl \ + libclang-dev \ + unzip + +rm -rf /var/lib/apt/lists/* diff --git a/scripts/cross/x86_64-unknown-linux-gnu.dockerfile b/scripts/cross/x86_64-unknown-linux-gnu.dockerfile index a0bebb83..f5adc36a 100644 --- a/scripts/cross/x86_64-unknown-linux-gnu.dockerfile +++ b/scripts/cross/x86_64-unknown-linux-gnu.dockerfile @@ -4,8 +4,3 @@ COPY bootstrap-ubuntu.sh . COPY install-protoc.sh . RUN ./bootstrap-ubuntu.sh RUN ./install-protoc.sh - -RUN apt-get update && \ - apt-get remove --assume-yes gcc-9 && \ - apt-get --assume-yes install clang && \ - rm -rf /var/lib/apt/lists/* diff --git a/scripts/docker/Dockerfile.alpine b/scripts/docker/Dockerfile.alpine new file mode 100644 index 00000000..be2f5467 --- /dev/null +++ b/scripts/docker/Dockerfile.alpine @@ -0,0 +1,31 @@ +# Alpine-based Dockerfile for minimal image size +FROM alpine:3.19 as builder + +# Install build dependencies +RUN apk add --no-cache \ + ca-certificates \ + tzdata \ + curl \ + binutils \ + musl-dev + +# Final stage with minimal runtime dependencies +FROM alpine:3.19 + +# Install only runtime dependencies +RUN apk add --no-cache \ + ca-certificates \ + tzdata \ + && rm -rf /var/cache/apk/* + +ARG TARGETARCH +COPY vector-$TARGETARCH /usr/bin/vector +# COPY vector.toml /etc/vector/vector.toml + +ENV VECTOR_LOG="info" + +RUN ["chmod", "+x", "/usr/bin/vector"] +# Smoke test +RUN ["vector", "--version"] + +ENTRYPOINT ["/usr/bin/vector"] diff --git a/scripts/docker/Dockerfile.minimal b/scripts/docker/Dockerfile.minimal new file mode 100644 index 00000000..d9b2c7db --- /dev/null +++ b/scripts/docker/Dockerfile.minimal @@ -0,0 +1,22 @@ +# Minimal scratch-based Dockerfile for smallest possible image +FROM scratch + +# Copy CA certificates from a build stage +FROM alpine:3.19 as certs +RUN apk add --no-cache ca-certificates + +# Final minimal image +FROM scratch + +# Copy only what's needed +COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=certs /usr/share/ca-certificates /usr/share/ca-certificates + +ARG TARGETARCH +COPY vector-$TARGETARCH /vector + +# Use static binary for scratch compatibility +ENV VECTOR_LOG="info" +ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + +ENTRYPOINT ["/vector"] From 54332ca40a4fc1dfaf0aa5e82af9ea4880312626 Mon Sep 17 00:00:00 2001 From: "zhou.cai" Date: Thu, 23 Jul 2026 15:29:10 +0800 Subject: [PATCH 6/6] try to fix aws warning --- Cargo.lock | 111 ++++++++++++++++++++++++++++++++--------------------- Cargo.toml | 7 ++-- 2 files changed, 71 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 786665d0..152c51e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1201,7 +1201,7 @@ dependencies = [ "aws-sdk-ssooidc", "aws-sdk-sts", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1221,9 +1221,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.7" +version = "1.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a1290207254984cb7c05245111bc77958b92a3c9bb449598044b36341cce6" +checksum = "3cd362783681b15d136480ad555a099e82ecd8e2d10a841e14dfd0078d67fee3" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -1255,15 +1255,15 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.10" +version = "1.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c034a1bc1d70e16e7f4e4caf7e9f7693e4c9c24cd91cf17c2a0b21abaebc7c8b" +checksum = "7ce527fb7e53ba9626fc47824f25e256250556c40d8f81d27dd92aa38239d632" dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -1288,7 +1288,7 @@ dependencies = [ "aws-runtime", "aws-smithy-async", "aws-smithy-compression", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-query", "aws-smithy-runtime", @@ -1314,7 +1314,7 @@ dependencies = [ "aws-runtime", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1336,7 +1336,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1358,7 +1358,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1381,7 +1381,7 @@ dependencies = [ "aws-runtime", "aws-smithy-async", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1403,7 +1403,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1428,7 +1428,7 @@ dependencies = [ "aws-smithy-async", "aws-smithy-checksums", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1459,7 +1459,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1481,7 +1481,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-query", "aws-smithy-runtime", @@ -1504,7 +1504,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1526,7 +1526,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1548,7 +1548,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-runtime", "aws-smithy-runtime-api", @@ -1570,7 +1570,7 @@ dependencies = [ "aws-credential-types", "aws-runtime", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-json", "aws-smithy-query", "aws-smithy-runtime", @@ -1586,13 +1586,13 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.3.4" +version = "1.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084c34162187d39e3740cb635acd73c4e3a551a36146ad6fe8883c929c9f876c" +checksum = "efa49f3c607b92daae0c078d48a4571f599f966dce3caee5f1ea55c4d9073f99" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", - "aws-smithy-http", + "aws-smithy-http 0.63.3", "aws-smithy-runtime-api", "aws-smithy-types", "bytes 1.10.1", @@ -1609,9 +1609,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "1.2.5" +version = "1.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e190749ea56f8c42bf15dd76c65e14f8f765233e6df9b0506d9d934ebef867c" +checksum = "52eec3db979d18cb807fc1070961cc51d87d069abe9ab57917769687368a8c6c" dependencies = [ "futures-util", "pin-project-lite", @@ -1624,7 +1624,7 @@ version = "0.63.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dbef71cd3cf607deb5c407df52f7e589e6849b296874ee448977efbb6d0832b" dependencies = [ - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-types", "bytes 1.10.1", "crc-fast", @@ -1657,9 +1657,9 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.10" +version = "0.60.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604c7aec361252b8f1c871a7641d5e0ba3a7f5a586e51b66bc9510a5519594d9" +checksum = "35b9c7354a3b13c66f60fe4616d6d1969c9fd36b1b5333a5dfb3ee716b33c588" dependencies = [ "aws-smithy-types", "bytes 1.10.1", @@ -1668,9 +1668,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.62.3" +version = "0.62.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c4dacf2d38996cf729f55e7a762b30918229917eca115de45dfa8dfb97796c9" +checksum = "826141069295752372f8203c17f28e30c464d22899a43a0c9fd9c458d469c88b" dependencies = [ "aws-smithy-eventstream", "aws-smithy-runtime-api", @@ -1678,6 +1678,7 @@ dependencies = [ "bytes 1.10.1", "bytes-utils", "futures-core", + "futures-util", "http 0.2.12", "http 1.3.1", "http-body 0.4.6", @@ -1687,11 +1688,32 @@ dependencies = [ "tracing 0.1.41", ] +[[package]] +name = "aws-smithy-http" +version = "0.63.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630e67f2a31094ffa51b210ae030855cb8f3b7ee1329bdd8d085aaf61e8b97fc" +dependencies = [ + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes 1.10.1", + "bytes-utils", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing 0.1.41", +] + [[package]] name = "aws-smithy-http-client" -version = "1.1.2" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "734b4282fbb7372923ac339cc2222530f8180d9d4745e582de19a18cee409fd8" +checksum = "12fb0abf49ff0cab20fd31ac1215ed7ce0ea92286ba09e2854b42ba5cabe7525" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -1728,9 +1750,9 @@ dependencies = [ [[package]] name = "aws-smithy-observability" -version = "0.1.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9364d5989ac4dd918e5cc4c4bdcc61c9be17dcd2586ea7f69e348fc7c6cab393" +checksum = "c0a46543fbc94621080b3cf553eb4cbbdc41dd9780a30c4756400f0139440a1d" dependencies = [ "aws-smithy-runtime-api", ] @@ -1747,12 +1769,12 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.9.2" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa63ad37685ceb7762fa4d73d06f1d5493feb88e3f27259b9ed277f4c01b185" +checksum = "f3df87c14f0127a0d77eb261c3bc45d5b4833e2a1f63583ebfb728e4852134ee" dependencies = [ "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.63.3", "aws-smithy-http-client", "aws-smithy-observability", "aws-smithy-runtime-api", @@ -1763,6 +1785,7 @@ dependencies = [ "http 1.3.1", "http-body 0.4.6", "http-body 1.0.1", + "http-body-util", "pin-project-lite", "pin-utils", "tokio", @@ -1771,9 +1794,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.9.0" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07f5e0fc8a6b3f2303f331b94504bbf754d85488f402d6f1dd7a6080f99afe56" +checksum = "49952c52f7eebb72ce2a754d3866cc0f87b97d2a46146b79f80f3a93fb2b3716" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -1788,9 +1811,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.3.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d498595448e43de7f4296b7b7a18a8a02c61ec9349128c80a368f7c3b4ab11a8" +checksum = "3b3a26048eeab0ddeba4b4f9d51654c79af8c3b32357dc5f336cee85ab331c33" dependencies = [ "base64-simd", "bytes 1.10.1", @@ -1823,9 +1846,9 @@ dependencies = [ [[package]] name = "aws-types" -version = "1.3.8" +version = "1.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b069d19bf01e46298eaedd7c6f283fe565a59263e53eebec945f3e6398f42390" +checksum = "1d980627d2dd7bfc32a3c025685a033eeab8d365cc840c631ef59d1b8f428164" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -6798,7 +6821,6 @@ dependencies = [ "hyper 0.14.32", "log", "rustls 0.21.12", - "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", ] @@ -13682,7 +13704,7 @@ dependencies = [ "aws-sdk-sts", "aws-sigv4", "aws-smithy-async", - "aws-smithy-http", + "aws-smithy-http 0.62.6", "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", @@ -14049,6 +14071,7 @@ dependencies = [ "async-recursion", "async-trait", "aws-config", + "aws-runtime", "aws-sdk-s3", "aws-smithy-types", "azure_storage_blobs", diff --git a/Cargo.toml b/Cargo.toml index 7eada567..87425f57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,9 +22,10 @@ async-compression = { git = "https://github.com/nolouch/async-compression", rev async-recursion = "1.1.1" async-trait = { version = "0.1.88", default-features = false } arrow = { version = "56.2.0" } -aws-config = { version = "1.0" } -aws-sdk-s3 = { version = "1.82.0", default-features = false, features = ["behavior-version-latest"] } -aws-smithy-types = { version = "1.3.2", default-features = false } +aws-config = { version = "1.8.6" } +aws-runtime = { version = "1.5.16" } +aws-sdk-s3 = { version = "1.103.0", default-features = false, features = ["behavior-version-latest"] } +aws-smithy-types = { version = "1.3.4", default-features = false } azure_storage_blobs = { version = "0.17.0", default-features = false, features = ["enable_reqwest"] } base64 = { version = "0.22.1", default-features = false } bytes = { version = "1.10.1", default-features = false, features = ["serde"] }