Repository: libsql/libsql
File: libsql-server/src/namespace/meta_store.rs (Rust)

Code before:
                };

                let config = match metadata::DatabaseConfig::decode(&v[..]) {
                    Ok(c) => DatabaseConfig::from(&c),
                    Err(e) => {
                        tracing::warn!("unable to convert config: {}", e);
                        continue;
                    }
                };

                let (tx, _) = watch::channel(Arc::new(config));

                configs.insert(ns, tx);
            }

            Err(e) => {
                tracing::error!("meta store restore failed: {}", e);
                return Err(Error::from(e));
            }
        }
    }

    tracing::info!("meta store restore completed");

    Ok(configs)
}

impl MetaStore {
    #[tracing::instrument(skip(config, base_path))]
    pub async fn new(config: Option<MetaStoreConfig>, base_path: &Path) -> Result<Self> {
        let db_path = base_path.join("metastore");
        tokio::fs::create_dir_all(&db_path).await?;
        let replicator = match config {
            Some(config) => {
                let options = bottomless::replicator::Options {
                    create_bucket_if_not_exists: true,
                    verify_crc: true,
                    use_compression: CompressionKind::None,
                    aws_endpoint: Some(config.bucket_endpoint),
                    access_key_id: Some(config.access_key_id),
                    secret_access_key: Some(config.secret_access_key),
                    region: Some(config.region),
                    db_id: Some(config.backup_id),
                    bucket_name: config.bucket_name,
                    max_frames_per_batch: 10_000,
                    max_batch_interval: config.backup_interval,
                    s3_upload_max_parallelism: 32,
                    restore_transaction_page_swap_after: 1000,
                    restore_transaction_cache_fpath: ".bottomless.restore".into(),
                    s3_max_retries: 10,
                };

Review comment (suggestion):
this is only ok for now, because we keep the config for all namespaces in memory at all time. When we allow the number of namespaces to grow, we'll want to tie the config's lifetime to the namespace's lifetime in memory, which won't work anymore. To keep in mind for when we implement that.

Code after:

    let mut configs = HashMap::new();

    for row in rows {
        match row {
            Ok((k, v)) => {
                let ns = match NamespaceName::from_string(k) {
                    Ok(ns) => ns,
                    Err(e) => {
                        tracing::warn!("unable to convert namespace name: {}", e);
                        continue;
                    }
                };

                let config = match metadata::DatabaseConfig::decode(&v[..]) {
                    Ok(c) => Arc::new(DatabaseConfig::from(&c)),
                    Err(e) => {
                        tracing::warn!("unable to convert config: {}", e);
                        continue;
                    }
                };

                // We don't store the version in the sqlitedb due to the session token
                // changed each time we start the primary, this will cause the replica to
                // handshake again and get the latest config.
                let (tx, _) = watch::channel(InnerConfig { version: 0, config });

                configs.insert(ns, tx);
            }

            Err(e) => {
                tracing::error!("meta store restore failed: {}", e);
                return Err(Error::from(e));
            }
        }
    }

    tracing::info!("meta store restore completed");

    Ok(configs)
}

impl MetaStore {
    #[tracing::instrument(skip(config, base_path))]
    pub async fn new(config: Option<MetaStoreConfig>, base_path: &Path) -> Result<Self> {
        let db_path = base_path.join("metastore");
        tokio::fs::create_dir_all(&db_path).await?;
        let replicator = match config {
            Some(config) => {
                let options = bottomless::replicator::Options {
                    create_bucket_if_not_exists: true,