pub struct XminReader<'a> { /* private fields */ }Expand description
Reads changed rows from a PostgreSQL table using xmin-based change detection.
PostgreSQL’s xmin system column contains the transaction ID that last modified
each row. By tracking the maximum xmin seen, we can query for only rows that
have been modified since the last sync.
Warning: xmin wraps around at 2^32 transactions. Use detect_wraparound()
to check for this condition and trigger a full table sync when detected.
Implementations§
Source§impl<'a> XminReader<'a>
impl<'a> XminReader<'a>
Sourcepub fn new(client: &'a Client) -> Self
pub fn new(client: &'a Client) -> Self
Create a new XminReader for the given PostgreSQL client connection.
Sourcepub async fn get_current_xmin(&self) -> Result<u32>
pub async fn get_current_xmin(&self) -> Result<u32>
Get the current transaction ID (xmin snapshot) from the database.
This should be called at the start of a sync to establish the high-water mark.
Sourcepub async fn read_changes(
&self,
schema: &str,
table: &str,
columns: &[String],
since_xmin: u32,
) -> Result<(Vec<Row>, u32)>
pub async fn read_changes( &self, schema: &str, table: &str, columns: &[String], since_xmin: u32, ) -> Result<(Vec<Row>, u32)>
Read all rows from a table that have xmin greater than the given value.
§Arguments
schema- The schema name (e.g., “public”)table- The table namecolumns- Column names to select (pass empty slice to select all)since_xmin- Only return rows with xmin > this value (0 = all rows)
§Returns
A tuple of (rows, max_xmin) where max_xmin is the highest xmin seen in the result set.
Sourcepub async fn read_changes_batched(
&self,
schema: &str,
table: &str,
columns: &[String],
since_xmin: u32,
batch_size: usize,
) -> Result<BatchReader>
pub async fn read_changes_batched( &self, schema: &str, table: &str, columns: &[String], since_xmin: u32, batch_size: usize, ) -> Result<BatchReader>
Read changes in batches to handle large tables efficiently.
§Arguments
schema- The schema nametable- The table namecolumns- Column names to selectsince_xmin- Only return rows with xmin > this valuebatch_size- Maximum rows per batch
§Returns
An iterator-like struct that yields batches of rows.
Sourcepub async fn fetch_batch(
&self,
batch_reader: &mut BatchReader,
) -> Result<Option<(Vec<Row>, u32)>>
pub async fn fetch_batch( &self, batch_reader: &mut BatchReader, ) -> Result<Option<(Vec<Row>, u32)>>
Execute a batched read query and return the next batch.
Uses (xmin, ctid) as the pagination key to correctly handle cases where many rows share the same xmin (e.g., bulk inserts in a single transaction). Without ctid tie-breaking, rows with duplicate xmin values would be skipped.
Sourcepub async fn estimate_changes(
&self,
schema: &str,
table: &str,
since_xmin: u32,
) -> Result<i64>
pub async fn estimate_changes( &self, schema: &str, table: &str, since_xmin: u32, ) -> Result<i64>
Get the estimated row count for changes since a given xmin.
This uses EXPLAIN to estimate without actually scanning the table.
Sourcepub async fn list_tables(&self, schema: &str) -> Result<Vec<String>>
pub async fn list_tables(&self, schema: &str) -> Result<Vec<String>>
Get list of all tables in a schema.
Sourcepub async fn get_columns(
&self,
schema: &str,
table: &str,
) -> Result<Vec<ColumnInfo>>
pub async fn get_columns( &self, schema: &str, table: &str, ) -> Result<Vec<ColumnInfo>>
Get column information for a table.
Sourcepub async fn get_primary_key(
&self,
schema: &str,
table: &str,
) -> Result<Vec<String>>
pub async fn get_primary_key( &self, schema: &str, table: &str, ) -> Result<Vec<String>>
Get primary key columns for a table.
Sourcepub async fn read_all_rows(
&self,
schema: &str,
table: &str,
columns: &[String],
) -> Result<(Vec<Row>, u32)>
pub async fn read_all_rows( &self, schema: &str, table: &str, columns: &[String], ) -> Result<(Vec<Row>, u32)>
Read ALL rows from a table (full sync).
This is used when xmin wraparound is detected and we need to resync the entire table to ensure data consistency.
§Arguments
schema- The schema name (e.g., “public”)table- The table namecolumns- Column names to select (pass empty slice to select all)
§Returns
A tuple of (rows, max_xmin) where max_xmin is the highest xmin seen.
Sourcepub async fn read_changes_with_wraparound_check(
&self,
schema: &str,
table: &str,
columns: &[String],
since_xmin: u32,
) -> Result<(Vec<Row>, u32, bool)>
pub async fn read_changes_with_wraparound_check( &self, schema: &str, table: &str, columns: &[String], since_xmin: u32, ) -> Result<(Vec<Row>, u32, bool)>
Check for wraparound and read changes accordingly.
This is the recommended method for reading changes as it automatically handles wraparound detection and triggers full table sync when needed.
§Arguments
schema- The schema nametable- The table namecolumns- Column names to selectsince_xmin- The last synced xmin value
§Returns
A tuple of (rows, max_xmin, was_full_sync) where was_full_sync indicates if a full table sync was performed due to wraparound.
Auto Trait Implementations§
impl<'a> Freeze for XminReader<'a>
impl<'a> !RefUnwindSafe for XminReader<'a>
impl<'a> Send for XminReader<'a>
impl<'a> Sync for XminReader<'a>
impl<'a> Unpin for XminReader<'a>
impl<'a> !UnwindSafe for XminReader<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<Choices> CoproductSubsetter<CNil, HNil> for Choices
impl<Choices> CoproductSubsetter<CNil, HNil> for Choices
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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 moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.