Skip to content
This repository was archived by the owner on Oct 18, 2023. It is now read-only.

write proxy: expire old write delegation streams #723

Merged
merged 2 commits into from
Oct 3, 2023

Conversation

psarna
Copy link
Contributor

@psarna psarna commented Oct 3, 2023

Right now we don't have a mechanism for expiring write delegation streams that disconnected, but without sending a valid Disconnect messages. That unfortunately also means that we leak libSQL connections, which are kept in-memory indefinitely. That leaks memory as well as disk space, because connections also keep temporary tables in place.

FIXME: we also need to keep information about expired streams for longer, in case a client tries to send a late message. Such a message should be rejected in order to avoid running it outside of transaction context.

Tested locally with grpcurl by sending counterfeit write proxy messages that start a transaction and then disconnect:

grpcurl -H 'x-proxy-authorization: full_access' -import-path ./proto -proto proxy.proto -d '{"client_id": "'$(uuidgen)'", "pgm": {"steps": [{"query": {"stmt": "begin immediate", "positional": []}}]}}' -plaintext localhost:5001 proxy.Proxy.Execute

@psarna psarna requested review from MarinPostma and penberg October 3, 2023 10:17
Comment on lines 458 to 463
let limit = std::time::Duration::from_secs(30);
for (client_id, db) in clients.iter() {
if db.idle_time() > limit {
to_remove.push(*client_id);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment on lines 293 to 298
impl<DB> TrackedConnection<DB> {
pub fn idle_time(&self) -> Duration {
let now = now_millis();
let atime = self.atime.load(Ordering::Relaxed);
Duration::from_millis(now - atime)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure this is safe. SystemTime is not monotonic, so there is a chance that now is in the past compared to time, and now - atime may overflow

Copy link
Contributor

Choose a reason for hiding this comment

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

Overall, since this is a temp fix, I would prefer that we work with Mutex<tokio::time::Instant>. The mutex should be completely uncontended, so it should be very cheap with parking lot mutex

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If our only concern here is overflow, I'd rather just do saturating_sub. I chose system time because it's the easiest to operate on timestamps, and since there's no AtomicInstant, I preferred that over a mutex, since it makes the code way simpler, and I'd rather keep temporary fixes dead simple.

Right now we don't have a mechanism for expiring write delegation
streams that disconnected, but without sending a valid Disconnect
messages. That unfortunately also means that we leak libSQL connections,
which are kept in-memory indefinitely. That leaks memory as well as disk
space, because connections also keep temporary tables in place.

FIXME: we also need to keep information about expired streams for longer,
in case a client tries to send a late message. Such a message should be
rejected in order to avoid running it outside of transaction context.
@psarna psarna added this pull request to the merge queue Oct 3, 2023
@psarna psarna removed this pull request from the merge queue due to a manual request Oct 3, 2023
@psarna psarna merged commit 82b839d into libsql:main Oct 3, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants