- Created T026-practical-test task.yaml for MVP smoke testing - Added k8shost-server to flake.nix (packages, apps, overlays) - Staged all workspace directories for nix flake build - Updated flake.nix shellHook to include k8shost Resolves: T026.S1 blocker (R8 - nix submodule visibility)
159 lines
4.8 KiB
Rust
159 lines
4.8 KiB
Rust
//! Storage backend trait definition
|
|
|
|
use async_trait::async_trait;
|
|
use bytes::Bytes;
|
|
use lightningstor_types::ObjectId;
|
|
use std::io;
|
|
use thiserror::Error;
|
|
|
|
/// Storage backend error
|
|
#[derive(Debug, Error)]
|
|
pub enum StorageError {
|
|
#[error("IO error: {0}")]
|
|
Io(#[from] io::Error),
|
|
|
|
#[error("Object not found: {0}")]
|
|
NotFound(ObjectId),
|
|
|
|
#[error("Storage backend error: {0}")]
|
|
Backend(String),
|
|
|
|
#[error("Invalid object ID: {0}")]
|
|
InvalidObjectId(String),
|
|
}
|
|
|
|
/// Storage result type
|
|
pub type StorageResult<T> = std::result::Result<T, StorageError>;
|
|
|
|
impl From<StorageError> for lightningstor_types::Error {
|
|
fn from(err: StorageError) -> Self {
|
|
match err {
|
|
StorageError::Io(e) => lightningstor_types::Error::StorageError(e.to_string()),
|
|
StorageError::NotFound(id) => {
|
|
lightningstor_types::Error::ObjectNotFound {
|
|
bucket: String::new(),
|
|
key: id.to_string(),
|
|
}
|
|
}
|
|
StorageError::Backend(msg) => lightningstor_types::Error::StorageError(msg),
|
|
StorageError::InvalidObjectId(msg) => {
|
|
lightningstor_types::Error::InvalidArgument(msg)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Storage backend trait for object data storage
|
|
///
|
|
/// This trait abstracts the storage of object data, allowing different
|
|
/// implementations (local filesystem, distributed storage, cloud storage).
|
|
#[async_trait]
|
|
pub trait StorageBackend: Send + Sync {
|
|
/// Write object data
|
|
///
|
|
/// # Arguments
|
|
/// * `object_id` - Internal object identifier
|
|
/// * `data` - Object data bytes
|
|
///
|
|
/// # Returns
|
|
/// * `Ok(())` if write succeeded
|
|
/// * `Err(StorageError)` if write failed
|
|
async fn put_object(&self, object_id: &ObjectId, data: Bytes) -> StorageResult<()>;
|
|
|
|
/// Read object data
|
|
///
|
|
/// # Arguments
|
|
/// * `object_id` - Internal object identifier
|
|
///
|
|
/// # Returns
|
|
/// * `Ok(Bytes)` if object exists
|
|
/// * `Err(StorageError::NotFound)` if object does not exist
|
|
/// * `Err(StorageError)` for other errors
|
|
async fn get_object(&self, object_id: &ObjectId) -> StorageResult<Bytes>;
|
|
|
|
/// Delete object data
|
|
///
|
|
/// # Arguments
|
|
/// * `object_id` - Internal object identifier
|
|
///
|
|
/// # Returns
|
|
/// * `Ok(())` if delete succeeded (or object didn't exist)
|
|
/// * `Err(StorageError)` for other errors
|
|
async fn delete_object(&self, object_id: &ObjectId) -> StorageResult<()>;
|
|
|
|
/// Check if object exists
|
|
///
|
|
/// # Arguments
|
|
/// * `object_id` - Internal object identifier
|
|
///
|
|
/// # Returns
|
|
/// * `Ok(true)` if object exists
|
|
/// * `Ok(false)` if object does not exist
|
|
/// * `Err(StorageError)` for other errors
|
|
async fn object_exists(&self, object_id: &ObjectId) -> StorageResult<bool>;
|
|
|
|
/// Get object size in bytes
|
|
///
|
|
/// # Arguments
|
|
/// * `object_id` - Internal object identifier
|
|
///
|
|
/// # Returns
|
|
/// * `Ok(u64)` if object exists
|
|
/// * `Err(StorageError::NotFound)` if object does not exist
|
|
/// * `Err(StorageError)` for other errors
|
|
async fn object_size(&self, object_id: &ObjectId) -> StorageResult<u64>;
|
|
|
|
/// Write part data (for multipart uploads)
|
|
///
|
|
/// # Arguments
|
|
/// * `upload_id` - Multipart upload ID
|
|
/// * `part_number` - Part number (1-based)
|
|
/// * `data` - Part data bytes
|
|
///
|
|
/// # Returns
|
|
/// * `Ok(())` if write succeeded
|
|
/// * `Err(StorageError)` if write failed
|
|
async fn put_part(
|
|
&self,
|
|
upload_id: &str,
|
|
part_number: u32,
|
|
data: Bytes,
|
|
) -> StorageResult<()>;
|
|
|
|
/// Read part data (for multipart uploads)
|
|
///
|
|
/// # Arguments
|
|
/// * `upload_id` - Multipart upload ID
|
|
/// * `part_number` - Part number (1-based)
|
|
///
|
|
/// # Returns
|
|
/// * `Ok(Bytes)` if part exists
|
|
/// * `Err(StorageError::NotFound)` if part does not exist
|
|
/// * `Err(StorageError)` for other errors
|
|
async fn get_part(
|
|
&self,
|
|
upload_id: &str,
|
|
part_number: u32,
|
|
) -> StorageResult<Bytes>;
|
|
|
|
/// Delete part data (for multipart uploads)
|
|
///
|
|
/// # Arguments
|
|
/// * `upload_id` - Multipart upload ID
|
|
/// * `part_number` - Part number (1-based)
|
|
///
|
|
/// # Returns
|
|
/// * `Ok(())` if delete succeeded
|
|
/// * `Err(StorageError)` for other errors
|
|
async fn delete_part(&self, upload_id: &str, part_number: u32) -> StorageResult<()>;
|
|
|
|
/// Delete all parts for a multipart upload
|
|
///
|
|
/// # Arguments
|
|
/// * `upload_id` - Multipart upload ID
|
|
///
|
|
/// # Returns
|
|
/// * `Ok(())` if delete succeeded
|
|
/// * `Err(StorageError)` for other errors
|
|
async fn delete_upload_parts(&self, upload_id: &str) -> StorageResult<()>;
|
|
}
|