Enum ExaImport

Source
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, the connection would just be re-attempted over and over since we’d still be sending no data.

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.

See https://github.com/exasol/websocket-api/issues/33 for more details.

Variants§

§

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

👎Deprecated: will be made private

Setup state of the worker. This typically means waiting on the TLS handshake.

This approach is needed because Exasol will issue connections sequentially and thus perform TLS handshakes the same way.

Therefore we accommodate the worker state until the query gets executed and data gets sent through the workers, which happens within consumer code.

§

Writing(ExaImportWriter)

👎Deprecated: will be made private

The worker is fully connected and ready for I/O.

Trait Implementations§

Source§

impl AsyncWrite for ExaImport

Source§

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

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

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

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<Result<()>>

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

Auto Trait Implementations§

Blanket Implementations§

Source§

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

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<W> AsyncWriteExt for W
where 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 T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where 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 T
where 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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

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

Source§

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 T
where U: TryFrom<T>,

Source§

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.
Source§

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

Source§

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
Source§

impl<T> ErasedDestructor for T
where T: 'static,