Use RwLock to never persist cli state to db

This commit is contained in:
bwbonanno 2023-10-19 12:45:57 -07:00
parent d8c649b3cd
commit dd619913da
4 changed files with 39 additions and 16 deletions

View File

@ -127,6 +127,8 @@ pub enum Error {
Persist(#[from] tempfile::PersistError), Persist(#[from] tempfile::PersistError),
#[error(transparent)] #[error(transparent)]
FeatureNotEnabled(#[from] FeatureNotEnabledError), FeatureNotEnabled(#[from] FeatureNotEnabledError),
#[error("An unexpected error occurred when accessing the runtime features.")]
RuntimeFeatureToggleError,
#[error(transparent)] #[error(transparent)]
Anyhow(#[from] anyhow::Error), Anyhow(#[from] anyhow::Error),
@ -186,6 +188,7 @@ impl Error {
| Error::IoError(_) | Error::IoError(_)
| Error::Persist(_) | Error::Persist(_)
| Error::FeatureNotEnabled(_) | Error::FeatureNotEnabled(_)
| Error::RuntimeFeatureToggleError
| Error::Anyhow(_) => true, | Error::Anyhow(_) => true,
Error::CreateBatch(_) Error::CreateBatch(_)
| Error::CorruptedTaskQueue | Error::CorruptedTaskQueue
@ -232,6 +235,7 @@ impl ErrorCode for Error {
Error::IoError(e) => e.error_code(), Error::IoError(e) => e.error_code(),
Error::Persist(e) => e.error_code(), Error::Persist(e) => e.error_code(),
Error::FeatureNotEnabled(_) => Code::FeatureNotEnabled, Error::FeatureNotEnabled(_) => Code::FeatureNotEnabled,
Error::RuntimeFeatureToggleError => Code::Internal,
// Irrecoverable errors // Irrecoverable errors
Error::Anyhow(_) => Code::Internal, Error::Anyhow(_) => Code::Internal,

View File

@ -1,7 +1,10 @@
use std::sync::{Arc, RwLock};
use meilisearch_types::features::{InstanceTogglableFeatures, RuntimeTogglableFeatures}; use meilisearch_types::features::{InstanceTogglableFeatures, RuntimeTogglableFeatures};
use meilisearch_types::heed::types::{SerdeJson, Str}; use meilisearch_types::heed::types::{SerdeJson, Str};
use meilisearch_types::heed::{Database, Env, RoTxn, RwTxn}; use meilisearch_types::heed::{Database, Env, RwTxn};
use crate::error::Error::RuntimeFeatureToggleError;
use crate::error::FeatureNotEnabledError; use crate::error::FeatureNotEnabledError;
use crate::Result; use crate::Result;
@ -9,7 +12,8 @@ const EXPERIMENTAL_FEATURES: &str = "experimental-features";
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct FeatureData { pub(crate) struct FeatureData {
runtime: Database<Str, SerdeJson<RuntimeTogglableFeatures>>, persisted: Database<Str, SerdeJson<RuntimeTogglableFeatures>>,
runtime: Arc<RwLock<RuntimeTogglableFeatures>>,
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -18,8 +22,8 @@ pub struct RoFeatures {
} }
impl RoFeatures { impl RoFeatures {
fn new(txn: RoTxn<'_>, data: &FeatureData) -> Result<Self> { fn new(data: &FeatureData) -> Result<Self> {
let runtime = data.runtime_features(txn)?; let runtime = data.runtime_features()?;
Ok(Self { runtime }) Ok(Self { runtime })
} }
@ -83,13 +87,18 @@ impl RoFeatures {
impl FeatureData { impl FeatureData {
pub fn new(env: &Env, instance_features: InstanceTogglableFeatures) -> Result<Self> { pub fn new(env: &Env, instance_features: InstanceTogglableFeatures) -> Result<Self> {
let mut wtxn = env.write_txn()?; let mut wtxn = env.write_txn()?;
let runtime_features = env.create_database(&mut wtxn, Some(EXPERIMENTAL_FEATURES))?; let runtime_features_db = env.create_database(&mut wtxn, Some(EXPERIMENTAL_FEATURES))?;
let default_features =
RuntimeTogglableFeatures { metrics: instance_features.metrics, ..Default::default() };
runtime_features.put(&mut wtxn, EXPERIMENTAL_FEATURES, &default_features)?;
wtxn.commit()?; wtxn.commit()?;
Ok(Self { runtime: runtime_features }) let txn = env.read_txn()?;
let persisted_features: RuntimeTogglableFeatures =
runtime_features_db.get(&txn, EXPERIMENTAL_FEATURES)?.unwrap_or_default();
let runtime = Arc::new(RwLock::new(RuntimeTogglableFeatures {
metrics: instance_features.metrics || persisted_features.metrics,
..persisted_features
}));
Ok(Self { persisted: runtime_features_db, runtime })
} }
pub fn put_runtime_features( pub fn put_runtime_features(
@ -97,16 +106,19 @@ impl FeatureData {
mut wtxn: RwTxn, mut wtxn: RwTxn,
features: RuntimeTogglableFeatures, features: RuntimeTogglableFeatures,
) -> Result<()> { ) -> Result<()> {
self.runtime.put(&mut wtxn, EXPERIMENTAL_FEATURES, &features)?; self.persisted.put(&mut wtxn, EXPERIMENTAL_FEATURES, &features)?;
wtxn.commit()?; wtxn.commit()?;
let mut toggled_features = self.runtime.write().map_err(|_| RuntimeFeatureToggleError)?;
*toggled_features = features;
Ok(()) Ok(())
} }
fn runtime_features(&self, txn: RoTxn) -> Result<RuntimeTogglableFeatures> { fn runtime_features(&self) -> Result<RuntimeTogglableFeatures> {
Ok(self.runtime.get(&txn, EXPERIMENTAL_FEATURES)?.unwrap_or_default()) Ok(*self.runtime.read().map_err(|_| RuntimeFeatureToggleError)?)
} }
pub fn features(&self, txn: RoTxn) -> Result<RoFeatures> { pub fn features(&self) -> Result<RoFeatures> {
RoFeatures::new(txn, self) RoFeatures::new(self)
} }
} }

View File

@ -1300,8 +1300,7 @@ impl IndexScheduler {
} }
pub fn features(&self) -> Result<RoFeatures> { pub fn features(&self) -> Result<RoFeatures> {
let rtxn = self.read_txn()?; self.features.features()
self.features.features(rtxn)
} }
pub fn put_runtime_features(&self, features: RuntimeTogglableFeatures) -> Result<()> { pub fn put_runtime_features(&self, features: RuntimeTogglableFeatures) -> Result<()> {

View File

@ -126,6 +126,14 @@ async fn experimental_feature_metrics() {
let (response, code) = server.get_metrics().await; let (response, code) = server.get_metrics().await;
meili_snap::snapshot!(code, @"200 OK"); meili_snap::snapshot!(code, @"200 OK");
meili_snap::snapshot!(response, @"null"); meili_snap::snapshot!(response, @"null");
// startup without flag respects persisted metrics value
let disable_metrics =
Opt { experimental_enable_metrics: false, ..default_settings(dir.path()) };
let server_no_flag = Server::new_with_options(disable_metrics).await.unwrap();
let (response, code) = server_no_flag.get_metrics().await;
meili_snap::snapshot!(code, @"200 OK");
meili_snap::snapshot!(response, @"null");
} }
#[actix_rt::test] #[actix_rt::test]