risingwave_stream/executor/iceberg_with_pk_index/
writer_impl.rs1use iceberg::table::Table;
16use iceberg::writer::PositionDeleteInput;
17use risingwave_common::array::DataChunk;
18use risingwave_connector::sink::SinkWriterParam;
19use risingwave_connector::sink::iceberg::{IcebergConfig, IcebergSinkWriterInner};
20use risingwave_pb::connector_service::SinkMetadata;
21use risingwave_pb::id::SinkId;
22
23use super::writer::IcebergWriter;
24use crate::executor::{StreamExecutorError, StreamExecutorResult};
25
26pub struct IcebergWriterImpl {
27 inner: IcebergSinkWriterInner,
28 sink_id: SinkId,
29}
30
31impl IcebergWriterImpl {
32 pub fn build(
33 config: &IcebergConfig,
34 table: Table,
35 writer_param: &SinkWriterParam,
36 ) -> StreamExecutorResult<Self> {
37 let sink_id = writer_param.sink_id;
38 let inner = IcebergSinkWriterInner::build_append_only(config, table, writer_param)
39 .map_err(|e| StreamExecutorError::sink_error(e, sink_id))?;
40
41 Ok(Self { inner, sink_id })
42 }
43}
44
45#[async_trait::async_trait]
46impl IcebergWriter for IcebergWriterImpl {
47 async fn write_chunk(
48 &mut self,
49 chunk: DataChunk,
50 ) -> StreamExecutorResult<Vec<PositionDeleteInput>> {
51 let positions = self
52 .inner
53 .write_batch_with_position(chunk.into())
54 .await
55 .map_err(|e| StreamExecutorError::sink_error(e, self.sink_id))?;
56 Ok(positions)
57 }
58
59 async fn flush(&mut self) -> StreamExecutorResult<Option<SinkMetadata>> {
60 let Some(data_files) = self
61 .inner
62 .close()
63 .await
64 .map_err(|e| StreamExecutorError::sink_error(e, self.sink_id))?
65 else {
66 return Ok(None);
67 };
68 if data_files.is_empty() {
69 return Ok(None);
70 }
71
72 let metadata = self
73 .inner
74 .generate_commit_metadata(data_files)
75 .map_err(|e| StreamExecutorError::sink_error(e, self.sink_id))?;
76
77 Ok(Some(metadata))
78 }
79}