Skip to main content

shardline_server/
fsck.rs

1use shardline_fsck::run_fsck_with_stores;
2use shardline_index::{LocalIndexStore, LocalRecordStore, PostgresIndexStore, PostgresRecordStore};
3
4use crate::{
5    ServerConfig, ServerError,
6    error::{IndexError, ObjectStoreError},
7    object_store::object_store_from_config,
8    postgres_backend::connect_postgres_metadata_pool,
9};
10
11pub use shardline_fsck::{
12    FsckError, FsckIssueDetail, FsckIssueKind, FsckReconstructionPlanDetail, LocalFsckIssue,
13    LocalFsckIssueKind, LocalFsckReport, ProviderRepositoryStateTimestampField, run_local_fsck,
14};
15
16/// Runs integrity checks against the configured metadata backend and local chunk storage.
17///
18/// # Errors
19///
20/// Returns [`ServerError`] when the storage root cannot be traversed, metadata cannot be
21/// queried, or chunk/record bytes cannot be read.
22pub async fn run_fsck(config: ServerConfig) -> Result<LocalFsckReport, ServerError> {
23    let object_root = config.root_dir().join("chunks");
24    let object_store = object_store_from_config(&config)?;
25    if let Some(index_postgres_url) = config.index_postgres_url() {
26        let pool = connect_postgres_metadata_pool(index_postgres_url, 4)?;
27        let index_store = PostgresIndexStore::new(pool.clone());
28        let record_store = PostgresRecordStore::new(pool);
29        return run_fsck_with_stores(
30            &record_store,
31            &index_store,
32            &object_root,
33            &object_store,
34            config.shard_metadata_limits(),
35        )
36        .await
37        .map_err(ServerError::from);
38    }
39
40    let index_store = LocalIndexStore::open(config.root_dir().to_path_buf());
41    let record_store = LocalRecordStore::open(config.root_dir().to_path_buf());
42    run_fsck_with_stores(
43        &record_store,
44        &index_store,
45        &object_root,
46        &object_store,
47        config.shard_metadata_limits(),
48    )
49    .await
50    .map_err(ServerError::from)
51}
52
53impl From<FsckError> for ServerError {
54    fn from(value: FsckError) -> Self {
55        match value {
56            FsckError::Io(e) => Self::Io(e),
57            FsckError::Json(e) => Self::Json(e),
58            FsckError::NumericConversion(e) => Self::NumericConversion(e),
59            FsckError::Overflow => Self::Overflow,
60            FsckError::LocalObjectStore(e) => Self::ObjectStore(ObjectStoreError::Local(e)),
61            FsckError::S3ObjectStore(e) => Self::ObjectStore(ObjectStoreError::S3(e)),
62            FsckError::ObjectStore(e) => match e {
63                shardline_server_core::ServerObjectStoreError::NotFound => Self::NotFound,
64                shardline_server_core::ServerObjectStoreError::Overflow => Self::Overflow,
65                shardline_server_core::ServerObjectStoreError::InvalidContentHash => {
66                    Self::InvalidContentHash
67                }
68                shardline_server_core::ServerObjectStoreError::StoredObjectLengthMismatch => {
69                    Self::ObjectStore(ObjectStoreError::StoredLengthMismatch)
70                }
71                shardline_server_core::ServerObjectStoreError::Local(e) => {
72                    Self::ObjectStore(ObjectStoreError::Local(e))
73                }
74                shardline_server_core::ServerObjectStoreError::S3(e) => {
75                    Self::ObjectStore(ObjectStoreError::S3(e))
76                }
77                shardline_server_core::ServerObjectStoreError::Io(e) => Self::Io(e),
78                shardline_server_core::ServerObjectStoreError::NumericConversion(e) => {
79                    Self::NumericConversion(e)
80                }
81            },
82            FsckError::XetAdapter(e) => Self::from(e),
83            FsckError::LocalIndexStore(e) => Self::Index(IndexError::Local(e)),
84            FsckError::MemoryIndexStore(e) => Self::Index(IndexError::MemoryIndex(e)),
85            FsckError::MemoryRecordStore(e) => Self::Index(IndexError::MemoryRecord(e)),
86            FsckError::PostgresMetadata(e) => Self::Index(IndexError::PostgresMetadata(e)),
87            FsckError::StoredFileMetadataTooLarge {
88                observed_bytes,
89                maximum_bytes,
90            } => Self::StoredFileMetadataTooLarge {
91                observed_bytes,
92                maximum_bytes,
93            },
94        }
95    }
96}