mirror of
https://github.com/stalwartlabs/mail-server.git
synced 2025-11-10 05:42:02 +08:00
Do not create tables when using SQL as an external directory (fixes #291)
This commit is contained in:
parent
abd318b678
commit
349bbbbe05
4 changed files with 90 additions and 14 deletions
|
|
@ -29,7 +29,12 @@ pub struct SQLReadReplica {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SQLReadReplica {
|
impl SQLReadReplica {
|
||||||
pub fn open(config: &mut Config, prefix: impl AsKey, stores: &Stores) -> Option<Self> {
|
pub async fn open(
|
||||||
|
config: &mut Config,
|
||||||
|
prefix: impl AsKey,
|
||||||
|
stores: &Stores,
|
||||||
|
create_tables: bool,
|
||||||
|
) -> Option<Self> {
|
||||||
let prefix = prefix.as_key();
|
let prefix = prefix.as_key();
|
||||||
let primary_id = config.value_require((&prefix, "primary"))?.to_string();
|
let primary_id = config.value_require((&prefix, "primary"))?.to_string();
|
||||||
let replica_ids = config
|
let replica_ids = config
|
||||||
|
|
@ -75,6 +80,30 @@ impl SQLReadReplica {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !replicas.is_empty() {
|
if !replicas.is_empty() {
|
||||||
|
if create_tables {
|
||||||
|
match &primary {
|
||||||
|
#[cfg(feature = "postgres")]
|
||||||
|
Store::PostgreSQL(store) => {
|
||||||
|
if let Err(err) = store.create_tables().await {
|
||||||
|
config.new_build_error(
|
||||||
|
(&prefix, "primary"),
|
||||||
|
format!("Failed to create tables: {err}"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "mysql")]
|
||||||
|
Store::MySQL(store) => {
|
||||||
|
if let Err(err) = store.create_tables().await {
|
||||||
|
config.new_build_error(
|
||||||
|
(&prefix, "primary"),
|
||||||
|
format!("Failed to create tables: {err}"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("Invalid store type"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Some(Self {
|
Some(Self {
|
||||||
primary,
|
primary,
|
||||||
replicas,
|
replicas,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,11 @@ use crate::*;
|
||||||
use super::{into_error, MysqlStore};
|
use super::{into_error, MysqlStore};
|
||||||
|
|
||||||
impl MysqlStore {
|
impl MysqlStore {
|
||||||
pub async fn open(config: &mut Config, prefix: impl AsKey) -> Option<Self> {
|
pub async fn open(
|
||||||
|
config: &mut Config,
|
||||||
|
prefix: impl AsKey,
|
||||||
|
create_tables: bool,
|
||||||
|
) -> Option<Self> {
|
||||||
let prefix = prefix.as_key();
|
let prefix = prefix.as_key();
|
||||||
let mut opts = OptsBuilder::default()
|
let mut opts = OptsBuilder::default()
|
||||||
.ip_or_hostname(config.value_require((&prefix, "host"))?.to_string())
|
.ip_or_hostname(config.value_require((&prefix, "host"))?.to_string())
|
||||||
|
|
@ -74,14 +78,16 @@ impl MysqlStore {
|
||||||
conn_pool: Pool::new(opts),
|
conn_pool: Pool::new(opts),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = db.create_tables().await {
|
if create_tables {
|
||||||
config.new_build_error(prefix.as_str(), format!("Failed to create tables: {err}"));
|
if let Err(err) = db.create_tables().await {
|
||||||
|
config.new_build_error(prefix.as_str(), format!("Failed to create tables: {err}"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(db)
|
Some(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn create_tables(&self) -> trc::Result<()> {
|
pub(crate) async fn create_tables(&self) -> trc::Result<()> {
|
||||||
let mut conn = self.conn_pool.get_conn().await.map_err(into_error)?;
|
let mut conn = self.conn_pool.get_conn().await.map_err(into_error)?;
|
||||||
|
|
||||||
for table in [
|
for table in [
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,11 @@ use tokio_postgres::NoTls;
|
||||||
use utils::{config::utils::AsKey, rustls_client_config};
|
use utils::{config::utils::AsKey, rustls_client_config};
|
||||||
|
|
||||||
impl PostgresStore {
|
impl PostgresStore {
|
||||||
pub async fn open(config: &mut utils::config::Config, prefix: impl AsKey) -> Option<Self> {
|
pub async fn open(
|
||||||
|
config: &mut utils::config::Config,
|
||||||
|
prefix: impl AsKey,
|
||||||
|
create_tables: bool,
|
||||||
|
) -> Option<Self> {
|
||||||
let prefix = prefix.as_key();
|
let prefix = prefix.as_key();
|
||||||
let mut cfg = Config::new();
|
let mut cfg = Config::new();
|
||||||
cfg.dbname = config
|
cfg.dbname = config
|
||||||
|
|
@ -61,14 +65,16 @@ impl PostgresStore {
|
||||||
.ok()?,
|
.ok()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = db.create_tables().await {
|
if create_tables {
|
||||||
config.new_build_error(prefix.as_str(), format!("Failed to create tables: {err}"));
|
if let Err(err) = db.create_tables().await {
|
||||||
|
config.new_build_error(prefix.as_str(), format!("Failed to create tables: {err}"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(db)
|
Some(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn create_tables(&self) -> trc::Result<()> {
|
pub(crate) async fn create_tables(&self) -> trc::Result<()> {
|
||||||
let conn = self.conn_pool.get().await.map_err(into_error)?;
|
let conn = self.conn_pool.get().await.map_err(into_error)?;
|
||||||
|
|
||||||
for table in [
|
for table in [
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,11 @@ impl Stores {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "postgres")]
|
#[cfg(feature = "postgres")]
|
||||||
"postgresql" => {
|
"postgresql" => {
|
||||||
if let Some(db) = PostgresStore::open(config, prefix).await.map(Store::from) {
|
if let Some(db) =
|
||||||
|
PostgresStore::open(config, prefix, config.is_active_store(id))
|
||||||
|
.await
|
||||||
|
.map(Store::from)
|
||||||
|
{
|
||||||
self.stores.insert(store_id.clone(), db.clone());
|
self.stores.insert(store_id.clone(), db.clone());
|
||||||
self.fts_stores.insert(store_id.clone(), db.clone().into());
|
self.fts_stores.insert(store_id.clone(), db.clone().into());
|
||||||
self.blob_stores.insert(
|
self.blob_stores.insert(
|
||||||
|
|
@ -142,7 +146,10 @@ impl Stores {
|
||||||
}
|
}
|
||||||
#[cfg(feature = "mysql")]
|
#[cfg(feature = "mysql")]
|
||||||
"mysql" => {
|
"mysql" => {
|
||||||
if let Some(db) = MysqlStore::open(config, prefix).await.map(Store::from) {
|
if let Some(db) = MysqlStore::open(config, prefix, config.is_active_store(id))
|
||||||
|
.await
|
||||||
|
.map(Store::from)
|
||||||
|
{
|
||||||
self.stores.insert(store_id.clone(), db.clone());
|
self.stores.insert(store_id.clone(), db.clone());
|
||||||
self.fts_stores.insert(store_id.clone(), db.clone().into());
|
self.fts_stores.insert(store_id.clone(), db.clone().into());
|
||||||
self.blob_stores.insert(
|
self.blob_stores.insert(
|
||||||
|
|
@ -222,10 +229,15 @@ impl Stores {
|
||||||
for (id, protocol) in composite_stores {
|
for (id, protocol) in composite_stores {
|
||||||
let prefix = ("store", id.as_str());
|
let prefix = ("store", id.as_str());
|
||||||
match protocol.as_str() {
|
match protocol.as_str() {
|
||||||
"composite-read" => {
|
"sql-read-replica" => {
|
||||||
if let Some(db) = crate::backend::composite::read_replica::SQLReadReplica::open(
|
if let Some(db) = crate::backend::composite::read_replica::SQLReadReplica::open(
|
||||||
config, prefix, self,
|
config,
|
||||||
) {
|
prefix,
|
||||||
|
self,
|
||||||
|
config.is_active_store(&id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
self.stores.insert(id, Store::SQLReadReplica(db.into()));
|
self.stores.insert(id, Store::SQLReadReplica(db.into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -346,3 +358,26 @@ impl Stores {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait IsActiveStore {
|
||||||
|
fn is_active_store(&self, id: &str) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IsActiveStore for Config {
|
||||||
|
fn is_active_store(&self, id: &str) -> bool {
|
||||||
|
for key in [
|
||||||
|
"storage.data",
|
||||||
|
"storage.blob",
|
||||||
|
"storage.lookup",
|
||||||
|
"storage.fts",
|
||||||
|
] {
|
||||||
|
if let Some(store_id) = self.value(key) {
|
||||||
|
if store_id == id {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue