Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 28 additions & 16 deletions backend/lib/src/data/indexer_db/mock_repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,18 +502,27 @@ impl IndexerOpsMut for MockRepository {
is_in_bucket: false,
};

// Update bucket statistics
// Verify bucket exists
let mut buckets = self.buckets.write().await;
if let Some(bucket) = buckets.get_mut(&bucket_id) {
bucket.file_count += 1;
bucket.total_size += BigDecimal::from(size);
bucket.updated_at = now;
} else {
if !buckets.contains_key(&bucket_id) {
return Err(RepositoryError::not_found("Bucket"));
}
drop(buckets);

self.files.write().await.insert(id, file.clone());

// Sync file count and total size by calculating from actual files
let files = self.files.read().await;
let bucket_files: Vec<_> = files
.values()
.filter(|f| f.bucket_id == bucket_id)
.collect();
let count = bucket_files.len() as i64;
let total_size: i64 = bucket_files.iter().map(|f| f.size).sum();
if let Some(bucket) = buckets.get_mut(&bucket_id) {
bucket.file_count = count;
bucket.total_size = BigDecimal::from(total_size);
}

Ok(file)
}

Expand All @@ -522,21 +531,24 @@ impl IndexerOpsMut for MockRepository {
let file_to_remove = files
.values()
.find(|f| f.file_key == file_key.as_bytes())
.map(|f| (f.id, f.bucket_id, f.size));
.map(|f| (f.id, f.bucket_id));

if let Some((id, bucket_id, size)) = file_to_remove {
if let Some((id, bucket_id)) = file_to_remove {
files.remove(&id);

// Sync file count and total size by calculating from actual files
let bucket_files: Vec<_> = files
.values()
.filter(|f| f.bucket_id == bucket_id)
.collect();
let count = bucket_files.len() as i64;
let total_size: i64 = bucket_files.iter().map(|f| f.size).sum();
drop(files);

// Update bucket statistics
let now = Utc::now().naive_utc();
let mut buckets = self.buckets.write().await;
if let Some(bucket) = buckets.get_mut(&bucket_id) {
bucket.file_count = bucket.file_count.saturating_sub(1);
bucket.total_size -= BigDecimal::from(size);
bucket.updated_at = now;
} else {
return Err(RepositoryError::not_found("Bucket"));
bucket.file_count = count;
bucket.total_size = BigDecimal::from(total_size);
}

Ok(())
Expand Down
37 changes: 15 additions & 22 deletions client/indexer-db/src/models/bucket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,39 +196,32 @@ impl Bucket {
Ok(total_size.unwrap_or_else(|| BigDecimal::from(0)))
}

/// Increment file count and update total size
pub async fn increment_file_count_and_size<'a>(
/// Sync the stored file_count and total_size by calculating from actual files.
///
/// This recalculates both values from the files table and updates the stored values.
pub async fn sync_stats<'a>(
conn: &mut DbConnection<'a>,
bucket_id: i64,
file_size: i64,
) -> Result<(), diesel::result::Error> {
let size_decimal = BigDecimal::from(file_size);
diesel::update(bucket::table)
.filter(bucket::id.eq(bucket_id))
.set((
bucket::total_size.eq(bucket::total_size + size_decimal),
bucket::file_count.eq(bucket::file_count + 1),
))
.execute(conn)
// Count files and sum sizes in one query
// Note: SQL sum function returns NULL (None) if there are no files.
let (count, total_size): (i64, Option<BigDecimal>) = file::table
.filter(file::bucket_id.eq(bucket_id))
.select((diesel::dsl::count_star(), sum(file::size)))
.first(conn)
.await?;
Ok(())
}

/// Decrement file count and update total size
pub async fn decrement_file_count_and_size<'a>(
conn: &mut DbConnection<'a>,
bucket_id: i64,
file_size: i64,
) -> Result<(), diesel::result::Error> {
let size_decimal = BigDecimal::from(file_size);
let total_size = total_size.unwrap_or_else(|| BigDecimal::from(0));

diesel::update(bucket::table)
.filter(bucket::id.eq(bucket_id))
.set((
bucket::total_size.eq(bucket::total_size - size_decimal),
bucket::file_count.eq(bucket::file_count - 1),
bucket::file_count.eq(count),
bucket::total_size.eq(total_size),
))
.execute(conn)
.await?;

Ok(())
}
}
16 changes: 8 additions & 8 deletions client/indexer-db/src/models/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ impl File {
.execute(conn)
.await?;

// Update bucket total size and file count
Bucket::increment_file_count_and_size(conn, bucket_id, size).await?;
// Sync the bucket's file count and total size from actual files
Bucket::sync_stats(conn, bucket_id).await?;

Ok(file)
}
Expand Down Expand Up @@ -194,10 +194,10 @@ impl File {
) -> Result<(), diesel::result::Error> {
let file_key = file_key.as_ref().to_vec();

// Get file info before deletion
let file_info: Option<(i64, i64)> = file::table
// Get bucket_id before deletion so we can sync the count
let bucket_id: Option<i64> = file::table
.filter(file::file_key.eq(&file_key))
.select((file::bucket_id, file::size))
.select(file::bucket_id)
.first(conn)
.await
.optional()?;
Expand All @@ -208,9 +208,9 @@ impl File {
.execute(conn)
.await?;

// Update bucket counts if file was found
if let Some((bucket_id, file_size)) = file_info {
Bucket::decrement_file_count_and_size(conn, bucket_id, file_size).await?;
// Sync the bucket's file count and total size from actual files
if let Some(bucket_id) = bucket_id {
Bucket::sync_stats(conn, bucket_id).await?;
}

Ok(())
Expand Down
Loading