Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrap cluster connection management in object. #42

Merged
merged 1 commit into from
Sep 13, 2023
Merged

Conversation

nihohit
Copy link

@nihohit nihohit commented Sep 10, 2023

Added connections_manager, a single object that handles addition, removal, and fetching of connections. This will allow us to easily modify behavior, for example, by adding round-robin read from replica.

connections.insert(addr, async { conn }.boxed().shared());
&mut *connections_container,
|connections_container, identifier| async move {
let addr_option = connections_container.address_for_identifier(&identifier);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

address_for_identifier should always return the address, regardless if it's found in the current connection map

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nihohit what about this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you got a whole commit, just for one comment!

Some(conn.clone())
}

pub(crate) fn connection_for_address(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would this function work if the identifier would be something different from the address?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean - or we'll need another map to save the addresses to their identifiers (then we also need to have a hash lookup which this solution should save), or we'll have the address already saved with the identifier - then we don't need to use the address at all. Or did you think about something else?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it depends on what the identifier is. for example, the identifier might be usize, and we'll have something like

struct Identifier(usize);

struct connections_manager {
connections: Vec<Option<C>>,
slot_map: BTree<usize, usize>, // the typing here is more complex, but the gist is - slot to index
addresses_map: HahsMap<String, usize>
}

then each identifier just goes into self.connections[*identifier], and saves us a hash lookup on the most common scenario - slot to connection, and on somewhat common scenario - retry to same node.

redis/src/cluster_async/connections_container.rs Outdated Show resolved Hide resolved
redis/src/cluster_async/mod.rs Show resolved Hide resolved
redis/src/cluster_async/mod.rs Outdated Show resolved Hide resolved
redis/src/cluster_async/connections_container.rs Outdated Show resolved Hide resolved
identifier
}

pub(crate) fn remove_connection(&mut self, identifier: &Identifier) -> Option<Connection> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, if we remove the connection only from the connection map, but the node's address is still present in the slot map, and we have a command that routes to a slot that points to this node address.
So we'll try to get the connection from the address and find that we don't have it in. So we'll try to create a new connection to this node, and if it fails we will send the command to a random node, even though we already decided to remove this connection in the refresh_connections function. not for this PR but we need to understand how to handle changes only in the connection map and when and how it should trigger a slots refreshment

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

once you have an identifier, a missing connection always means that a disconnect happened. That's one of the benefits of using strong typing - identifiers are only creatable by the connection_manager.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently it isn't true - we're searching for a connection based on its address, so a missing connection might say a disconnect happened or it's a new node. Am I wrong?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, the API says that you search for a connection based on an identifier. The user doesn't know that an identifier contains the address, and in future refactors, identifiers might not contain these addresses.
Of course, there's another problematic scenario - what happens if you have an existing identifier from an old container, but the connections container was replaced? The new container might not contain the address.

@nihohit
Copy link
Author

nihohit commented Sep 12, 2023

@barshaul round

Added connections_manager, a single object that handles addition,
removal, and fetching of connections. This will allow us to easily
modify behavior, for example, by adding round-robin read from replica.
@nihohit nihohit merged commit 37a627c into main Sep 13, 2023
10 checks passed
@nihohit nihohit deleted the connection-container branch September 13, 2023 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants