Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::{
|
||||
search::{
|
||||
CalendarSearchField, ContactSearchField, EmailSearchField, FileSearchField, SearchField,
|
||||
TracingSearchField,
|
||||
},
|
||||
write::SearchIndex,
|
||||
};
|
||||
use ahash::AHashSet;
|
||||
use deadpool_postgres::Pool;
|
||||
use tokio_postgres::error::SqlState;
|
||||
|
||||
pub mod blob;
|
||||
pub mod lookup;
|
||||
pub mod main;
|
||||
pub mod read;
|
||||
pub mod search;
|
||||
pub mod tls;
|
||||
pub mod write;
|
||||
|
||||
pub struct PostgresStore {
|
||||
pub(crate) conn_pool: Pool,
|
||||
pub(crate) ts_configs: AHashSet<&'static str>,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_error(err: tokio_postgres::error::Error) -> trc::Error {
|
||||
let mut local_err = trc::StoreEvent::PostgresqlError.reason(error_chain(&err));
|
||||
if let Some(db_err) = err.as_db_error() {
|
||||
local_err = local_err.code(db_err.code().code().to_string());
|
||||
if let Some(detail) = db_err.detail() {
|
||||
local_err = local_err.details(detail.to_string());
|
||||
}
|
||||
|
||||
if let Some(hint) = db_err.hint() {
|
||||
local_err = local_err.caused_by(hint.to_string());
|
||||
}
|
||||
}
|
||||
local_err
|
||||
}
|
||||
|
||||
fn error_chain(err: &(dyn std::error::Error + 'static)) -> String {
|
||||
let mut message = err.to_string();
|
||||
let mut source = err.source();
|
||||
while let Some(cause) = source {
|
||||
let cause_message = cause.to_string();
|
||||
if !cause_message.is_empty() && !message.ends_with(&cause_message) {
|
||||
message.push_str(": ");
|
||||
message.push_str(&cause_message);
|
||||
}
|
||||
source = cause.source();
|
||||
}
|
||||
message
|
||||
}
|
||||
|
||||
pub(crate) const DELETE_CHUNK_SIZE: usize = 1000;
|
||||
pub(crate) const MIN_DELETE_CHUNK_SIZE: usize = 10;
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn is_timeout_error(err: &tokio_postgres::Error) -> bool {
|
||||
err.code().is_some_and(|code| {
|
||||
*code == SqlState::QUERY_CANCELED
|
||||
|| *code == SqlState::IDLE_IN_TRANSACTION_SESSION_TIMEOUT
|
||||
|| *code == SqlState::LOCK_NOT_AVAILABLE
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_pool_error(err: deadpool_postgres::PoolError) -> trc::Error {
|
||||
match err {
|
||||
deadpool_postgres::PoolError::Backend(err) => into_error(err),
|
||||
err => trc::StoreEvent::PostgresqlError.reason(error_chain(&err)),
|
||||
}
|
||||
}
|
||||
|
||||
impl SearchIndex {
|
||||
pub fn psql_table(&self) -> &'static str {
|
||||
match self {
|
||||
SearchIndex::Email => "s_email",
|
||||
SearchIndex::Calendar => "s_cal",
|
||||
SearchIndex::Contacts => "s_card",
|
||||
SearchIndex::File => "s_file",
|
||||
SearchIndex::Tracing => "s_trace",
|
||||
SearchIndex::InMemory => "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait PsqlSearchField {
|
||||
fn column(&self) -> &'static str;
|
||||
fn column_type(&self) -> &'static str;
|
||||
fn sort_column_type(&self) -> Option<&'static str>;
|
||||
fn sort_column(&self) -> Option<&'static str>;
|
||||
}
|
||||
|
||||
impl PsqlSearchField for EmailSearchField {
|
||||
fn column(&self) -> &'static str {
|
||||
match self {
|
||||
EmailSearchField::From => "fadr",
|
||||
EmailSearchField::To => "tadr",
|
||||
EmailSearchField::Cc => "cc",
|
||||
EmailSearchField::Bcc => "bcc",
|
||||
EmailSearchField::Subject => "subj",
|
||||
EmailSearchField::Body => "body",
|
||||
EmailSearchField::Attachment => "atta",
|
||||
EmailSearchField::ReceivedAt => "rcvd",
|
||||
EmailSearchField::SentAt => "sent",
|
||||
EmailSearchField::Size => "size",
|
||||
EmailSearchField::HasAttachment => "hatt",
|
||||
EmailSearchField::Headers => "hdrs",
|
||||
}
|
||||
}
|
||||
|
||||
fn column_type(&self) -> &'static str {
|
||||
match self {
|
||||
EmailSearchField::ReceivedAt | EmailSearchField::SentAt => "BIGINT",
|
||||
EmailSearchField::Size => "INTEGER",
|
||||
EmailSearchField::HasAttachment => "BOOLEAN",
|
||||
EmailSearchField::Headers => "JSONB",
|
||||
_ => "TSVECTOR",
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_column_type(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
EmailSearchField::From | EmailSearchField::To | EmailSearchField::Subject => {
|
||||
Some("TEXT")
|
||||
}
|
||||
#[cfg(feature = "test_mode")]
|
||||
EmailSearchField::Cc | EmailSearchField::Bcc => Some("TEXT"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_column(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
EmailSearchField::From => Some("s_fr"),
|
||||
EmailSearchField::To => Some("s_to"),
|
||||
EmailSearchField::Subject => Some("s_sj"),
|
||||
#[cfg(feature = "test_mode")]
|
||||
EmailSearchField::Bcc => Some("s_bc"),
|
||||
#[cfg(feature = "test_mode")]
|
||||
EmailSearchField::Cc => Some("s_cc"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PsqlSearchField for CalendarSearchField {
|
||||
fn column(&self) -> &'static str {
|
||||
match self {
|
||||
CalendarSearchField::Title => "titl",
|
||||
CalendarSearchField::Description => "dscd",
|
||||
CalendarSearchField::Location => "locn",
|
||||
CalendarSearchField::Owner => "ownr",
|
||||
CalendarSearchField::Attendee => "atnd",
|
||||
CalendarSearchField::Start => "strt",
|
||||
CalendarSearchField::Uid => "uid",
|
||||
}
|
||||
}
|
||||
|
||||
fn column_type(&self) -> &'static str {
|
||||
match self {
|
||||
CalendarSearchField::Start => "BIGINT",
|
||||
CalendarSearchField::Uid => "TEXT",
|
||||
_ => "TSVECTOR",
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_column_type(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn sort_column(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PsqlSearchField for ContactSearchField {
|
||||
fn column(&self) -> &'static str {
|
||||
match self {
|
||||
ContactSearchField::Member => "mmbr",
|
||||
ContactSearchField::Name => "name",
|
||||
ContactSearchField::Nickname => "nick",
|
||||
ContactSearchField::Organization => "orgn",
|
||||
ContactSearchField::Email => "eml",
|
||||
ContactSearchField::Phone => "phon",
|
||||
ContactSearchField::OnlineService => "olsv",
|
||||
ContactSearchField::Address => "addr",
|
||||
ContactSearchField::Note => "note",
|
||||
ContactSearchField::Kind => "kind",
|
||||
ContactSearchField::Uid => "uid",
|
||||
}
|
||||
}
|
||||
|
||||
fn column_type(&self) -> &'static str {
|
||||
match self {
|
||||
ContactSearchField::Kind | ContactSearchField::Uid => "TEXT",
|
||||
_ => "TSVECTOR",
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_column_type(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn sort_column(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PsqlSearchField for FileSearchField {
|
||||
fn column(&self) -> &'static str {
|
||||
match self {
|
||||
FileSearchField::Name => "name",
|
||||
FileSearchField::Content => "body",
|
||||
}
|
||||
}
|
||||
|
||||
fn column_type(&self) -> &'static str {
|
||||
"TSVECTOR"
|
||||
}
|
||||
|
||||
fn sort_column_type(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn sort_column(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
}
|
||||
impl PsqlSearchField for TracingSearchField {
|
||||
fn column(&self) -> &'static str {
|
||||
match self {
|
||||
TracingSearchField::QueueId => "qid",
|
||||
TracingSearchField::EventType => "etyp",
|
||||
TracingSearchField::Keywords => "kwds",
|
||||
}
|
||||
}
|
||||
|
||||
fn column_type(&self) -> &'static str {
|
||||
match self {
|
||||
TracingSearchField::EventType => "BIGINT",
|
||||
TracingSearchField::QueueId => "BIGINT",
|
||||
TracingSearchField::Keywords => "TSVECTOR",
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_column_type(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn sort_column(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl PsqlSearchField for SearchField {
|
||||
fn column(&self) -> &'static str {
|
||||
match self {
|
||||
SearchField::AccountId => "accid",
|
||||
SearchField::DocumentId => "docid",
|
||||
SearchField::Id => "id",
|
||||
SearchField::Email(field) => field.column(),
|
||||
SearchField::Calendar(field) => field.column(),
|
||||
SearchField::Contact(field) => field.column(),
|
||||
SearchField::File(field) => field.column(),
|
||||
SearchField::Tracing(field) => field.column(),
|
||||
}
|
||||
}
|
||||
|
||||
fn column_type(&self) -> &'static str {
|
||||
match self {
|
||||
SearchField::AccountId => "INTEGER NOT NULL",
|
||||
SearchField::DocumentId => "INTEGER NOT NULL",
|
||||
SearchField::Id => "BIGINT NOT NULL",
|
||||
SearchField::Email(field) => field.column_type(),
|
||||
SearchField::Calendar(field) => field.column_type(),
|
||||
SearchField::Contact(field) => field.column_type(),
|
||||
SearchField::File(field) => field.column_type(),
|
||||
SearchField::Tracing(field) => field.column_type(),
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_column_type(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
SearchField::Email(field) => field.sort_column_type(),
|
||||
SearchField::Calendar(field) => field.sort_column_type(),
|
||||
SearchField::Contact(field) => field.sort_column_type(),
|
||||
SearchField::File(field) => field.sort_column_type(),
|
||||
SearchField::Tracing(field) => field.sort_column_type(),
|
||||
SearchField::AccountId | SearchField::DocumentId | SearchField::Id => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_column(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
SearchField::Email(field) => field.sort_column(),
|
||||
SearchField::Calendar(field) => field.sort_column(),
|
||||
SearchField::Contact(field) => field.sort_column(),
|
||||
SearchField::File(field) => field.sort_column(),
|
||||
SearchField::Tracing(field) => field.sort_column(),
|
||||
SearchField::AccountId | SearchField::DocumentId | SearchField::Id => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user