Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(webserver): add endpoint to calculate disk usage #1964

Merged
merged 4 commits into from
Apr 25, 2024
Merged
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
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions ee/tabby-webserver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ validator = { version = "0.16.1", features = ["derive"] }
regex.workspace = true
tabby-search = { path = "../tabby-search" }
octocrab = "0.38.0"
fs_extra = "1.3.0"

[dev-dependencies]
assert_matches = "1.5.0"
tokio = { workspace = true, features = ["macros"] }
tabby-db = { path = "../../ee/tabby-db", features = ["testutils"] }
tabby-common = { path = "../../crates/tabby-common", features = [ "testutils" ] }
serial_test = { workspace = true }
temp_testdir = { workspace = true }
13 changes: 13 additions & 0 deletions ee/tabby-webserver/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ type UserConnection {
pageInfo: PageInfo!
}

type DiskUsageStats {
events: DiskUsage!
indexedRepositories: DiskUsage!
database: DiskUsage!
models: DiskUsage!
}

input UpdateOAuthCredentialInput {
provider: OAuthProvider!
clientId: String!
Expand Down Expand Up @@ -258,6 +265,7 @@ type Query {
dailyStatsInPastYear(users: [ID!]): [CompletionStats!]!
dailyStats(start: DateTimeUtc!, end: DateTimeUtc!, users: [ID!], languages: [Language!]): [CompletionStats!]!
userEvents(after: String, before: String, first: Int, last: Int, users: [ID!], start: DateTimeUtc!, end: DateTimeUtc!): UserEventConnection!
diskUsageStats: DiskUsageStats!
}

input NetworkSettingInput {
Expand All @@ -275,6 +283,11 @@ type UserEdge {
cursor: String!
}

type DiskUsage {
filePaths: [String!]!
size: Float!
}

type JobRunConnection {
edges: [JobRunEdge!]!
pageInfo: PageInfo!
Expand Down
2 changes: 1 addition & 1 deletion ee/tabby-webserver/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::path::PathBuf;

use tabby_common::path::tabby_root;

fn tabby_ee_root() -> PathBuf {
pub fn tabby_ee_root() -> PathBuf {
tabby_root().join("ee")
}

Expand Down
29 changes: 29 additions & 0 deletions ee/tabby-webserver/src/schema/analytic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,33 @@

use crate::schema::Result;

#[derive(GraphQLObject)]

Check warning on line 11 in ee/tabby-webserver/src/schema/analytic.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/schema/analytic.rs#L11

Added line #L11 was not covered by tests
pub struct DiskUsageStats {
pub events: DiskUsage,
pub indexed_repositories: DiskUsage,
pub database: DiskUsage,
pub models: DiskUsage,
}

#[derive(GraphQLObject)]

Check warning on line 19 in ee/tabby-webserver/src/schema/analytic.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/schema/analytic.rs#L19

Added line #L19 was not covered by tests
pub struct DiskUsage {
pub file_paths: Vec<String>,
pub size: f64,
}

impl DiskUsage {
pub fn combine(self, other: Self) -> Self {
DiskUsage {
size: self.size + other.size,
file_paths: self
.file_paths
.into_iter()
.chain(other.file_paths)
.collect(),
}
}
}

#[derive(GraphQLObject, Debug, Clone)]
pub struct CompletionStats {
pub start: DateTime<Utc>,
Expand Down Expand Up @@ -101,4 +128,6 @@
users: Vec<ID>,
languages: Vec<Language>,
) -> Result<Vec<CompletionStats>>;

async fn disk_usage_stats(&self) -> Result<DiskUsageStats>;
}
8 changes: 7 additions & 1 deletion ee/tabby-webserver/src/schema/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use validator::{Validate, ValidationErrors};
use worker::{Worker, WorkerService};

use self::{
analytic::{AnalyticService, CompletionStats},
analytic::{AnalyticService, CompletionStats, DiskUsageStats},
auth::{
JWTPayload, OAuthCredential, OAuthProvider, PasswordChangeInput, PasswordResetInput,
RequestInvitationInput, RequestPasswordResetEmailInput, UpdateOAuthCredentialInput,
Expand Down Expand Up @@ -457,6 +457,12 @@ impl Query {
)
.await
}

async fn disk_usage_stats(ctx: &Context) -> Result<DiskUsageStats> {
check_admin(ctx).await?;
let storage_stats = ctx.locator.analytic().disk_usage_stats().await?;
Ok(storage_stats)
}
}

#[derive(GraphQLObject)]
Expand Down
62 changes: 60 additions & 2 deletions ee/tabby-webserver/src/service/analytic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::sync::Arc;
use std::{path::PathBuf, sync::Arc};

use async_trait::async_trait;
use chrono::{DateTime, Utc};
Expand All @@ -8,7 +8,7 @@

use super::AsRowid;
use crate::schema::{
analytic::{AnalyticService, CompletionStats, Language},
analytic::{AnalyticService, CompletionStats, DiskUsage, DiskUsageStats, Language},
Result,
};

Expand Down Expand Up @@ -70,6 +70,35 @@
.collect();
Ok(stats)
}

async fn disk_usage_stats(&self) -> Result<DiskUsageStats> {
Ok(DiskUsageStats {
events: recursive_dir_size(tabby_common::path::events_dir()).await?,
indexed_repositories: recursive_dir_size(tabby_common::path::dataset_dir())
.await?

Check warning on line 78 in ee/tabby-webserver/src/service/analytic.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/analytic.rs#L78

Added line #L78 was not covered by tests
.combine(recursive_dir_size(tabby_common::path::index_dir()).await?),
database: recursive_dir_size(crate::path::tabby_ee_root()).await?,
models: recursive_dir_size(tabby_common::path::models_dir()).await?,
})
}
}

/// Calculate the size of a directory in kilobytes recursively
async fn recursive_dir_size(path: PathBuf) -> Result<DiskUsage, anyhow::Error> {
let path_str = path.to_string_lossy().to_string();

let size = if path.exists() {
tokio::task::spawn_blocking(|| async { fs_extra::dir::get_size(path) })
.await?
.await?

Check warning on line 93 in ee/tabby-webserver/src/service/analytic.rs

View check run for this annotation

Codecov / codecov/patch

ee/tabby-webserver/src/service/analytic.rs#L93

Added line #L93 was not covered by tests
} else {
0
};

Ok(DiskUsage {
file_paths: vec![path_str],
size: size as f64 / 1024.0,
})
}

fn convert_ids(ids: Vec<ID>) -> Vec<i64> {
Expand All @@ -91,6 +120,8 @@
#[cfg(test)]
mod tests {
use chrono::{Days, Duration};
use tabby_common::path::set_tabby_root;
use temp_testdir::TempDir;

use super::*;
use crate::service::AsID;
Expand Down Expand Up @@ -297,4 +328,31 @@
.unwrap()
.is_empty());
}

#[tokio::test]
async fn test_disk_usage() {
let tmp_dir = TempDir::default();
set_tabby_root(tmp_dir.to_path_buf());

tokio::fs::create_dir_all(tabby_common::path::models_dir())
.await
.unwrap();

tokio::fs::write(
tabby_common::path::models_dir().join("testfile"),
"0".repeat(1024).as_bytes(),
)
.await
.unwrap();

let db = DbConn::new_in_memory().await.unwrap();
let service = new_analytic_service(db);

let disk_usage = service.disk_usage_stats().await.unwrap();

assert_eq!(disk_usage.events.size, 0.0);
assert_eq!(disk_usage.indexed_repositories.size, 0.0);
assert_eq!(disk_usage.database.size, 0.0);
assert_eq!(disk_usage.models.size, 1.0);
}
}
Loading