mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-06 21:12:55 +00:00
@@ -587,6 +587,8 @@ components:
|
||||
type: string
|
||||
state:
|
||||
type: string
|
||||
current_physical_size:
|
||||
type: integer
|
||||
has_in_progress_downloads:
|
||||
type: boolean
|
||||
TenantCreateInfo:
|
||||
|
||||
@@ -438,14 +438,37 @@ async fn tenant_status(request: Request<Body>) -> Result<Response<Body>, ApiErro
|
||||
let index_accessor = remote_index.read().await;
|
||||
let has_in_progress_downloads = index_accessor
|
||||
.tenant_entry(&tenant_id)
|
||||
.ok_or_else(|| ApiError::NotFound("Tenant not found in remote index".to_string()))?
|
||||
.has_in_progress_downloads();
|
||||
.map(|t| t.has_in_progress_downloads())
|
||||
.unwrap_or_else(|| {
|
||||
info!("Tenant {tenant_id} not found in remote index");
|
||||
false
|
||||
});
|
||||
|
||||
let current_physical_size = match tokio::task::spawn_blocking(move || {
|
||||
crate::timelines::get_local_timelines(tenant_id, false, false)
|
||||
})
|
||||
.await
|
||||
.map_err(ApiError::from_err)?
|
||||
{
|
||||
Err(err) => {
|
||||
// Getting local timelines can fail when no local repo is on disk (e.g, when tenant data is being downloaded).
|
||||
// In that case, put a warning message into log and operate normally.
|
||||
warn!("Failed to get local timelines for tenant {tenant_id}: {err}");
|
||||
None
|
||||
}
|
||||
Ok(local_timeline_infos) => Some(
|
||||
local_timeline_infos
|
||||
.into_iter()
|
||||
.fold(0, |acc, x| acc + x.1.current_physical_size.unwrap()),
|
||||
),
|
||||
};
|
||||
|
||||
json_response(
|
||||
StatusCode::OK,
|
||||
TenantInfo {
|
||||
id: tenant_id,
|
||||
state: tenant_state,
|
||||
current_physical_size,
|
||||
has_in_progress_downloads: Some(has_in_progress_downloads),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -508,6 +508,7 @@ pub struct TenantInfo {
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
pub id: ZTenantId,
|
||||
pub state: Option<TenantState>,
|
||||
pub current_physical_size: Option<u64>, // physical size is only included in `tenant_status` endpoint
|
||||
pub has_in_progress_downloads: Option<bool>,
|
||||
}
|
||||
|
||||
@@ -526,6 +527,7 @@ pub fn list_tenants(remote_index: &RemoteTimelineIndex) -> Vec<TenantInfo> {
|
||||
TenantInfo {
|
||||
id: *id,
|
||||
state: Some(tenant.state),
|
||||
current_physical_size: None,
|
||||
has_in_progress_downloads,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from contextlib import closing
|
||||
import pathlib
|
||||
import random
|
||||
from uuid import UUID
|
||||
import re
|
||||
import psycopg2.extras
|
||||
@@ -298,6 +298,40 @@ def test_timeline_physical_size_metric(neon_simple_env: NeonEnv):
|
||||
assert tl_physical_size_metric == get_timeline_dir_size(timeline_path)
|
||||
|
||||
|
||||
def test_tenant_physical_size(neon_simple_env: NeonEnv):
|
||||
random.seed(100)
|
||||
|
||||
env = neon_simple_env
|
||||
client = env.pageserver.http_client()
|
||||
|
||||
tenant, timeline = env.neon_cli.create_tenant()
|
||||
|
||||
def get_timeline_physical_size(timeline: UUID):
|
||||
res = client.timeline_detail(tenant, timeline)
|
||||
return res['local']['current_physical_size_non_incremental']
|
||||
|
||||
timeline_total_size = get_timeline_physical_size(timeline)
|
||||
for i in range(10):
|
||||
n_rows = random.randint(100, 1000)
|
||||
|
||||
timeline = env.neon_cli.create_branch(f"test_tenant_physical_size_{i}", tenant_id=tenant)
|
||||
pg = env.postgres.create_start(f"test_tenant_physical_size_{i}", tenant_id=tenant)
|
||||
|
||||
pg.safe_psql_many([
|
||||
"CREATE TABLE foo (t text)",
|
||||
f"INSERT INTO foo SELECT 'long string to consume some space' || g FROM generate_series(1, {n_rows}) g",
|
||||
])
|
||||
|
||||
env.pageserver.safe_psql(f"checkpoint {tenant.hex} {timeline.hex}")
|
||||
|
||||
timeline_total_size += get_timeline_physical_size(timeline)
|
||||
|
||||
pg.stop()
|
||||
|
||||
tenant_physical_size = int(client.tenant_status(tenant_id=tenant)['current_physical_size'])
|
||||
assert tenant_physical_size == timeline_total_size
|
||||
|
||||
|
||||
def assert_physical_size(env: NeonEnv, tenant_id: UUID, timeline_id: UUID):
|
||||
"""Check the current physical size returned from timeline API
|
||||
matches the total physical size of the timeline on disk"""
|
||||
|
||||
Reference in New Issue
Block a user