Skip to content

Commit dfff907

Browse files
committed
pageserver: API for invoking page trace
1 parent 72d85b0 commit dfff907

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pageserver/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ arc-swap.workspace = true
1616
async-compression.workspace = true
1717
async-stream.workspace = true
1818
bit_field.workspace = true
19+
bincode.workspace = true
1920
byteorder.workspace = true
2021
bytes.workspace = true
2122
camino.workspace = true

pageserver/src/http/routes.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::collections::HashMap;
77
use std::str::FromStr;
88
use std::sync::Arc;
99
use std::time::Duration;
10+
use std::time::Instant;
1011

1112
use anyhow::{anyhow, Context, Result};
1213
use enumset::EnumSet;
@@ -90,6 +91,7 @@ use crate::tenant::timeline::CompactFlags;
9091
use crate::tenant::timeline::CompactOptions;
9192
use crate::tenant::timeline::CompactRequest;
9293
use crate::tenant::timeline::CompactionError;
94+
use crate::tenant::timeline::PageTrace;
9395
use crate::tenant::timeline::Timeline;
9496
use crate::tenant::GetTimelineError;
9597
use crate::tenant::OffloadedTimeline;
@@ -1521,6 +1523,60 @@ async fn timeline_gc_unblocking_handler(
15211523
block_or_unblock_gc(request, false).await
15221524
}
15231525

1526+
async fn timeline_page_trace_handler(
1527+
request: Request<Body>,
1528+
_cancel: CancellationToken,
1529+
) -> Result<Response<Body>, ApiError> {
1530+
let tenant_shard_id: TenantShardId = parse_request_param(&request, "tenant_shard_id")?;
1531+
let timeline_id: TimelineId = parse_request_param(&request, "timeline_id")?;
1532+
let state = get_state(&request);
1533+
1534+
let size_limit =
1535+
parse_query_param::<_, u64>(&request, "size_limit_bytes")?.unwrap_or(1024 * 1024);
1536+
let time_limit_secs = parse_query_param::<_, u64>(&request, "time_limit_secs")?.unwrap_or(5);
1537+
1538+
// Convert size limit to event limit based on known serialized size of an event
1539+
let event_limit = size_limit / 32;
1540+
1541+
let timeline =
1542+
active_timeline_of_active_tenant(&state.tenant_manager, tenant_shard_id, timeline_id)
1543+
.await?;
1544+
1545+
let (page_trace, mut trace_rx) = PageTrace::new(event_limit);
1546+
timeline.page_trace.store(Arc::new(Some(page_trace)));
1547+
1548+
let mut buffer = Vec::with_capacity(size_limit as usize);
1549+
1550+
let deadline = Instant::now() + Duration::from_secs(time_limit_secs);
1551+
1552+
loop {
1553+
let timeout = deadline.saturating_duration_since(Instant::now());
1554+
tokio::select! {
1555+
event = trace_rx.recv() => {
1556+
buffer.extend(bincode::serialize(&event).unwrap());
1557+
1558+
if buffer.len() >= size_limit as usize {
1559+
// Size threshold reached
1560+
break;
1561+
}
1562+
}
1563+
_ = tokio::time::sleep(timeout) => {
1564+
// Time threshold reached
1565+
break;
1566+
}
1567+
}
1568+
}
1569+
1570+
// Above code is infallible, so we guarantee to switch the trace off when done
1571+
timeline.page_trace.store(Arc::new(None));
1572+
1573+
Ok(Response::builder()
1574+
.status(StatusCode::OK)
1575+
.header(header::CONTENT_TYPE, "application/octet-stream")
1576+
.body(hyper::Body::from(buffer))
1577+
.unwrap())
1578+
}
1579+
15241580
/// Adding a block is `POST ../block_gc`, removing a block is `POST ../unblock_gc`.
15251581
///
15261582
/// Both are technically unsafe because they might fire off index uploads, thus they are POST.
@@ -3487,6 +3543,10 @@ pub fn make_router(
34873543
"/v1/tenant/:tenant_shard_id/timeline/:timeline_id/unblock_gc",
34883544
|r| api_handler(r, timeline_gc_unblocking_handler),
34893545
)
3546+
.post(
3547+
"/v1/tenant/:tenant_shard_id/timeline/:timeline_id/page_trace",
3548+
|r| api_handler(r, timeline_page_trace_handler),
3549+
)
34903550
.post("/v1/tenant/:tenant_shard_id/heatmap_upload", |r| {
34913551
api_handler(r, secondary_upload_handler)
34923552
})

0 commit comments

Comments
 (0)