Avoid connection-per-RPC-call again by caching connections
authorMatt Corallo <git@bluematt.me>
Thu, 30 Mar 2023 18:51:56 +0000 (18:51 +0000)
committerMatt Corallo <git@bluematt.me>
Thu, 30 Mar 2023 22:28:26 +0000 (22:28 +0000)
In general, only one request will be in flight at a time in
`lightning-block-sync`. Ideally we'd only have one connection, but
without using the `futures` mutex type.

Here we solve this narrowly for the one-request-at-a-time case by
caching the connection and takeing the connection out of the cache
while we work on it.

lightning-block-sync/src/rest.rs
lightning-block-sync/src/rpc.rs

index c2926b7a0f766fdc975614735f025d80c05e5e9f..4300893013c06d7a3ee81c715b256066f4d28333 100644 (file)
@@ -9,10 +9,12 @@ use bitcoin::hashes::hex::ToHex;
 
 use std::convert::TryFrom;
 use std::convert::TryInto;
+use std::sync::Mutex;
 
 /// A simple REST client for requesting resources using HTTP `GET`.
 pub struct RestClient {
        endpoint: HttpEndpoint,
+       client: Mutex<Option<HttpClient>>,
 }
 
 impl RestClient {
@@ -20,7 +22,7 @@ impl RestClient {
        ///
        /// The endpoint should contain the REST path component (e.g., http://127.0.0.1:8332/rest).
        pub fn new(endpoint: HttpEndpoint) -> std::io::Result<Self> {
-               Ok(Self { endpoint })
+               Ok(Self { endpoint, client: Mutex::new(None) })
        }
 
        /// Requests a resource encoded in `F` format and interpreted as type `T`.
@@ -28,8 +30,11 @@ impl RestClient {
        where F: TryFrom<Vec<u8>, Error = std::io::Error> + TryInto<T, Error = std::io::Error> {
                let host = format!("{}:{}", self.endpoint.host(), self.endpoint.port());
                let uri = format!("{}/{}", self.endpoint.path().trim_end_matches("/"), resource_path);
-               let mut client = HttpClient::connect(&self.endpoint)?;
-               client.get::<F>(&uri, &host).await?.try_into()
+               let mut client = if let Some(client) = self.client.lock().unwrap().take() { client }
+                       else { HttpClient::connect(&self.endpoint)? };
+               let res = client.get::<F>(&uri, &host).await?.try_into();
+               *self.client.lock().unwrap() = Some(client);
+               res
        }
 }
 
index 521d94f3d1441a42e07498513c6aadde1a8a1e1c..4c4706cb1cd584e201fe1464d20abe5015dbe7bc 100644 (file)
@@ -7,6 +7,8 @@ use crate::http::{HttpClient, HttpEndpoint, HttpError, JsonResponse};
 use bitcoin::hash_types::BlockHash;
 use bitcoin::hashes::hex::ToHex;
 
+use std::sync::Mutex;
+
 use serde_json;
 
 use std::convert::TryFrom;
@@ -39,6 +41,7 @@ impl Error for RpcError {}
 pub struct RpcClient {
        basic_auth: String,
        endpoint: HttpEndpoint,
+       client: Mutex<Option<HttpClient>>,
        id: AtomicUsize,
 }
 
@@ -50,6 +53,7 @@ impl RpcClient {
                Ok(Self {
                        basic_auth: "Basic ".to_string() + credentials,
                        endpoint,
+                       client: Mutex::new(None),
                        id: AtomicUsize::new(0),
                })
        }
@@ -68,8 +72,12 @@ impl RpcClient {
                        "id": &self.id.fetch_add(1, Ordering::AcqRel).to_string()
                });
 
-               let mut client = HttpClient::connect(&self.endpoint)?;
-               let mut response = match client.post::<JsonResponse>(&uri, &host, &self.basic_auth, content).await {
+               let mut client = if let Some(client) = self.client.lock().unwrap().take() { client }
+                       else { HttpClient::connect(&self.endpoint)? };
+               let http_response = client.post::<JsonResponse>(&uri, &host, &self.basic_auth, content).await;
+               *self.client.lock().unwrap() = Some(client);
+
+               let mut response = match http_response {
                        Ok(JsonResponse(response)) => response,
                        Err(e) if e.kind() == std::io::ErrorKind::Other => {
                                match e.get_ref().unwrap().downcast_ref::<HttpError>() {