Line data Source code
1 : //! A DeltaLayer represents a collection of WAL records or page images in a range of
2 : //! LSNs, and in a range of Keys. It is stored on a file on disk.
3 : //!
4 : //! Usually a delta layer only contains differences, in the form of WAL records
5 : //! against a base LSN. However, if a relation extended or a whole new relation
6 : //! is created, there would be no base for the new pages. The entries for them
7 : //! must be page images or WAL records with the 'will_init' flag set, so that
8 : //! they can be replayed without referring to an older page version.
9 : //!
10 : //! The delta files are stored in `timelines/<timeline_id>` directory. Currently,
11 : //! there are no subdirectories, and each delta file is named like this:
12 : //!
13 : //! ```text
14 : //! <key start>-<key end>__<start LSN>-<end LSN>
15 : //! ```
16 : //!
17 : //! For example:
18 : //!
19 : //! ```text
20 : //! 000000067F000032BE0000400000000020B6-000000067F000032BE0000400000000030B6__000000578C6B29-0000000057A50051
21 : //! ```
22 : //!
23 : //! Every delta file consists of three parts: "summary", "index", and
24 : //! "values". The summary is a fixed size header at the beginning of the file,
25 : //! and it contains basic information about the layer, and offsets to the other
26 : //! parts. The "index" is a B-tree, mapping from Key and LSN to an offset in the
27 : //! "values" part. The actual page images and WAL records are stored in the
28 : //! "values" part.
29 : //!
30 : use crate::config::PageServerConf;
31 : use crate::context::{PageContentKind, RequestContext, RequestContextBuilder};
32 : use crate::page_cache::PAGE_SZ;
33 : use crate::repository::{Key, Value, KEY_SIZE};
34 : use crate::tenant::blob_io::BlobWriter;
35 : use crate::tenant::block_io::{BlockBuf, BlockCursor, BlockLease, BlockReader, FileBlockReader};
36 : use crate::tenant::disk_btree::{DiskBtreeBuilder, DiskBtreeReader, VisitDirection};
37 : use crate::tenant::storage_layer::{Layer, ValueReconstructResult, ValueReconstructState};
38 : use crate::tenant::Timeline;
39 : use crate::virtual_file::{self, VirtualFile};
40 : use crate::{walrecord, TEMP_FILE_SUFFIX};
41 : use crate::{DELTA_FILE_MAGIC, STORAGE_FORMAT_VERSION};
42 : use anyhow::{bail, ensure, Context, Result};
43 : use camino::{Utf8Path, Utf8PathBuf};
44 : use pageserver_api::models::LayerAccessKind;
45 : use pageserver_api::shard::TenantShardId;
46 : use rand::{distributions::Alphanumeric, Rng};
47 : use serde::{Deserialize, Serialize};
48 : use std::fs::File;
49 : use std::io::SeekFrom;
50 : use std::ops::Range;
51 : use std::os::unix::fs::FileExt;
52 : use std::sync::Arc;
53 : use tokio::sync::OnceCell;
54 : use tracing::*;
55 :
56 : use utils::{
57 : bin_ser::BeSer,
58 : id::{TenantId, TimelineId},
59 : lsn::Lsn,
60 : };
61 :
62 : use super::{AsLayerDesc, LayerAccessStats, PersistentLayerDesc, ResidentLayer};
63 :
64 : ///
65 : /// Header stored in the beginning of the file
66 : ///
67 : /// After this comes the 'values' part, starting on block 1. After that,
68 : /// the 'index' starts at the block indicated by 'index_start_blk'
69 : ///
70 15915 : #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
71 : pub struct Summary {
72 : /// Magic value to identify this as a neon delta file. Always DELTA_FILE_MAGIC.
73 : pub magic: u16,
74 : pub format_version: u16,
75 :
76 : pub tenant_id: TenantId,
77 : pub timeline_id: TimelineId,
78 : pub key_range: Range<Key>,
79 : pub lsn_range: Range<Lsn>,
80 :
81 : /// Block number where the 'index' part of the file begins.
82 : pub index_start_blk: u32,
83 : /// Block within the 'index', where the B-tree root page is stored
84 : pub index_root_blk: u32,
85 : }
86 :
87 : impl From<&DeltaLayer> for Summary {
88 0 : fn from(layer: &DeltaLayer) -> Self {
89 0 : Self::expected(
90 0 : layer.desc.tenant_shard_id.tenant_id,
91 0 : layer.desc.timeline_id,
92 0 : layer.desc.key_range.clone(),
93 0 : layer.desc.lsn_range.clone(),
94 0 : )
95 0 : }
96 : }
97 :
98 : impl Summary {
99 12046 : pub(super) fn expected(
100 12046 : tenant_id: TenantId,
101 12046 : timeline_id: TimelineId,
102 12046 : keys: Range<Key>,
103 12046 : lsns: Range<Lsn>,
104 12046 : ) -> Self {
105 12046 : Self {
106 12046 : magic: DELTA_FILE_MAGIC,
107 12046 : format_version: STORAGE_FORMAT_VERSION,
108 12046 :
109 12046 : tenant_id,
110 12046 : timeline_id,
111 12046 : key_range: keys,
112 12046 : lsn_range: lsns,
113 12046 :
114 12046 : index_start_blk: 0,
115 12046 : index_root_blk: 0,
116 12046 : }
117 12046 : }
118 : }
119 :
120 : // Flag indicating that this version initialize the page
121 : const WILL_INIT: u64 = 1;
122 :
123 : /// Struct representing reference to BLOB in layers. Reference contains BLOB
124 : /// offset, and for WAL records it also contains `will_init` flag. The flag
125 : /// helps to determine the range of records that needs to be applied, without
126 : /// reading/deserializing records themselves.
127 0 : #[derive(Debug, Serialize, Deserialize, Copy, Clone)]
128 : pub struct BlobRef(pub u64);
129 :
130 : impl BlobRef {
131 50446638 : pub fn will_init(&self) -> bool {
132 50446638 : (self.0 & WILL_INIT) != 0
133 50446638 : }
134 :
135 85464521 : pub fn pos(&self) -> u64 {
136 85464521 : self.0 >> 1
137 85464521 : }
138 :
139 52539017 : pub fn new(pos: u64, will_init: bool) -> BlobRef {
140 52539017 : let mut blob_ref = pos << 1;
141 52539017 : if will_init {
142 9483289 : blob_ref |= WILL_INIT;
143 43055728 : }
144 52539017 : BlobRef(blob_ref)
145 52539017 : }
146 : }
147 :
148 : pub const DELTA_KEY_SIZE: usize = KEY_SIZE + 8;
149 : struct DeltaKey([u8; DELTA_KEY_SIZE]);
150 :
151 : /// This is the key of the B-tree index stored in the delta layer. It consists
152 : /// of the serialized representation of a Key and LSN.
153 : impl DeltaKey {
154 17514718 : fn from_slice(buf: &[u8]) -> Self {
155 17514718 : let mut bytes: [u8; DELTA_KEY_SIZE] = [0u8; DELTA_KEY_SIZE];
156 17514718 : bytes.copy_from_slice(buf);
157 17514718 : DeltaKey(bytes)
158 17514718 : }
159 :
160 75338313 : fn from_key_lsn(key: &Key, lsn: Lsn) -> Self {
161 75338313 : let mut bytes: [u8; DELTA_KEY_SIZE] = [0u8; DELTA_KEY_SIZE];
162 75338313 : key.write_to_byte_slice(&mut bytes[0..KEY_SIZE]);
163 75338313 : bytes[KEY_SIZE..].copy_from_slice(&u64::to_be_bytes(lsn.0));
164 75338313 : DeltaKey(bytes)
165 75338313 : }
166 :
167 17514718 : fn key(&self) -> Key {
168 17514718 : Key::from_slice(&self.0)
169 17514718 : }
170 :
171 17514718 : fn lsn(&self) -> Lsn {
172 17514718 : Lsn(u64::from_be_bytes(self.0[KEY_SIZE..].try_into().unwrap()))
173 17514718 : }
174 :
175 50899107 : fn extract_lsn_from_buf(buf: &[u8]) -> Lsn {
176 50899107 : let mut lsn_buf = [0u8; 8];
177 50899107 : lsn_buf.copy_from_slice(&buf[KEY_SIZE..]);
178 50899107 : Lsn(u64::from_be_bytes(lsn_buf))
179 50899107 : }
180 : }
181 :
182 : /// This is used only from `pagectl`. Within pageserver, all layers are
183 : /// [`crate::tenant::storage_layer::Layer`], which can hold a [`DeltaLayerInner`].
184 : pub struct DeltaLayer {
185 : path: Utf8PathBuf,
186 : pub desc: PersistentLayerDesc,
187 : access_stats: LayerAccessStats,
188 : inner: OnceCell<Arc<DeltaLayerInner>>,
189 : }
190 :
191 : impl std::fmt::Debug for DeltaLayer {
192 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193 0 : use super::RangeDisplayDebug;
194 0 :
195 0 : f.debug_struct("DeltaLayer")
196 0 : .field("key_range", &RangeDisplayDebug(&self.desc.key_range))
197 0 : .field("lsn_range", &self.desc.lsn_range)
198 0 : .field("file_size", &self.desc.file_size)
199 0 : .field("inner", &self.inner)
200 0 : .finish()
201 0 : }
202 : }
203 :
204 : /// `DeltaLayerInner` is the in-memory data structure associated with an on-disk delta
205 : /// file.
206 : pub struct DeltaLayerInner {
207 : // values copied from summary
208 : index_start_blk: u32,
209 : index_root_blk: u32,
210 :
211 : /// Reader object for reading blocks from the file.
212 : file: FileBlockReader,
213 : }
214 :
215 : impl std::fmt::Debug for DeltaLayerInner {
216 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 0 : f.debug_struct("DeltaLayerInner")
218 0 : .field("index_start_blk", &self.index_start_blk)
219 0 : .field("index_root_blk", &self.index_root_blk)
220 0 : .finish()
221 0 : }
222 : }
223 :
224 : /// Boilerplate to implement the Layer trait, always use layer_desc for persistent layers.
225 : impl std::fmt::Display for DeltaLayer {
226 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227 0 : write!(f, "{}", self.layer_desc().short_id())
228 0 : }
229 : }
230 :
231 : impl AsLayerDesc for DeltaLayer {
232 0 : fn layer_desc(&self) -> &PersistentLayerDesc {
233 0 : &self.desc
234 0 : }
235 : }
236 :
237 : impl DeltaLayer {
238 0 : pub(crate) async fn dump(&self, verbose: bool, ctx: &RequestContext) -> Result<()> {
239 0 : self.desc.dump();
240 0 :
241 0 : if !verbose {
242 0 : return Ok(());
243 0 : }
244 :
245 0 : let inner = self.load(LayerAccessKind::Dump, ctx).await?;
246 :
247 0 : inner.dump(ctx).await
248 0 : }
249 :
250 15918 : fn temp_path_for(
251 15918 : conf: &PageServerConf,
252 15918 : tenant_shard_id: &TenantShardId,
253 15918 : timeline_id: &TimelineId,
254 15918 : key_start: Key,
255 15918 : lsn_range: &Range<Lsn>,
256 15918 : ) -> Utf8PathBuf {
257 15918 : let rand_string: String = rand::thread_rng()
258 15918 : .sample_iter(&Alphanumeric)
259 15918 : .take(8)
260 15918 : .map(char::from)
261 15918 : .collect();
262 15918 :
263 15918 : conf.timeline_path(tenant_shard_id, timeline_id)
264 15918 : .join(format!(
265 15918 : "{}-XXX__{:016X}-{:016X}.{}.{}",
266 15918 : key_start,
267 15918 : u64::from(lsn_range.start),
268 15918 : u64::from(lsn_range.end),
269 15918 : rand_string,
270 15918 : TEMP_FILE_SUFFIX,
271 15918 : ))
272 15918 : }
273 :
274 : ///
275 : /// Open the underlying file and read the metadata into memory, if it's
276 : /// not loaded already.
277 : ///
278 0 : async fn load(
279 0 : &self,
280 0 : access_kind: LayerAccessKind,
281 0 : ctx: &RequestContext,
282 0 : ) -> Result<&Arc<DeltaLayerInner>> {
283 0 : self.access_stats.record_access(access_kind, ctx);
284 0 : // Quick exit if already loaded
285 0 : self.inner
286 0 : .get_or_try_init(|| self.load_inner(ctx))
287 0 : .await
288 0 : .with_context(|| format!("Failed to load delta layer {}", self.path()))
289 0 : }
290 :
291 0 : async fn load_inner(&self, ctx: &RequestContext) -> Result<Arc<DeltaLayerInner>> {
292 0 : let path = self.path();
293 :
294 0 : let loaded = DeltaLayerInner::load(&path, None, ctx)
295 0 : .await
296 0 : .and_then(|res| res)?;
297 :
298 : // not production code
299 0 : let actual_filename = path.file_name().unwrap().to_owned();
300 0 : let expected_filename = self.layer_desc().filename().file_name();
301 0 :
302 0 : if actual_filename != expected_filename {
303 0 : println!("warning: filename does not match what is expected from in-file summary");
304 0 : println!("actual: {:?}", actual_filename);
305 0 : println!("expected: {:?}", expected_filename);
306 0 : }
307 :
308 0 : Ok(Arc::new(loaded))
309 0 : }
310 :
311 : /// Create a DeltaLayer struct representing an existing file on disk.
312 : ///
313 : /// This variant is only used for debugging purposes, by the 'pagectl' binary.
314 0 : pub fn new_for_path(path: &Utf8Path, file: File) -> Result<Self> {
315 0 : let mut summary_buf = vec![0; PAGE_SZ];
316 0 : file.read_exact_at(&mut summary_buf, 0)?;
317 0 : let summary = Summary::des_prefix(&summary_buf)?;
318 :
319 0 : let metadata = file
320 0 : .metadata()
321 0 : .context("get file metadata to determine size")?;
322 :
323 : // This function is never used for constructing layers in a running pageserver,
324 : // so it does not need an accurate TenantShardId.
325 0 : let tenant_shard_id = TenantShardId::unsharded(summary.tenant_id);
326 0 :
327 0 : Ok(DeltaLayer {
328 0 : path: path.to_path_buf(),
329 0 : desc: PersistentLayerDesc::new_delta(
330 0 : tenant_shard_id,
331 0 : summary.timeline_id,
332 0 : summary.key_range,
333 0 : summary.lsn_range,
334 0 : metadata.len(),
335 0 : ),
336 0 : access_stats: LayerAccessStats::empty_will_record_residence_event_later(),
337 0 : inner: OnceCell::new(),
338 0 : })
339 0 : }
340 :
341 : /// Path to the layer file in pageserver workdir.
342 0 : fn path(&self) -> Utf8PathBuf {
343 0 : self.path.clone()
344 0 : }
345 : }
346 :
347 : /// A builder object for constructing a new delta layer.
348 : ///
349 : /// Usage:
350 : ///
351 : /// 1. Create the DeltaLayerWriter by calling DeltaLayerWriter::new(...)
352 : ///
353 : /// 2. Write the contents by calling `put_value` for every page
354 : /// version to store in the layer.
355 : ///
356 : /// 3. Call `finish`.
357 : ///
358 : struct DeltaLayerWriterInner {
359 : conf: &'static PageServerConf,
360 : pub path: Utf8PathBuf,
361 : timeline_id: TimelineId,
362 : tenant_shard_id: TenantShardId,
363 :
364 : key_start: Key,
365 : lsn_range: Range<Lsn>,
366 :
367 : tree: DiskBtreeBuilder<BlockBuf, DELTA_KEY_SIZE>,
368 :
369 : blob_writer: BlobWriter<true>,
370 : }
371 :
372 : impl DeltaLayerWriterInner {
373 : ///
374 : /// Start building a new delta layer.
375 : ///
376 15918 : async fn new(
377 15918 : conf: &'static PageServerConf,
378 15918 : timeline_id: TimelineId,
379 15918 : tenant_shard_id: TenantShardId,
380 15918 : key_start: Key,
381 15918 : lsn_range: Range<Lsn>,
382 15918 : ) -> anyhow::Result<Self> {
383 15918 : // Create the file initially with a temporary filename. We don't know
384 15918 : // the end key yet, so we cannot form the final filename yet. We will
385 15918 : // rename it when we're done.
386 15918 : //
387 15918 : // Note: This overwrites any existing file. There shouldn't be any.
388 15918 : // FIXME: throw an error instead?
389 15918 : let path =
390 15918 : DeltaLayer::temp_path_for(conf, &tenant_shard_id, &timeline_id, key_start, &lsn_range);
391 :
392 15918 : let mut file = VirtualFile::create(&path).await?;
393 : // make room for the header block
394 15918 : file.seek(SeekFrom::Start(PAGE_SZ as u64)).await?;
395 15918 : let blob_writer = BlobWriter::new(file, PAGE_SZ as u64);
396 15918 :
397 15918 : // Initialize the b-tree index builder
398 15918 : let block_buf = BlockBuf::new();
399 15918 : let tree_builder = DiskBtreeBuilder::new(block_buf);
400 15918 :
401 15918 : Ok(Self {
402 15918 : conf,
403 15918 : path,
404 15918 : timeline_id,
405 15918 : tenant_shard_id,
406 15918 : key_start,
407 15918 : lsn_range,
408 15918 : tree: tree_builder,
409 15918 : blob_writer,
410 15918 : })
411 15918 : }
412 :
413 : ///
414 : /// Append a key-value pair to the file.
415 : ///
416 : /// The values must be appended in key, lsn order.
417 : ///
418 17503157 : async fn put_value(&mut self, key: Key, lsn: Lsn, val: Value) -> anyhow::Result<()> {
419 17503157 : self.put_value_bytes(key, lsn, &Value::ser(&val)?, val.will_init())
420 21523 : .await
421 17503157 : }
422 :
423 52539018 : async fn put_value_bytes(
424 52539018 : &mut self,
425 52539018 : key: Key,
426 52539018 : lsn: Lsn,
427 52539018 : val: &[u8],
428 52539018 : will_init: bool,
429 52539018 : ) -> anyhow::Result<()> {
430 52539017 : assert!(self.lsn_range.start <= lsn);
431 :
432 52539017 : let off = self.blob_writer.write_blob(val).await?;
433 :
434 52539016 : let blob_ref = BlobRef::new(off, will_init);
435 52539016 :
436 52539016 : let delta_key = DeltaKey::from_key_lsn(&key, lsn);
437 52539016 : self.tree.append(&delta_key.0, blob_ref.0)?;
438 :
439 52539016 : Ok(())
440 52539016 : }
441 :
442 2373630 : fn size(&self) -> u64 {
443 2373630 : self.blob_writer.size() + self.tree.borrow_writer().size()
444 2373630 : }
445 :
446 : ///
447 : /// Finish writing the delta layer.
448 : ///
449 15915 : async fn finish(self, key_end: Key, timeline: &Arc<Timeline>) -> anyhow::Result<ResidentLayer> {
450 15915 : let index_start_blk =
451 15915 : ((self.blob_writer.size() + PAGE_SZ as u64 - 1) / PAGE_SZ as u64) as u32;
452 :
453 15915 : let mut file = self.blob_writer.into_inner().await?;
454 :
455 : // Write out the index
456 15915 : let (index_root_blk, block_buf) = self.tree.finish()?;
457 15915 : file.seek(SeekFrom::Start(index_start_blk as u64 * PAGE_SZ as u64))
458 0 : .await?;
459 131163 : for buf in block_buf.blocks {
460 115248 : file.write_all(buf.as_ref()).await?;
461 : }
462 15915 : assert!(self.lsn_range.start < self.lsn_range.end);
463 : // Fill in the summary on blk 0
464 15915 : let summary = Summary {
465 15915 : magic: DELTA_FILE_MAGIC,
466 15915 : format_version: STORAGE_FORMAT_VERSION,
467 15915 : tenant_id: self.tenant_shard_id.tenant_id,
468 15915 : timeline_id: self.timeline_id,
469 15915 : key_range: self.key_start..key_end,
470 15915 : lsn_range: self.lsn_range.clone(),
471 15915 : index_start_blk,
472 15915 : index_root_blk,
473 15915 : };
474 15915 :
475 15915 : let mut buf = smallvec::SmallVec::<[u8; PAGE_SZ]>::new();
476 15915 : Summary::ser_into(&summary, &mut buf)?;
477 15915 : if buf.spilled() {
478 : // This is bad as we only have one free block for the summary
479 0 : warn!(
480 0 : "Used more than one page size for summary buffer: {}",
481 0 : buf.len()
482 0 : );
483 15915 : }
484 15915 : file.seek(SeekFrom::Start(0)).await?;
485 15915 : file.write_all(&buf).await?;
486 :
487 15915 : let metadata = file
488 15915 : .metadata()
489 243 : .await
490 15915 : .context("get file metadata to determine size")?;
491 :
492 : // 5GB limit for objects without multipart upload (which we don't want to use)
493 : // Make it a little bit below to account for differing GB units
494 : // https://docs.aws.amazon.com/AmazonS3/latest/userguide/upload-objects.html
495 : const S3_UPLOAD_LIMIT: u64 = 4_500_000_000;
496 : ensure!(
497 15915 : metadata.len() <= S3_UPLOAD_LIMIT,
498 0 : "Created delta layer file at {} of size {} above limit {S3_UPLOAD_LIMIT}!",
499 0 : file.path,
500 0 : metadata.len()
501 : );
502 :
503 : // Note: Because we opened the file in write-only mode, we cannot
504 : // reuse the same VirtualFile for reading later. That's why we don't
505 : // set inner.file here. The first read will have to re-open it.
506 :
507 15915 : let desc = PersistentLayerDesc::new_delta(
508 15915 : self.tenant_shard_id,
509 15915 : self.timeline_id,
510 15915 : self.key_start..key_end,
511 15915 : self.lsn_range.clone(),
512 15915 : metadata.len(),
513 15915 : );
514 15915 :
515 15915 : // fsync the file
516 15915 : file.sync_all().await?;
517 :
518 15915 : let layer = Layer::finish_creating(self.conf, timeline, desc, &self.path)?;
519 :
520 0 : trace!("created delta layer {}", layer.local_path());
521 :
522 15915 : Ok(layer)
523 15915 : }
524 : }
525 :
526 : /// A builder object for constructing a new delta layer.
527 : ///
528 : /// Usage:
529 : ///
530 : /// 1. Create the DeltaLayerWriter by calling DeltaLayerWriter::new(...)
531 : ///
532 : /// 2. Write the contents by calling `put_value` for every page
533 : /// version to store in the layer.
534 : ///
535 : /// 3. Call `finish`.
536 : ///
537 : /// # Note
538 : ///
539 : /// As described in <https://github.com/neondatabase/neon/issues/2650>, it's
540 : /// possible for the writer to drop before `finish` is actually called. So this
541 : /// could lead to odd temporary files in the directory, exhausting file system.
542 : /// This structure wraps `DeltaLayerWriterInner` and also contains `Drop`
543 : /// implementation that cleans up the temporary file in failure. It's not
544 : /// possible to do this directly in `DeltaLayerWriterInner` since `finish` moves
545 : /// out some fields, making it impossible to implement `Drop`.
546 : ///
547 : #[must_use]
548 : pub struct DeltaLayerWriter {
549 : inner: Option<DeltaLayerWriterInner>,
550 : }
551 :
552 : impl DeltaLayerWriter {
553 : ///
554 : /// Start building a new delta layer.
555 : ///
556 15918 : pub async fn new(
557 15918 : conf: &'static PageServerConf,
558 15918 : timeline_id: TimelineId,
559 15918 : tenant_shard_id: TenantShardId,
560 15918 : key_start: Key,
561 15918 : lsn_range: Range<Lsn>,
562 15918 : ) -> anyhow::Result<Self> {
563 15918 : Ok(Self {
564 15918 : inner: Some(
565 15918 : DeltaLayerWriterInner::new(
566 15918 : conf,
567 15918 : timeline_id,
568 15918 : tenant_shard_id,
569 15918 : key_start,
570 15918 : lsn_range,
571 15918 : )
572 215 : .await?,
573 : ),
574 : })
575 15918 : }
576 :
577 : ///
578 : /// Append a key-value pair to the file.
579 : ///
580 : /// The values must be appended in key, lsn order.
581 : ///
582 17503157 : pub async fn put_value(&mut self, key: Key, lsn: Lsn, val: Value) -> anyhow::Result<()> {
583 17503157 : self.inner.as_mut().unwrap().put_value(key, lsn, val).await
584 17503157 : }
585 :
586 35035861 : pub async fn put_value_bytes(
587 35035861 : &mut self,
588 35035861 : key: Key,
589 35035861 : lsn: Lsn,
590 35035861 : val: &[u8],
591 35035861 : will_init: bool,
592 35035861 : ) -> anyhow::Result<()> {
593 35035860 : self.inner
594 35035860 : .as_mut()
595 35035860 : .unwrap()
596 35035860 : .put_value_bytes(key, lsn, val, will_init)
597 48979 : .await
598 35035859 : }
599 :
600 2373630 : pub fn size(&self) -> u64 {
601 2373630 : self.inner.as_ref().unwrap().size()
602 2373630 : }
603 :
604 : ///
605 : /// Finish writing the delta layer.
606 : ///
607 15915 : pub(crate) async fn finish(
608 15915 : mut self,
609 15915 : key_end: Key,
610 15915 : timeline: &Arc<Timeline>,
611 15915 : ) -> anyhow::Result<ResidentLayer> {
612 15915 : let inner = self.inner.take().unwrap();
613 15915 : let temp_path = inner.path.clone();
614 15915 : let result = inner.finish(key_end, timeline).await;
615 : // The delta layer files can sometimes be really large. Clean them up.
616 15915 : if result.is_err() {
617 0 : tracing::warn!(
618 0 : "Cleaning up temporary delta file {temp_path} after error during writing"
619 0 : );
620 0 : if let Err(e) = std::fs::remove_file(&temp_path) {
621 0 : tracing::warn!("Error cleaning up temporary delta layer file {temp_path}: {e:?}")
622 0 : }
623 15915 : }
624 15915 : result
625 15915 : }
626 : }
627 :
628 : impl Drop for DeltaLayerWriter {
629 15915 : fn drop(&mut self) {
630 15915 : if let Some(inner) = self.inner.take() {
631 0 : // We want to remove the virtual file here, so it's fine to not
632 0 : // having completely flushed unwritten data.
633 0 : let vfile = inner.blob_writer.into_inner_no_flush();
634 0 : vfile.remove();
635 15915 : }
636 15915 : }
637 : }
638 :
639 0 : #[derive(thiserror::Error, Debug)]
640 : pub enum RewriteSummaryError {
641 : #[error("magic mismatch")]
642 : MagicMismatch,
643 : #[error(transparent)]
644 : Other(#[from] anyhow::Error),
645 : }
646 :
647 : impl From<std::io::Error> for RewriteSummaryError {
648 0 : fn from(e: std::io::Error) -> Self {
649 0 : Self::Other(anyhow::anyhow!(e))
650 0 : }
651 : }
652 :
653 : impl DeltaLayer {
654 0 : pub async fn rewrite_summary<F>(
655 0 : path: &Utf8Path,
656 0 : rewrite: F,
657 0 : ctx: &RequestContext,
658 0 : ) -> Result<(), RewriteSummaryError>
659 0 : where
660 0 : F: Fn(Summary) -> Summary,
661 0 : {
662 0 : let file = VirtualFile::open_with_options(
663 0 : path,
664 0 : virtual_file::OpenOptions::new().read(true).write(true),
665 0 : )
666 0 : .await
667 0 : .with_context(|| format!("Failed to open file '{}'", path))?;
668 0 : let file = FileBlockReader::new(file);
669 0 : let summary_blk = file.read_blk(0, ctx).await?;
670 0 : let actual_summary = Summary::des_prefix(summary_blk.as_ref()).context("deserialize")?;
671 0 : let mut file = file.file;
672 0 : if actual_summary.magic != DELTA_FILE_MAGIC {
673 0 : return Err(RewriteSummaryError::MagicMismatch);
674 0 : }
675 0 :
676 0 : let new_summary = rewrite(actual_summary);
677 0 :
678 0 : let mut buf = smallvec::SmallVec::<[u8; PAGE_SZ]>::new();
679 0 : Summary::ser_into(&new_summary, &mut buf).context("serialize")?;
680 0 : if buf.spilled() {
681 : // The code in DeltaLayerWriterInner just warn!()s for this.
682 : // It should probably error out as well.
683 0 : return Err(RewriteSummaryError::Other(anyhow::anyhow!(
684 0 : "Used more than one page size for summary buffer: {}",
685 0 : buf.len()
686 0 : )));
687 0 : }
688 0 : file.seek(SeekFrom::Start(0)).await?;
689 0 : file.write_all(&buf).await?;
690 0 : Ok(())
691 0 : }
692 : }
693 :
694 : impl DeltaLayerInner {
695 : /// Returns nested result following Result<Result<_, OpErr>, Critical>:
696 : /// - inner has the success or transient failure
697 : /// - outer has the permanent failure
698 12046 : pub(super) async fn load(
699 12046 : path: &Utf8Path,
700 12046 : summary: Option<Summary>,
701 12046 : ctx: &RequestContext,
702 12046 : ) -> Result<Result<Self, anyhow::Error>, anyhow::Error> {
703 12046 : let file = match VirtualFile::open(path).await {
704 12046 : Ok(file) => file,
705 0 : Err(e) => return Ok(Err(anyhow::Error::new(e).context("open layer file"))),
706 : };
707 12046 : let file = FileBlockReader::new(file);
708 :
709 12046 : let summary_blk = match file.read_blk(0, ctx).await {
710 12046 : Ok(blk) => blk,
711 0 : Err(e) => return Ok(Err(anyhow::Error::new(e).context("read first block"))),
712 : };
713 :
714 : // TODO: this should be an assertion instead; see ImageLayerInner::load
715 12046 : let actual_summary =
716 12046 : Summary::des_prefix(summary_blk.as_ref()).context("deserialize first block")?;
717 :
718 12046 : if let Some(mut expected_summary) = summary {
719 : // production code path
720 12046 : expected_summary.index_start_blk = actual_summary.index_start_blk;
721 12046 : expected_summary.index_root_blk = actual_summary.index_root_blk;
722 12046 : if actual_summary != expected_summary {
723 1 : bail!(
724 1 : "in-file summary does not match expected summary. actual = {:?} expected = {:?}",
725 1 : actual_summary,
726 1 : expected_summary
727 1 : );
728 12045 : }
729 0 : }
730 :
731 12045 : Ok(Ok(DeltaLayerInner {
732 12045 : file,
733 12045 : index_start_blk: actual_summary.index_start_blk,
734 12045 : index_root_blk: actual_summary.index_root_blk,
735 12045 : }))
736 12046 : }
737 :
738 22799296 : pub(super) async fn get_value_reconstruct_data(
739 22799296 : &self,
740 22799296 : key: Key,
741 22799296 : lsn_range: Range<Lsn>,
742 22799296 : reconstruct_state: &mut ValueReconstructState,
743 22799296 : ctx: &RequestContext,
744 22799296 : ) -> anyhow::Result<ValueReconstructResult> {
745 22799296 : let mut need_image = true;
746 22799296 : // Scan the page versions backwards, starting from `lsn`.
747 22799296 : let file = &self.file;
748 22799296 : let tree_reader = DiskBtreeReader::<_, DELTA_KEY_SIZE>::new(
749 22799296 : self.index_start_blk,
750 22799296 : self.index_root_blk,
751 22799296 : file,
752 22799296 : );
753 22799296 : let search_key = DeltaKey::from_key_lsn(&key, Lsn(lsn_range.end.0 - 1));
754 22799296 :
755 22799296 : let mut offsets: Vec<(Lsn, u64)> = Vec::new();
756 22799296 :
757 22799296 : tree_reader
758 22799296 : .visit(
759 22799296 : &search_key.0,
760 22799296 : VisitDirection::Backwards,
761 56989198 : |key, value| {
762 56989198 : let blob_ref = BlobRef(value);
763 56989198 : if key[..KEY_SIZE] != search_key.0[..KEY_SIZE] {
764 6090093 : return false;
765 50899105 : }
766 50899105 : let entry_lsn = DeltaKey::extract_lsn_from_buf(key);
767 50899105 : if entry_lsn < lsn_range.start {
768 452469 : return false;
769 50446636 : }
770 50446636 : offsets.push((entry_lsn, blob_ref.pos()));
771 50446636 :
772 50446636 : !blob_ref.will_init()
773 56989198 : },
774 22799296 : &RequestContextBuilder::extend(ctx)
775 22799296 : .page_content_kind(PageContentKind::DeltaLayerBtreeNode)
776 22799296 : .build(),
777 22799296 : )
778 239895 : .await?;
779 :
780 22799294 : let ctx = &RequestContextBuilder::extend(ctx)
781 22799294 : .page_content_kind(PageContentKind::DeltaLayerValue)
782 22799294 : .build();
783 22799294 :
784 22799294 : // Ok, 'offsets' now contains the offsets of all the entries we need to read
785 22799294 : let cursor = file.block_cursor();
786 22799294 : let mut buf = Vec::new();
787 69615466 : for (entry_lsn, pos) in offsets {
788 50445168 : cursor
789 50445168 : .read_blob_into_buf(pos, &mut buf, ctx)
790 756004 : .await
791 50445168 : .with_context(|| {
792 0 : format!("Failed to read blob from virtual file {}", file.file.path)
793 50445168 : })?;
794 50445168 : let val = Value::des(&buf).with_context(|| {
795 0 : format!(
796 0 : "Failed to deserialize file blob from virtual file {}",
797 0 : file.file.path
798 0 : )
799 50445168 : })?;
800 50445168 : match val {
801 1913726 : Value::Image(img) => {
802 1913726 : reconstruct_state.img = Some((entry_lsn, img));
803 1913726 : need_image = false;
804 1913726 : break;
805 : }
806 48531442 : Value::WalRecord(rec) => {
807 48531442 : let will_init = rec.will_init();
808 48531442 : reconstruct_state.records.push((entry_lsn, rec));
809 48531442 : if will_init {
810 : // This WAL record initializes the page, so no need to go further back
811 1715270 : need_image = false;
812 1715270 : break;
813 46816172 : }
814 : }
815 : }
816 : }
817 :
818 : // If an older page image is needed to reconstruct the page, let the
819 : // caller know.
820 22799294 : if need_image {
821 19170298 : Ok(ValueReconstructResult::Continue)
822 : } else {
823 3628995 : Ok(ValueReconstructResult::Complete)
824 : }
825 22799293 : }
826 :
827 4232 : pub(super) async fn load_keys<'a>(
828 4232 : &'a self,
829 4232 : ctx: &RequestContext,
830 4232 : ) -> Result<Vec<DeltaEntry<'a>>> {
831 4232 : let file = &self.file;
832 4232 :
833 4232 : let tree_reader = DiskBtreeReader::<_, DELTA_KEY_SIZE>::new(
834 4232 : self.index_start_blk,
835 4232 : self.index_root_blk,
836 4232 : file,
837 4232 : );
838 4232 :
839 4232 : let mut all_keys: Vec<DeltaEntry<'_>> = Vec::new();
840 4232 :
841 4232 : tree_reader
842 4232 : .visit(
843 4232 : &[0u8; DELTA_KEY_SIZE],
844 4232 : VisitDirection::Forwards,
845 17514718 : |key, value| {
846 17514718 : let delta_key = DeltaKey::from_slice(key);
847 17514718 : let val_ref = ValueRef {
848 17514718 : blob_ref: BlobRef(value),
849 17514718 : reader: BlockCursor::new(crate::tenant::block_io::BlockReaderRef::Adapter(
850 17514718 : Adapter(self),
851 17514718 : )),
852 17514718 : };
853 17514718 : let pos = BlobRef(value).pos();
854 17514718 : if let Some(last) = all_keys.last_mut() {
855 17510486 : // subtract offset of the current and last entries to get the size
856 17510486 : // of the value associated with this (key, lsn) tuple
857 17510486 : let first_pos = last.size;
858 17510486 : last.size = pos - first_pos;
859 17510486 : }
860 17514718 : let entry = DeltaEntry {
861 17514718 : key: delta_key.key(),
862 17514718 : lsn: delta_key.lsn(),
863 17514718 : size: pos,
864 17514718 : val: val_ref,
865 17514718 : };
866 17514718 : all_keys.push(entry);
867 17514718 : true
868 17514718 : },
869 4232 : &RequestContextBuilder::extend(ctx)
870 4232 : .page_content_kind(PageContentKind::DeltaLayerBtreeNode)
871 4232 : .build(),
872 4232 : )
873 2320 : .await?;
874 4232 : if let Some(last) = all_keys.last_mut() {
875 4232 : // Last key occupies all space till end of value storage,
876 4232 : // which corresponds to beginning of the index
877 4232 : last.size = self.index_start_blk as u64 * PAGE_SZ as u64 - last.size;
878 4232 : }
879 4232 : Ok(all_keys)
880 4232 : }
881 :
882 4 : pub(super) async fn dump(&self, ctx: &RequestContext) -> anyhow::Result<()> {
883 4 : println!(
884 4 : "index_start_blk: {}, root {}",
885 4 : self.index_start_blk, self.index_root_blk
886 4 : );
887 4 :
888 4 : let file = &self.file;
889 4 : let tree_reader = DiskBtreeReader::<_, DELTA_KEY_SIZE>::new(
890 4 : self.index_start_blk,
891 4 : self.index_root_blk,
892 4 : file,
893 4 : );
894 4 :
895 4 : tree_reader.dump().await?;
896 :
897 4 : let keys = self.load_keys(ctx).await?;
898 :
899 8 : async fn dump_blob(val: &ValueRef<'_>, ctx: &RequestContext) -> anyhow::Result<String> {
900 8 : let buf = val.reader.read_blob(val.blob_ref.pos(), ctx).await?;
901 8 : let val = Value::des(&buf)?;
902 8 : let desc = match val {
903 8 : Value::Image(img) => {
904 8 : format!(" img {} bytes", img.len())
905 : }
906 0 : Value::WalRecord(rec) => {
907 0 : let wal_desc = walrecord::describe_wal_record(&rec)?;
908 0 : format!(
909 0 : " rec {} bytes will_init: {} {}",
910 0 : buf.len(),
911 0 : rec.will_init(),
912 0 : wal_desc
913 0 : )
914 : }
915 : };
916 8 : Ok(desc)
917 8 : }
918 :
919 12 : for entry in keys {
920 8 : let DeltaEntry { key, lsn, val, .. } = entry;
921 8 : let desc = match dump_blob(&val, ctx).await {
922 8 : Ok(desc) => desc,
923 0 : Err(err) => {
924 0 : format!("ERROR: {err}")
925 : }
926 : };
927 8 : println!(" key {key} at {lsn}: {desc}");
928 8 :
929 8 : // Print more details about CHECKPOINT records. Would be nice to print details
930 8 : // of many other record types too, but these are particularly interesting, as
931 8 : // have a lot of special processing for them in walingest.rs.
932 8 : use pageserver_api::key::CHECKPOINT_KEY;
933 8 : use postgres_ffi::CheckPoint;
934 8 : if key == CHECKPOINT_KEY {
935 0 : let buf = val.reader.read_blob(val.blob_ref.pos(), ctx).await?;
936 0 : let val = Value::des(&buf)?;
937 0 : match val {
938 0 : Value::Image(img) => {
939 0 : let checkpoint = CheckPoint::decode(&img)?;
940 0 : println!(" CHECKPOINT: {:?}", checkpoint);
941 : }
942 0 : Value::WalRecord(_rec) => {
943 0 : println!(" unexpected walrecord value for checkpoint key");
944 0 : }
945 : }
946 8 : }
947 : }
948 :
949 4 : Ok(())
950 4 : }
951 : }
952 :
953 : /// A set of data associated with a delta layer key and its value
954 : pub struct DeltaEntry<'a> {
955 : pub key: Key,
956 : pub lsn: Lsn,
957 : /// Size of the stored value
958 : pub size: u64,
959 : /// Reference to the on-disk value
960 : pub val: ValueRef<'a>,
961 : }
962 :
963 : /// Reference to an on-disk value
964 : pub struct ValueRef<'a> {
965 : blob_ref: BlobRef,
966 : reader: BlockCursor<'a>,
967 : }
968 :
969 : impl<'a> ValueRef<'a> {
970 : /// Loads the value from disk
971 17503157 : pub async fn load(&self, ctx: &RequestContext) -> Result<Value> {
972 : // theoretically we *could* record an access time for each, but it does not really matter
973 17503157 : let buf = self.reader.read_blob(self.blob_ref.pos(), ctx).await?;
974 17503157 : let val = Value::des(&buf)?;
975 17503157 : Ok(val)
976 17503157 : }
977 : }
978 :
979 : pub(crate) struct Adapter<T>(T);
980 :
981 : impl<T: AsRef<DeltaLayerInner>> Adapter<T> {
982 18879676 : pub(crate) async fn read_blk(
983 18879676 : &self,
984 18879676 : blknum: u32,
985 18879676 : ctx: &RequestContext,
986 18879676 : ) -> Result<BlockLease, std::io::Error> {
987 18879676 : self.0.as_ref().file.read_blk(blknum, ctx).await
988 18879676 : }
989 : }
990 :
991 : impl AsRef<DeltaLayerInner> for DeltaLayerInner {
992 18879676 : fn as_ref(&self) -> &DeltaLayerInner {
993 18879676 : self
994 18879676 : }
995 : }
|