pub mod manifest;
pub mod manifest_feature_flags;
mod builder;
mod index_params;
mod load;
mod marker;
mod namespace;
mod query;
mod resolve;
mod transactions;
mod versions;
pub use builder::DirectoryNamespaceBuilder;
pub(crate) use marker::{MarkerFileError, put_marker_file_atomic};
use lance::session::Session;
use lance_io::object_store::ObjectStore;
use object_store::path::Path;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use tokio::sync::OnceCell;
use crate::context::DynamicContextProvider;
use lance_core::{Error, Result};
use lance_namespace::LanceNamespace;
use crate::credentials::CredentialVendor;
#[derive(Debug, Default)]
pub struct OpsMetrics {
counters: Mutex<HashMap<String, u64>>,
}
impl OpsMetrics {
pub fn increment(&self, operation: &str) {
if let Ok(mut counters) = self.counters.lock() {
*counters.entry(operation.to_string()).or_insert(0) += 1;
}
}
pub fn retrieve(&self) -> HashMap<String, u64> {
self.counters.lock().map(|c| c.clone()).unwrap_or_default()
}
pub fn reset(&self) {
if let Ok(mut counters) = self.counters.lock() {
counters.clear();
}
}
}
pub(crate) fn build_sql_expressions(
new_columns: &[lance_namespace::models::AddColumnsEntry],
) -> Result<Vec<(String, String)>> {
new_columns
.iter()
.map(|col| {
let expression = col.expression.clone().and_then(|opt| opt).ok_or_else(|| {
Error::invalid_input(format!(
"Expression is required for new column '{}'",
col.name
))
})?;
Ok((col.name.clone(), expression))
})
.collect()
}
pub(crate) fn build_column_alterations(
alterations: &[lance_namespace::models::AlterColumnsEntry],
) -> Result<Vec<lance::dataset::ColumnAlteration>> {
alterations
.iter()
.map(|entry| {
let mut alteration = lance::dataset::ColumnAlteration::new(entry.path.clone());
if let Some(Some(rename)) = &entry.rename {
alteration = alteration.rename(rename.clone());
}
if let Some(Some(nullable)) = entry.nullable {
alteration = alteration.set_nullable(nullable);
}
if let Some(data_type) = &entry.data_type
&& !data_type.is_null()
{
let type_str = data_type.as_str().ok_or_else(|| {
Error::invalid_input(format!(
"data_type for column '{}' must be a JSON string, got: {}",
entry.path, data_type
))
})?;
let json_type =
lance_namespace::models::JsonArrowDataType::new(type_str.to_string());
let dt =
lance_namespace::schema::convert_json_arrow_type(&json_type).map_err(|e| {
Error::invalid_input(format!(
"Failed to parse data_type '{}' for column '{}': {}",
type_str, entry.path, e
))
})?;
alteration = alteration.cast_to(dt);
}
Ok(alteration)
})
.collect()
}
pub(crate) struct TableStatus {
pub(crate) exists: bool,
pub(crate) is_deregistered: bool,
pub(crate) has_reserved_file: bool,
}
pub struct DirectoryNamespace {
root: String,
storage_options: Option<HashMap<String, String>>,
session: Option<Arc<Session>>,
object_store: Arc<ObjectStore>,
base_path: Path,
manifest_ns: OnceCell<Arc<manifest::ManifestNamespace>>,
write_manifest_ns: OnceCell<Arc<manifest::ManifestNamespace>>,
manifest_enabled: bool,
dir_listing_enabled: bool,
inline_optimization_enabled: bool,
commit_retries: Option<u32>,
dir_listing_to_manifest_migration_enabled: bool,
table_version_tracking_enabled: bool,
credential_vendor: Option<Arc<dyn CredentialVendor>>,
#[allow(dead_code)]
context_provider: Option<Arc<dyn DynamicContextProvider>>,
vend_input_storage_options: bool,
vend_input_storage_options_refresh_interval_millis: Option<u64>,
ops_metrics: Option<Arc<OpsMetrics>>,
}
impl std::fmt::Debug for DirectoryNamespace {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.namespace_id())
}
}
impl std::fmt::Display for DirectoryNamespace {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.namespace_id())
}
}
impl DirectoryNamespace {
pub fn retrieve_ops_metrics(&self) -> HashMap<String, u64> {
self.ops_metrics
.as_ref()
.map(|m| m.retrieve())
.unwrap_or_default()
}
pub fn reset_ops_metrics(&self) {
if let Some(ref metrics) = self.ops_metrics {
metrics.reset();
}
}
fn record_op(&self, operation: &str) {
if let Some(ref metrics) = self.ops_metrics {
metrics.increment(operation);
}
}
}
#[cfg(test)]
mod tests;