Line data Source code
1 : use crate::walrecord::NeonWalRecord;
2 : use anyhow::Result;
3 : use bytes::Bytes;
4 : use serde::{Deserialize, Serialize};
5 : use std::ops::AddAssign;
6 : use std::time::Duration;
7 :
8 : pub use pageserver_api::key::{Key, KEY_SIZE};
9 :
10 : /// A 'value' stored for a one Key.
11 273509500 : #[derive(Debug, Clone, Serialize, Deserialize)]
12 4 : #[cfg_attr(test, derive(PartialEq))]
13 : pub enum Value {
14 : /// An Image value contains a full copy of the value
15 : Image(Bytes),
16 : /// A WalRecord value contains a WAL record that needs to be
17 : /// replayed get the full value. Replaying the WAL record
18 : /// might need a previous version of the value (if will_init()
19 : /// returns false), or it may be replayed stand-alone (true).
20 : WalRecord(NeonWalRecord),
21 : }
22 :
23 : impl Value {
24 0 : pub fn is_image(&self) -> bool {
25 0 : matches!(self, Value::Image(_))
26 0 : }
27 :
28 52098905 : pub fn will_init(&self) -> bool {
29 52098905 : match self {
30 7172359 : Value::Image(_) => true,
31 44926546 : Value::WalRecord(rec) => rec.will_init(),
32 : }
33 52098905 : }
34 : }
35 :
36 : #[cfg(test)]
37 : mod test {
38 : use super::*;
39 :
40 : use bytes::Bytes;
41 : use utils::bin_ser::BeSer;
42 :
43 : macro_rules! roundtrip {
44 : ($orig:expr, $expected:expr) => {{
45 : let orig: Value = $orig;
46 :
47 : let actual = Value::ser(&orig).unwrap();
48 : let expected: &[u8] = &$expected;
49 :
50 : assert_eq!(utils::Hex(&actual), utils::Hex(expected));
51 :
52 : let deser = Value::des(&actual).unwrap();
53 :
54 : assert_eq!(orig, deser);
55 : }};
56 : }
57 :
58 2 : #[test]
59 2 : fn image_roundtrip() {
60 2 : let image = Bytes::from_static(b"foobar");
61 2 : let image = Value::Image(image);
62 2 :
63 2 : #[rustfmt::skip]
64 2 : let expected = [
65 2 : // top level discriminator of 4 bytes
66 2 : 0x00, 0x00, 0x00, 0x00,
67 2 : // 8 byte length
68 2 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
69 2 : // foobar
70 2 : 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72
71 2 : ];
72 2 :
73 2 : roundtrip!(image, expected);
74 2 : }
75 :
76 2 : #[test]
77 2 : fn walrecord_postgres_roundtrip() {
78 2 : let rec = NeonWalRecord::Postgres {
79 2 : will_init: true,
80 2 : rec: Bytes::from_static(b"foobar"),
81 2 : };
82 2 : let rec = Value::WalRecord(rec);
83 2 :
84 2 : #[rustfmt::skip]
85 2 : let expected = [
86 2 : // flattened discriminator of total 8 bytes
87 2 : 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
88 2 : // will_init
89 2 : 0x01,
90 2 : // 8 byte length
91 2 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
92 2 : // foobar
93 2 : 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72
94 2 : ];
95 2 :
96 2 : roundtrip!(rec, expected);
97 2 : }
98 : }
99 :
100 : ///
101 : /// Result of performing GC
102 : ///
103 1201 : #[derive(Default, Serialize, Debug)]
104 : pub struct GcResult {
105 : pub layers_total: u64,
106 : pub layers_needed_by_cutoff: u64,
107 : pub layers_needed_by_pitr: u64,
108 : pub layers_needed_by_branches: u64,
109 : pub layers_not_updated: u64,
110 : pub layers_removed: u64, // # of layer files removed because they have been made obsolete by newer ondisk files.
111 :
112 : #[serde(serialize_with = "serialize_duration_as_millis")]
113 : pub elapsed: Duration,
114 :
115 : /// The layers which were garbage collected.
116 : ///
117 : /// Used in `/v1/tenant/:tenant_id/timeline/:timeline_id/do_gc` to wait for the layers to be
118 : /// dropped in tests.
119 : #[cfg(feature = "testing")]
120 : #[serde(skip)]
121 : pub(crate) doomed_layers: Vec<crate::tenant::storage_layer::Layer>,
122 : }
123 :
124 : // helper function for `GcResult`, serializing a `Duration` as an integer number of milliseconds
125 372 : fn serialize_duration_as_millis<S>(d: &Duration, serializer: S) -> Result<S::Ok, S::Error>
126 372 : where
127 372 : S: serde::Serializer,
128 372 : {
129 372 : d.as_millis().serialize(serializer)
130 372 : }
131 :
132 : impl AddAssign for GcResult {
133 496 : fn add_assign(&mut self, other: Self) {
134 496 : self.layers_total += other.layers_total;
135 496 : self.layers_needed_by_pitr += other.layers_needed_by_pitr;
136 496 : self.layers_needed_by_cutoff += other.layers_needed_by_cutoff;
137 496 : self.layers_needed_by_branches += other.layers_needed_by_branches;
138 496 : self.layers_not_updated += other.layers_not_updated;
139 496 : self.layers_removed += other.layers_removed;
140 496 :
141 496 : self.elapsed += other.elapsed;
142 496 :
143 496 : #[cfg(feature = "testing")]
144 496 : {
145 496 : let mut other = other;
146 496 : self.doomed_layers.append(&mut other.doomed_layers);
147 496 : }
148 496 : }
149 : }
|