Skip to content

Commit d161f18

Browse files
committed
progress
1 parent 3c34a95 commit d161f18

7 files changed

Lines changed: 78 additions & 121 deletions

File tree

crates/pgt_workspace/src/settings.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ use tracing::trace;
1212

1313
use ignore::gitignore::{Gitignore, GitignoreBuilder};
1414
use pgt_configuration::{
15+
ConfigurationDiagnostic, LinterConfiguration, PartialConfiguration,
1516
database::PartialDatabaseConfiguration,
1617
diagnostics::InvalidIgnorePattern,
1718
files::FilesConfiguration,
1819
migrations::{MigrationsConfiguration, PartialMigrationsConfiguration},
19-
ConfigurationDiagnostic, LinterConfiguration, PartialConfiguration,
2020
};
2121
use pgt_fs::PgTPath;
2222

2323
use crate::{
24+
WorkspaceError,
2425
matcher::Matcher,
2526
workspace::{ProjectKey, WorkspaceData},
26-
WorkspaceError,
2727
};
2828

2929
#[derive(Debug, Default)]
@@ -133,8 +133,7 @@ impl WorkspaceSettings {
133133
for (key, path_to_settings) in iter {
134134
trace!(
135135
"Workspace path {:?}, file path {:?}",
136-
path_to_settings.path,
137-
path
136+
path_to_settings.path, path
138137
);
139138
trace!("Iter key: {:?}", key);
140139
if key == self.current_project {

crates/pgt_workspace/src/workspace.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,24 @@ use pgt_configuration::{PartialConfiguration, RuleSelector};
66
use pgt_fs::PgTPath;
77
use pgt_text_size::TextRange;
88
use serde::{Deserialize, Serialize};
9-
use slotmap::{new_key_type, DenseSlotMap};
9+
use slotmap::{DenseSlotMap, new_key_type};
1010

1111
use crate::{
12+
WorkspaceError,
1213
features::{
1314
code_actions::{
1415
CodeActionsParams, CodeActionsResult, ExecuteStatementParams, ExecuteStatementResult,
1516
},
1617
completions::{CompletionsResult, GetCompletionsParams},
1718
diagnostics::{PullDiagnosticsParams, PullDiagnosticsResult},
1819
},
19-
WorkspaceError,
2020
};
2121

2222
mod client;
2323
mod server;
2424

25-
pub(crate) use server::parsed_document::*;
2625
pub use server::StatementId;
26+
pub(crate) use server::parsed_document::*;
2727

2828
#[derive(Debug, serde::Serialize, serde::Deserialize)]
2929
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]

crates/pgt_workspace/src/workspace/client.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
use crate::workspace::ServerInfo;
22
use crate::{TransportError, Workspace, WorkspaceError};
3-
use serde::{de::DeserializeOwned, Deserialize, Serialize};
3+
use serde::{Deserialize, Serialize, de::DeserializeOwned};
44
use serde_json::json;
55
use std::{
66
panic::RefUnwindSafe,
77
sync::atomic::{AtomicU64, Ordering},
88
};
99

10-
use super::{CloseFileParams, GetFileContentParams, IsPathIgnoredParams, OpenFileParams};
10+
use super::{
11+
CloseFileParams, GetFileContentParams, IsPathIgnoredParams, OpenFileParams, ProjectKey,
12+
RegisterProjectFolderParams, UnregisterProjectFolderParams,
13+
};
1114

1215
pub struct WorkspaceClient<T> {
1316
transport: T,

crates/pgt_workspace/src/workspace/server.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ use async_helper::run_async;
1010
use connection_manager::ConnectionManager;
1111
use dashmap::DashMap;
1212
use document::Document;
13-
use futures::{stream, StreamExt};
13+
use futures::{StreamExt, stream};
1414
use parsed_document::{
1515
AsyncDiagnosticsMapper, CursorPositionFilter, DefaultMapper, ExecuteStatementMapper,
1616
ParsedDocument, SyncDiagnosticsMapper,
1717
};
1818
use pgt_analyse::{AnalyserOptions, AnalysisFilter};
1919
use pgt_analyser::{Analyser, AnalyserConfig, AnalyserContext};
2020
use pgt_diagnostics::{
21-
serde::Diagnostic as SDiagnostic, Diagnostic, DiagnosticExt, Error, Severity,
21+
Diagnostic, DiagnosticExt, Error, Severity, serde::Diagnostic as SDiagnostic,
2222
};
2323
use pgt_fs::{ConfigName, PgTPath};
2424
use pgt_typecheck::{IdentifierType, TypecheckParams, TypedIdentifier};
@@ -27,20 +27,17 @@ use sqlx::{Executor, PgPool};
2727
use tracing::{debug, info};
2828

2929
use crate::{
30+
WorkspaceError,
3031
configuration::to_analyser_rules,
3132
features::{
3233
code_actions::{
3334
self, CodeAction, CodeActionKind, CodeActionsResult, CommandAction,
3435
CommandActionCategory, ExecuteStatementParams, ExecuteStatementResult,
3536
},
36-
completions::{get_statement_for_completions, CompletionsResult, GetCompletionsParams},
37+
completions::{CompletionsResult, GetCompletionsParams, get_statement_for_completions},
3738
diagnostics::{PullDiagnosticsParams, PullDiagnosticsResult},
3839
},
39-
settings::{
40-
Settings, SettingsHandle, SettingsHandleMut, WorkspaceSettings, WorkspaceSettingsHandle,
41-
WorkspaceSettingsHandleMut,
42-
},
43-
WorkspaceError,
40+
settings::{WorkspaceSettings, WorkspaceSettingsHandle, WorkspaceSettingsHandleMut},
4441
};
4542

4643
use super::{
@@ -55,6 +52,7 @@ mod analyser;
5552
mod annotation;
5653
mod async_helper;
5754
mod change;
55+
mod connection_key;
5856
mod connection_manager;
5957
pub(crate) mod document;
6058
mod migration;
@@ -444,15 +442,14 @@ impl Workspace for WorkspaceServer {
444442
if let Some(pool) = self.get_current_connection() {
445443
let path_clone = params.path.clone();
446444
let schema_cache = self.schema_cache.load(pool.clone())?;
447-
let schema_cache_arc = schema_cache.get_arc();
448445
let input = parser.iter(AsyncDiagnosticsMapper).collect::<Vec<_>>();
449446
// sorry for the ugly code :(
450447
let async_results = run_async(async move {
451448
stream::iter(input)
452449
.map(|(_id, range, content, ast, cst, sign)| {
453450
let pool = pool.clone();
454451
let path = path_clone.clone();
455-
let schema_cache = Arc::clone(&schema_cache_arc);
452+
let schema_cache = Arc::clone(&schema_cache);
456453
async move {
457454
if let Some(ast) = ast {
458455
pgt_typecheck::check_sql(TypecheckParams {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use sqlx::PgPool;
2+
3+
use crate::settings::DatabaseSettings;
4+
5+
/// A unique identifier for database connection settings
6+
#[derive(Clone, PartialEq, Eq, Hash)]
7+
pub(crate) struct ConnectionKey {
8+
pub host: String,
9+
pub port: u16,
10+
pub username: String,
11+
pub database: String,
12+
}
13+
14+
impl From<&DatabaseSettings> for ConnectionKey {
15+
fn from(settings: &DatabaseSettings) -> Self {
16+
Self {
17+
host: settings.host.clone(),
18+
port: settings.port,
19+
username: settings.username.clone(),
20+
database: settings.database.clone(),
21+
}
22+
}
23+
}
24+
25+
impl From<&PgPool> for ConnectionKey {
26+
fn from(pool: &PgPool) -> Self {
27+
let conn = pool.connect_options();
28+
29+
match conn.get_database() {
30+
None => Self {
31+
host: conn.get_host().to_string(),
32+
port: conn.get_port(),
33+
username: conn.get_username().to_string(),
34+
database: String::new(),
35+
},
36+
Some(db) => Self {
37+
host: conn.get_host().to_string(),
38+
port: conn.get_port(),
39+
username: conn.get_username().to_string(),
40+
database: db.to_string(),
41+
},
42+
}
43+
}
44+
}

crates/pgt_workspace/src/workspace/server/connection_manager.rs

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,11 @@
11
use std::time::{Duration, Instant};
22

33
use dashmap::DashMap;
4-
use sqlx::{pool::PoolOptions, postgres::PgConnectOptions, PgPool, Postgres};
4+
use sqlx::{PgPool, Postgres, pool::PoolOptions, postgres::PgConnectOptions};
55

66
use crate::settings::DatabaseSettings;
77

8-
/// A unique identifier for database connection settings
9-
#[derive(Clone, PartialEq, Eq, Hash)]
10-
struct ConnectionKey {
11-
host: String,
12-
port: u16,
13-
username: String,
14-
password: String,
15-
database: String,
16-
}
17-
18-
impl From<&DatabaseSettings> for ConnectionKey {
19-
fn from(settings: &DatabaseSettings) -> Self {
20-
Self {
21-
host: settings.host.clone(),
22-
port: settings.port,
23-
username: settings.username.clone(),
24-
password: settings.password.clone(),
25-
database: settings.database.clone(),
26-
}
27-
}
28-
}
8+
use super::connection_key::ConnectionKey;
299

3010
/// Cached connection pool with last access time
3111
struct CachedPool {
@@ -49,6 +29,7 @@ impl ConnectionManager {
4929
/// Get a connection pool for the given database settings.
5030
/// If a pool already exists for these settings, it will be returned.
5131
/// If not, a new pool will be created if connections are enabled.
32+
/// Will also clean up idle connections that haven't been accessed for a while.
5233
pub(crate) fn get_pool(&self, settings: &DatabaseSettings) -> Option<PgPool> {
5334
let key = ConnectionKey::from(settings);
5435

@@ -84,8 +65,8 @@ impl ConnectionManager {
8465
let cached_pool = CachedPool {
8566
pool: pool.clone(),
8667
last_accessed: Instant::now(),
87-
// TODO: add this to the db settings, for now default to one minute
88-
idle_timeout: Duration::from_secs(60),
68+
// TODO: add this to the db settings, for now default to five minutes
69+
idle_timeout: Duration::from_secs(60 * 5),
8970
};
9071

9172
self.pools.insert(key, cached_pool);
Lines changed: 11 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,30 @@
1-
use std::sync::{Arc, RwLock, RwLockReadGuard};
1+
use std::sync::Arc;
22

3+
use dashmap::DashMap;
34
use pgt_schema_cache::SchemaCache;
45
use sqlx::PgPool;
56

67
use crate::WorkspaceError;
78

8-
use super::async_helper::run_async;
9-
10-
pub(crate) struct SchemaCacheHandle<'a> {
11-
inner: RwLockReadGuard<'a, SchemaCacheManagerInner>,
12-
}
13-
14-
impl<'a> SchemaCacheHandle<'a> {
15-
pub(crate) fn new(cache: &'a RwLock<SchemaCacheManagerInner>) -> Self {
16-
Self {
17-
inner: cache.read().unwrap(),
18-
}
19-
}
20-
21-
pub(crate) fn wrap(inner: RwLockReadGuard<'a, SchemaCacheManagerInner>) -> Self {
22-
Self { inner }
23-
}
24-
25-
pub fn get_arc(&self) -> Arc<SchemaCache> {
26-
Arc::clone(&self.inner.cache)
27-
}
28-
}
29-
30-
impl AsRef<SchemaCache> for SchemaCacheHandle<'_> {
31-
fn as_ref(&self) -> &SchemaCache {
32-
&self.inner.cache
33-
}
34-
}
35-
36-
#[derive(Default)]
37-
pub(crate) struct SchemaCacheManagerInner {
38-
cache: Arc<SchemaCache>,
39-
conn_str: String,
40-
}
9+
use super::{async_helper::run_async, connection_key::ConnectionKey};
4110

4211
#[derive(Default)]
4312
pub struct SchemaCacheManager {
44-
inner: RwLock<SchemaCacheManagerInner>,
13+
schemas: DashMap<ConnectionKey, Arc<SchemaCache>>,
4514
}
4615

4716
impl SchemaCacheManager {
48-
pub fn load(&self, pool: PgPool) -> Result<SchemaCacheHandle, WorkspaceError> {
49-
let new_conn_str = pool_to_conn_str(&pool);
17+
pub fn load(&self, pool: PgPool) -> Result<Arc<SchemaCache>, WorkspaceError> {
18+
let key: ConnectionKey = (&pool).into();
5019

51-
{
52-
// return early if the connection string is the same
53-
let inner = self.inner.read().unwrap();
54-
if new_conn_str == inner.conn_str {
55-
tracing::info!("Same connection string, no updates.");
56-
return Ok(SchemaCacheHandle::wrap(inner));
57-
}
20+
if let Some(cache) = self.schemas.get(&key) {
21+
return Ok(Arc::clone(&*cache));
5822
}
5923

60-
let maybe_refreshed = run_async(async move { SchemaCache::load(&pool).await })?;
61-
let refreshed = maybe_refreshed?;
62-
63-
{
64-
// write lock must be dropped before we return the reference below, hence the block
65-
let mut inner = self.inner.write().unwrap();
66-
67-
// Double-check that we still need to refresh (another thread might have done it)
68-
if new_conn_str != inner.conn_str {
69-
inner.cache = Arc::new(refreshed);
70-
inner.conn_str = new_conn_str;
71-
tracing::info!("Refreshed connection.");
72-
}
73-
}
74-
75-
Ok(SchemaCacheHandle::new(&self.inner))
76-
}
77-
}
24+
let schema_cache = Arc::new(run_async(async move { SchemaCache::load(&pool).await })??);
7825

79-
fn pool_to_conn_str(pool: &PgPool) -> String {
80-
let conn = pool.connect_options();
26+
self.schemas.insert(key, Arc::clone(&schema_cache));
8127

82-
match conn.get_database() {
83-
None => format!(
84-
"postgres://{}:<redacted_pw>@{}:{}",
85-
conn.get_username(),
86-
conn.get_host(),
87-
conn.get_port()
88-
),
89-
Some(db) => format!(
90-
"postgres://{}:<redacted_pw>@{}:{}/{}",
91-
conn.get_username(),
92-
conn.get_host(),
93-
conn.get_port(),
94-
db
95-
),
28+
Ok(schema_cache)
9629
}
9730
}

0 commit comments

Comments
 (0)