Skip to main content

ReshardGuard

Struct ReshardGuard 

Source
pub struct ReshardGuard<'a> { /* private fields */ }
Expand description

Holds a hash slot in the MIGRATING/IMPORTING state so tests can deterministically observe -ASK redirects, then finishes or reverts the migration.

Construct with ReshardGuard::start. While the guard is alive, slot is MIGRATING on the source node and IMPORTING on the target node – the window in which Redis Cluster returns -ASK for keys in that slot that live on the source but haven’t been moved yet, and clients that address the target directly get -TRYAGAIN/MOVED depending on the key.

Call ReshardGuard::migrate_keys any number of times to move keys without changing ownership (this is what lets a test provoke -ASK deterministically: move some keys, leave others, then issue commands against them). Call ReshardGuard::complete to migrate any remaining keys and hand the slot to the target, or ReshardGuard::abort to hand it back to the source.

If the guard is dropped without calling either, it makes a best-effort synchronous attempt to reset the slot to STABLE on both nodes so the cluster doesn’t get stuck straddling the migration.

§Example

use redis_server_wrapper::{RedisCluster, chaos::ReshardGuard};

let cluster = RedisCluster::builder()
    .masters(2)
    .base_port(7200)
    .start()
    .await
    .unwrap();

let guard = ReshardGuard::start(&cluster, 0, cluster.node(0), cluster.node(1))
    .await
    .unwrap();

// ... issue commands against a key in slot 0 and assert on -ASK ...

guard.complete().await.unwrap();

Implementations§

Source§

impl<'a> ReshardGuard<'a>

Source

pub async fn start( cluster: &'a RedisClusterHandle, slot: u16, from: &'a RedisServerHandle, to: &'a RedisServerHandle, ) -> Result<ReshardGuard<'a>>

Put slot into MIGRATING on from and IMPORTING on to.

No keys are moved yet – this only opens the migration window.

Source

pub async fn migrate_keys(&self) -> Result<usize>

Migrate every key currently in the slot from from to to, without changing slot ownership.

Safe to call more than once (e.g. to sweep up keys written after a previous call). Returns the number of keys moved by this call.

Source

pub async fn complete(self) -> Result<usize>

Finish the migration: sweep up any remaining keys, then reassign slot to the target node on every master.

Source

pub async fn abort(self) -> Result<()>

Abort the migration: reset slot back to STABLE on both nodes, leaving ownership with the source.

Any keys already moved to the target by ReshardGuard::migrate_keys stay there – MIGRATE does not roll back, so a partial abort can leave a few keys reachable only via the target until the next reshard picks them up.

Trait Implementations§

Source§

impl Drop for ReshardGuard<'_>

Available on crate feature tokio only.
Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for ReshardGuard<'a>

§

impl<'a> RefUnwindSafe for ReshardGuard<'a>

§

impl<'a> Send for ReshardGuard<'a>

§

impl<'a> Sync for ReshardGuard<'a>

§

impl<'a> Unpin for ReshardGuard<'a>

§

impl<'a> UnsafeUnpin for ReshardGuard<'a>

§

impl<'a> UnwindSafe for ReshardGuard<'a>

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<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, 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, 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.