pub enum ExaImport {
    Setup(BoxFuture<'static, Result<ExaSocket>>, usize, bool),
    Writing(ExaImportWriter),
}
Expand description

An ETL IMPORT worker.

The type implements AsyncWrite and is Send and Sync so it can be (almost) freely used for any data pipeline.

The only caveat is that you MUST call futures_util::AsyncWriteExt::close on each worker to finalize the import. Otherwise, Exasol keeps on expecting data.

Atomicity

IMPORT jobs are not atomic by themselves. If an error occurs during the data ingestion, some of the data might be already sent and written in the database. However, since IMPORT is fundamentally just a query, it can be transactional. Therefore, beginning a transaction and passing that to the ImportBuilder::build method will result in the import job needing to be explicitly committed:

use std::env;

use sqlx_exasol::{etl::*, *};

let pool = ExaPool::connect(&env::var("DATABASE_URL").unwrap()).await?;
let mut con = pool.acquire().await?;
let mut tx = con.begin().await?;

let (query_fut, writers) = ImportBuilder::new("SOME_TABLE").build(&mut *tx).await?;

// concurrently use the writers and await the query future

tx.commit().await?;

IMPORTANT

In multi-node environments closing a writer without writing any data to it can, and most likely will, cause issues; Exasol does not immediately start reading data from all workers but rather seems to connect to them sequentially after each of them provides some data.

From what I could gather from the logs, providing no data (although the request is responded to gracefully) makes Exasol retry the connection. With these workers being implemented as one-shot HTTP servers, there’s nothing to connect to anymore. Even if it were, it’s possible the connection would just be re-attempted over and over since we’d still be sending no data (I did not test this, though).

Since not using one or more import workers seems to be treated as an error on Exasol’s side, it’s best not to create excess writers that you don’t plan on using to avoid such issues.

Variants§

§

Setup(BoxFuture<'static, Result<ExaSocket>>, usize, bool)

§

Writing(ExaImportWriter)

Trait Implementations§

source§

impl AsyncWrite for ExaImport

source§

fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8] ) -> Poll<IoResult<usize>>

Attempt to write bytes from buf into the object. Read more
source§

fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<IoResult<()>>

Attempt to flush the object, ensuring that any buffered data reach their destination. Read more
source§

fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<IoResult<()>>

Attempt to close the object. Read more
source§

fn poll_write_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>] ) -> Poll<Result<usize, Error>>

Attempt to write bytes from bufs into the object using vectored IO operations. Read more
source§

impl Debug for ExaImport

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'pin> Unpin for ExaImportwhere __ExaImport<'pin>: Unpin,

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<W> AsyncWriteExt for Wwhere W: AsyncWrite + ?Sized,

source§

fn flush(&mut self) -> Flush<'_, Self>where Self: Unpin,

Creates a future which will entirely flush this AsyncWrite. Read more
source§

fn close(&mut self) -> Close<'_, Self>where Self: Unpin,

Creates a future which will entirely close this AsyncWrite.
source§

fn write<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self>where Self: Unpin,

Creates a future which will write bytes from buf into the object. Read more
source§

fn write_vectored<'a>( &'a mut self, bufs: &'a [IoSlice<'a>] ) -> WriteVectored<'a, Self>where Self: Unpin,

Creates a future which will write bytes from bufs into the object using vectored IO operations. Read more
source§

fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self>where Self: Unpin,

Write data into this object. Read more
source§

fn into_sink<Item>(self) -> IntoSink<Self, Item>where Item: AsRef<[u8]>, Self: Sized,

Allow using an AsyncWrite as a Sink<Item: AsRef<[u8]>>. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for Twhere V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more