Line data Source code
1 : use anyhow::{bail, Result};
2 : use byteorder::{ByteOrder, BE};
3 : use postgres_ffi::relfile_utils::{FSM_FORKNUM, VISIBILITYMAP_FORKNUM};
4 : use postgres_ffi::RepOriginId;
5 : use postgres_ffi::{Oid, TransactionId};
6 : use serde::{Deserialize, Serialize};
7 : use std::{fmt, ops::Range};
8 :
9 : use crate::reltag::{BlockNumber, RelTag, SlruKind};
10 :
11 : /// Key used in the Repository kv-store.
12 : ///
13 : /// The Repository treats this as an opaque struct, but see the code in pgdatadir_mapping.rs
14 : /// for what we actually store in these fields.
15 6864 : #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize)]
16 : pub struct Key {
17 : pub field1: u8,
18 : pub field2: u32,
19 : pub field3: u32,
20 : pub field4: u32,
21 : pub field5: u8,
22 : pub field6: u32,
23 : }
24 :
25 : /// When working with large numbers of Keys in-memory, it is more efficient to handle them as i128 than as
26 : /// a struct of fields.
27 : #[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd)]
28 : pub struct CompactKey(i128);
29 :
30 : /// The storage key size.
31 : pub const KEY_SIZE: usize = 18;
32 :
33 : /// The metadata key size. 2B fewer than the storage key size because field2 is not fully utilized.
34 : /// See [`Key::to_i128`] for more information on the encoding.
35 : pub const METADATA_KEY_SIZE: usize = 16;
36 :
37 : /// The key prefix start range for the metadata keys. All keys with the first byte >= 0x60 is a metadata key.
38 : pub const METADATA_KEY_BEGIN_PREFIX: u8 = 0x60;
39 : pub const METADATA_KEY_END_PREFIX: u8 = 0x7F;
40 :
41 : /// The (reserved) key prefix of relation sizes.
42 : pub const RELATION_SIZE_PREFIX: u8 = 0x61;
43 :
44 : /// The key prefix of AUX file keys.
45 : pub const AUX_KEY_PREFIX: u8 = 0x62;
46 :
47 : /// The key prefix of ReplOrigin keys.
48 : pub const REPL_ORIGIN_KEY_PREFIX: u8 = 0x63;
49 :
50 : /// Check if the key falls in the range of metadata keys.
51 122 : pub const fn is_metadata_key_slice(key: &[u8]) -> bool {
52 122 : key[0] >= METADATA_KEY_BEGIN_PREFIX && key[0] < METADATA_KEY_END_PREFIX
53 122 : }
54 :
55 : impl Key {
56 : /// Check if the key falls in the range of metadata keys.
57 199 : pub const fn is_metadata_key(&self) -> bool {
58 199 : self.field1 >= METADATA_KEY_BEGIN_PREFIX && self.field1 < METADATA_KEY_END_PREFIX
59 199 : }
60 :
61 : /// Encode a metadata key to a storage key.
62 121 : pub fn from_metadata_key_fixed_size(key: &[u8; METADATA_KEY_SIZE]) -> Self {
63 121 : assert!(is_metadata_key_slice(key), "key not in metadata key range");
64 : // Metadata key space ends at 0x7F so it's fine to directly convert it to i128.
65 121 : Self::from_i128(i128::from_be_bytes(*key))
66 121 : }
67 :
68 : /// Encode a metadata key to a storage key.
69 1 : pub fn from_metadata_key(key: &[u8]) -> Self {
70 1 : Self::from_metadata_key_fixed_size(key.try_into().expect("expect 16 byte metadata key"))
71 1 : }
72 :
73 : /// Get the range of metadata keys.
74 3288 : pub const fn metadata_key_range() -> Range<Self> {
75 3288 : Key {
76 3288 : field1: METADATA_KEY_BEGIN_PREFIX,
77 3288 : field2: 0,
78 3288 : field3: 0,
79 3288 : field4: 0,
80 3288 : field5: 0,
81 3288 : field6: 0,
82 3288 : }..Key {
83 3288 : field1: METADATA_KEY_END_PREFIX,
84 3288 : field2: 0,
85 3288 : field3: 0,
86 3288 : field4: 0,
87 3288 : field5: 0,
88 3288 : field6: 0,
89 3288 : }
90 3288 : }
91 :
92 : /// Get the range of aux keys.
93 936 : pub fn metadata_aux_key_range() -> Range<Self> {
94 936 : Key {
95 936 : field1: AUX_KEY_PREFIX,
96 936 : field2: 0,
97 936 : field3: 0,
98 936 : field4: 0,
99 936 : field5: 0,
100 936 : field6: 0,
101 936 : }..Key {
102 936 : field1: AUX_KEY_PREFIX + 1,
103 936 : field2: 0,
104 936 : field3: 0,
105 936 : field4: 0,
106 936 : field5: 0,
107 936 : field6: 0,
108 936 : }
109 936 : }
110 :
111 : /// This function checks more extensively what keys we can take on the write path.
112 : /// If a key beginning with 00 does not have a global/default tablespace OID, it
113 : /// will be rejected on the write path.
114 : #[allow(dead_code)]
115 0 : pub fn is_valid_key_on_write_path_strong(&self) -> bool {
116 0 : use postgres_ffi::pg_constants::{DEFAULTTABLESPACE_OID, GLOBALTABLESPACE_OID};
117 0 : if !self.is_i128_representable() {
118 0 : return false;
119 0 : }
120 0 : if self.field1 == 0
121 0 : && !(self.field2 == GLOBALTABLESPACE_OID
122 0 : || self.field2 == DEFAULTTABLESPACE_OID
123 0 : || self.field2 == 0)
124 : {
125 0 : return false; // User defined tablespaces are not supported
126 0 : }
127 0 : true
128 0 : }
129 :
130 : /// This is a weaker version of `is_valid_key_on_write_path_strong` that simply
131 : /// checks if the key is i128 representable. Note that some keys can be successfully
132 : /// ingested into the pageserver, but will cause errors on generating basebackup.
133 15271446 : pub fn is_valid_key_on_write_path(&self) -> bool {
134 15271446 : self.is_i128_representable()
135 15271446 : }
136 :
137 48865018 : pub fn is_i128_representable(&self) -> bool {
138 48865018 : self.field2 <= 0xFFFF || self.field2 == 0xFFFFFFFF || self.field2 == 0x22222222
139 48865018 : }
140 :
141 : /// 'field2' is used to store tablespaceid for relations and small enum numbers for other relish.
142 : /// As long as Neon does not support tablespace (because of lack of access to local file system),
143 : /// we can assume that only some predefined namespace OIDs are used which can fit in u16
144 33593572 : pub fn to_i128(&self) -> i128 {
145 33593572 : assert!(self.is_i128_representable(), "invalid key: {self}");
146 33593572 : (((self.field1 & 0x7F) as i128) << 120)
147 33593572 : | (((self.field2 & 0xFFFF) as i128) << 104)
148 33593572 : | ((self.field3 as i128) << 72)
149 33593572 : | ((self.field4 as i128) << 40)
150 33593572 : | ((self.field5 as i128) << 32)
151 33593572 : | self.field6 as i128
152 33593572 : }
153 :
154 16385234 : pub const fn from_i128(x: i128) -> Self {
155 16385234 : Key {
156 16385234 : field1: ((x >> 120) & 0x7F) as u8,
157 16385234 : field2: ((x >> 104) & 0xFFFF) as u32,
158 16385234 : field3: (x >> 72) as u32,
159 16385234 : field4: (x >> 40) as u32,
160 16385234 : field5: (x >> 32) as u8,
161 16385234 : field6: x as u32,
162 16385234 : }
163 16385234 : }
164 :
165 18910172 : pub fn to_compact(&self) -> CompactKey {
166 18910172 : CompactKey(self.to_i128())
167 18910172 : }
168 :
169 14653101 : pub fn from_compact(k: CompactKey) -> Self {
170 14653101 : Self::from_i128(k.0)
171 14653101 : }
172 :
173 26526228 : pub const fn next(&self) -> Key {
174 26526228 : self.add(1)
175 26526228 : }
176 :
177 26540436 : pub const fn add(&self, x: u32) -> Key {
178 26540436 : let mut key = *self;
179 26540436 :
180 26540436 : let r = key.field6.overflowing_add(x);
181 26540436 : key.field6 = r.0;
182 26540436 : if r.1 {
183 2481285 : let r = key.field5.overflowing_add(1);
184 2481285 : key.field5 = r.0;
185 2481285 : if r.1 {
186 0 : let r = key.field4.overflowing_add(1);
187 0 : key.field4 = r.0;
188 0 : if r.1 {
189 0 : let r = key.field3.overflowing_add(1);
190 0 : key.field3 = r.0;
191 0 : if r.1 {
192 0 : let r = key.field2.overflowing_add(1);
193 0 : key.field2 = r.0;
194 0 : if r.1 {
195 0 : let r = key.field1.overflowing_add(1);
196 0 : key.field1 = r.0;
197 0 : assert!(!r.1);
198 0 : }
199 0 : }
200 0 : }
201 2481285 : }
202 24059151 : }
203 26540436 : key
204 26540436 : }
205 :
206 : /// Convert a 18B slice to a key. This function should not be used for 16B metadata keys because `field2` is handled differently.
207 : /// Use [`Key::from_i128`] instead if you want to handle 16B keys (i.e., metadata keys). There are some restrictions on `field2`,
208 : /// and therefore not all 18B slices are valid page server keys.
209 17616142 : pub fn from_slice(b: &[u8]) -> Self {
210 17616142 : Key {
211 17616142 : field1: b[0],
212 17616142 : field2: u32::from_be_bytes(b[1..5].try_into().unwrap()),
213 17616142 : field3: u32::from_be_bytes(b[5..9].try_into().unwrap()),
214 17616142 : field4: u32::from_be_bytes(b[9..13].try_into().unwrap()),
215 17616142 : field5: b[13],
216 17616142 : field6: u32::from_be_bytes(b[14..18].try_into().unwrap()),
217 17616142 : }
218 17616142 : }
219 :
220 : /// Convert a key to a 18B slice. This function should not be used for getting a 16B metadata key because `field2` is handled differently.
221 : /// Use [`Key::to_i128`] instead if you want to get a 16B key (i.e., metadata keys).
222 21882620 : pub fn write_to_byte_slice(&self, buf: &mut [u8]) {
223 21882620 : buf[0] = self.field1;
224 21882620 : BE::write_u32(&mut buf[1..5], self.field2);
225 21882620 : BE::write_u32(&mut buf[5..9], self.field3);
226 21882620 : BE::write_u32(&mut buf[9..13], self.field4);
227 21882620 : buf[13] = self.field5;
228 21882620 : BE::write_u32(&mut buf[14..18], self.field6);
229 21882620 : }
230 : }
231 :
232 : impl fmt::Display for Key {
233 1124539 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 1124539 : write!(
235 1124539 : f,
236 1124539 : "{:02X}{:08X}{:08X}{:08X}{:02X}{:08X}",
237 1124539 : self.field1, self.field2, self.field3, self.field4, self.field5, self.field6
238 1124539 : )
239 1124539 : }
240 : }
241 :
242 : impl fmt::Display for CompactKey {
243 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 0 : let k = Key::from_compact(*self);
245 0 : k.fmt(f)
246 0 : }
247 : }
248 :
249 : impl Key {
250 : pub const MIN: Key = Key {
251 : field1: u8::MIN,
252 : field2: u32::MIN,
253 : field3: u32::MIN,
254 : field4: u32::MIN,
255 : field5: u8::MIN,
256 : field6: u32::MIN,
257 : };
258 : pub const MAX: Key = Key {
259 : field1: u8::MAX,
260 : field2: u32::MAX,
261 : field3: u32::MAX,
262 : field4: u32::MAX,
263 : field5: u8::MAX,
264 : field6: u32::MAX,
265 : };
266 : /// A key slightly smaller than [`Key::MAX`] for use in layer key ranges to avoid them to be confused with L0 layers
267 : pub const NON_L0_MAX: Key = Key {
268 : field1: u8::MAX,
269 : field2: u32::MAX,
270 : field3: u32::MAX,
271 : field4: u32::MAX,
272 : field5: u8::MAX,
273 : field6: u32::MAX - 1,
274 : };
275 :
276 114797 : pub fn from_hex(s: &str) -> Result<Self> {
277 114797 : if s.len() != 36 {
278 4 : bail!("parse error");
279 114793 : }
280 114793 : Ok(Key {
281 114793 : field1: u8::from_str_radix(&s[0..2], 16)?,
282 114793 : field2: u32::from_str_radix(&s[2..10], 16)?,
283 114793 : field3: u32::from_str_radix(&s[10..18], 16)?,
284 114793 : field4: u32::from_str_radix(&s[18..26], 16)?,
285 114793 : field5: u8::from_str_radix(&s[26..28], 16)?,
286 114793 : field6: u32::from_str_radix(&s[28..36], 16)?,
287 : })
288 114797 : }
289 : }
290 :
291 : // Layout of the Key address space
292 : //
293 : // The Key struct, used to address the underlying key-value store, consists of
294 : // 18 bytes, split into six fields. See 'Key' in repository.rs. We need to map
295 : // all the data and metadata keys into those 18 bytes.
296 : //
297 : // Principles for the mapping:
298 : //
299 : // - Things that are often accessed or modified together, should be close to
300 : // each other in the key space. For example, if a relation is extended by one
301 : // block, we create a new key-value pair for the block data, and update the
302 : // relation size entry. Because of that, the RelSize key comes after all the
303 : // RelBlocks of a relation: the RelSize and the last RelBlock are always next
304 : // to each other.
305 : //
306 : // The key space is divided into four major sections, identified by the first
307 : // byte, and the form a hierarchy:
308 : //
309 : // 00 Relation data and metadata
310 : //
311 : // DbDir () -> (dbnode, spcnode)
312 : // Filenodemap
313 : // RelDir -> relnode forknum
314 : // RelBlocks
315 : // RelSize
316 : //
317 : // 01 SLRUs
318 : //
319 : // SlruDir kind
320 : // SlruSegBlocks segno
321 : // SlruSegSize
322 : //
323 : // 02 pg_twophase
324 : //
325 : // 03 misc
326 : // Controlfile
327 : // checkpoint
328 : // pg_version
329 : //
330 : // 04 aux files
331 : //
332 : // Below is a full list of the keyspace allocation:
333 : //
334 : // DbDir:
335 : // 00 00000000 00000000 00000000 00 00000000
336 : //
337 : // Filenodemap:
338 : // 00 SPCNODE DBNODE 00000000 00 00000000
339 : //
340 : // RelDir:
341 : // 00 SPCNODE DBNODE 00000000 00 00000001 (Postgres never uses relfilenode 0)
342 : //
343 : // RelBlock:
344 : // 00 SPCNODE DBNODE RELNODE FORK BLKNUM
345 : //
346 : // RelSize:
347 : // 00 SPCNODE DBNODE RELNODE FORK FFFFFFFF
348 : //
349 : // SlruDir:
350 : // 01 kind 00000000 00000000 00 00000000
351 : //
352 : // SlruSegBlock:
353 : // 01 kind 00000001 SEGNO 00 BLKNUM
354 : //
355 : // SlruSegSize:
356 : // 01 kind 00000001 SEGNO 00 FFFFFFFF
357 : //
358 : // TwoPhaseDir:
359 : // 02 00000000 00000000 00000000 00 00000000
360 : //
361 : // TwoPhaseFile:
362 : // 02 00000000 00000000 00000000 00 XID
363 : //
364 : // ControlFile:
365 : // 03 00000000 00000000 00000000 00 00000000
366 : //
367 : // Checkpoint:
368 : // 03 00000000 00000000 00000000 00 00000001
369 : //
370 : // AuxFiles:
371 : // 03 00000000 00000000 00000000 00 00000002
372 : //
373 :
374 : //-- Section 01: relation data and metadata
375 :
376 : pub const DBDIR_KEY: Key = Key {
377 : field1: 0x00,
378 : field2: 0,
379 : field3: 0,
380 : field4: 0,
381 : field5: 0,
382 : field6: 0,
383 : };
384 :
385 : #[inline(always)]
386 0 : pub fn dbdir_key_range(spcnode: Oid, dbnode: Oid) -> Range<Key> {
387 0 : Key {
388 0 : field1: 0x00,
389 0 : field2: spcnode,
390 0 : field3: dbnode,
391 0 : field4: 0,
392 0 : field5: 0,
393 0 : field6: 0,
394 0 : }..Key {
395 0 : field1: 0x00,
396 0 : field2: spcnode,
397 0 : field3: dbnode,
398 0 : field4: 0xffffffff,
399 0 : field5: 0xff,
400 0 : field6: 0xffffffff,
401 0 : }
402 0 : }
403 :
404 : #[inline(always)]
405 48 : pub fn relmap_file_key(spcnode: Oid, dbnode: Oid) -> Key {
406 48 : Key {
407 48 : field1: 0x00,
408 48 : field2: spcnode,
409 48 : field3: dbnode,
410 48 : field4: 0,
411 48 : field5: 0,
412 48 : field6: 0,
413 48 : }
414 48 : }
415 :
416 : #[inline(always)]
417 5844 : pub fn rel_dir_to_key(spcnode: Oid, dbnode: Oid) -> Key {
418 5844 : Key {
419 5844 : field1: 0x00,
420 5844 : field2: spcnode,
421 5844 : field3: dbnode,
422 5844 : field4: 0,
423 5844 : field5: 0,
424 5844 : field6: 1,
425 5844 : }
426 5844 : }
427 :
428 : #[inline(always)]
429 2612292 : pub fn rel_block_to_key(rel: RelTag, blknum: BlockNumber) -> Key {
430 2612292 : Key {
431 2612292 : field1: 0x00,
432 2612292 : field2: rel.spcnode,
433 2612292 : field3: rel.dbnode,
434 2612292 : field4: rel.relnode,
435 2612292 : field5: rel.forknum,
436 2612292 : field6: blknum,
437 2612292 : }
438 2612292 : }
439 :
440 : #[inline(always)]
441 869262 : pub fn rel_size_to_key(rel: RelTag) -> Key {
442 869262 : Key {
443 869262 : field1: 0x00,
444 869262 : field2: rel.spcnode,
445 869262 : field3: rel.dbnode,
446 869262 : field4: rel.relnode,
447 869262 : field5: rel.forknum,
448 869262 : field6: 0xffff_ffff,
449 869262 : }
450 869262 : }
451 :
452 : impl Key {
453 : #[inline(always)]
454 0 : pub fn is_rel_size_key(&self) -> bool {
455 0 : self.field1 == 0 && self.field6 == u32::MAX
456 0 : }
457 : }
458 :
459 : #[inline(always)]
460 6 : pub fn rel_key_range(rel: RelTag) -> Range<Key> {
461 6 : Key {
462 6 : field1: 0x00,
463 6 : field2: rel.spcnode,
464 6 : field3: rel.dbnode,
465 6 : field4: rel.relnode,
466 6 : field5: rel.forknum,
467 6 : field6: 0,
468 6 : }..Key {
469 6 : field1: 0x00,
470 6 : field2: rel.spcnode,
471 6 : field3: rel.dbnode,
472 6 : field4: rel.relnode,
473 6 : field5: rel.forknum + 1,
474 6 : field6: 0,
475 6 : }
476 6 : }
477 :
478 : //-- Section 02: SLRUs
479 :
480 : #[inline(always)]
481 4176 : pub fn slru_dir_to_key(kind: SlruKind) -> Key {
482 4176 : Key {
483 4176 : field1: 0x01,
484 4176 : field2: match kind {
485 1392 : SlruKind::Clog => 0x00,
486 1392 : SlruKind::MultiXactMembers => 0x01,
487 1392 : SlruKind::MultiXactOffsets => 0x02,
488 : },
489 : field3: 0,
490 : field4: 0,
491 : field5: 0,
492 : field6: 0,
493 : }
494 4176 : }
495 :
496 : #[inline(always)]
497 0 : pub fn slru_dir_kind(key: &Key) -> Option<Result<SlruKind, u32>> {
498 0 : if key.field1 == 0x01
499 0 : && key.field3 == 0
500 0 : && key.field4 == 0
501 0 : && key.field5 == 0
502 0 : && key.field6 == 0
503 : {
504 0 : match key.field2 {
505 0 : 0 => Some(Ok(SlruKind::Clog)),
506 0 : 1 => Some(Ok(SlruKind::MultiXactMembers)),
507 0 : 2 => Some(Ok(SlruKind::MultiXactOffsets)),
508 0 : x => Some(Err(x)),
509 : }
510 : } else {
511 0 : None
512 : }
513 0 : }
514 :
515 : #[inline(always)]
516 42 : pub fn slru_block_to_key(kind: SlruKind, segno: u32, blknum: BlockNumber) -> Key {
517 42 : Key {
518 42 : field1: 0x01,
519 42 : field2: match kind {
520 30 : SlruKind::Clog => 0x00,
521 6 : SlruKind::MultiXactMembers => 0x01,
522 6 : SlruKind::MultiXactOffsets => 0x02,
523 : },
524 : field3: 1,
525 42 : field4: segno,
526 42 : field5: 0,
527 42 : field6: blknum,
528 42 : }
529 42 : }
530 :
531 : #[inline(always)]
532 18 : pub fn slru_segment_size_to_key(kind: SlruKind, segno: u32) -> Key {
533 18 : Key {
534 18 : field1: 0x01,
535 18 : field2: match kind {
536 6 : SlruKind::Clog => 0x00,
537 6 : SlruKind::MultiXactMembers => 0x01,
538 6 : SlruKind::MultiXactOffsets => 0x02,
539 : },
540 : field3: 1,
541 18 : field4: segno,
542 18 : field5: 0,
543 18 : field6: 0xffff_ffff,
544 18 : }
545 18 : }
546 :
547 : impl Key {
548 0 : pub fn is_slru_segment_size_key(&self) -> bool {
549 0 : self.field1 == 0x01
550 0 : && self.field2 < 0x03
551 0 : && self.field3 == 0x01
552 0 : && self.field5 == 0
553 0 : && self.field6 == u32::MAX
554 0 : }
555 : }
556 :
557 : #[inline(always)]
558 0 : pub fn slru_segment_key_range(kind: SlruKind, segno: u32) -> Range<Key> {
559 0 : let field2 = match kind {
560 0 : SlruKind::Clog => 0x00,
561 0 : SlruKind::MultiXactMembers => 0x01,
562 0 : SlruKind::MultiXactOffsets => 0x02,
563 : };
564 :
565 0 : Key {
566 0 : field1: 0x01,
567 0 : field2,
568 0 : field3: 1,
569 0 : field4: segno,
570 0 : field5: 0,
571 0 : field6: 0,
572 0 : }..Key {
573 0 : field1: 0x01,
574 0 : field2,
575 0 : field3: 1,
576 0 : field4: segno,
577 0 : field5: 1,
578 0 : field6: 0,
579 0 : }
580 0 : }
581 :
582 : //-- Section 03: pg_twophase
583 :
584 : pub const TWOPHASEDIR_KEY: Key = Key {
585 : field1: 0x02,
586 : field2: 0,
587 : field3: 0,
588 : field4: 0,
589 : field5: 0,
590 : field6: 0,
591 : };
592 :
593 : #[inline(always)]
594 0 : pub fn twophase_file_key(xid: TransactionId) -> Key {
595 0 : Key {
596 0 : field1: 0x02,
597 0 : field2: 0,
598 0 : field3: 0,
599 0 : field4: 0,
600 0 : field5: 0,
601 0 : field6: xid,
602 0 : }
603 0 : }
604 :
605 : #[inline(always)]
606 0 : pub fn twophase_key_range(xid: TransactionId) -> Range<Key> {
607 0 : let (next_xid, overflowed) = xid.overflowing_add(1);
608 0 :
609 0 : Key {
610 0 : field1: 0x02,
611 0 : field2: 0,
612 0 : field3: 0,
613 0 : field4: 0,
614 0 : field5: 0,
615 0 : field6: xid,
616 0 : }..Key {
617 0 : field1: 0x02,
618 0 : field2: 0,
619 0 : field3: 0,
620 0 : field4: 0,
621 0 : field5: u8::from(overflowed),
622 0 : field6: next_xid,
623 0 : }
624 0 : }
625 :
626 : //-- Section 03: Control file
627 : pub const CONTROLFILE_KEY: Key = Key {
628 : field1: 0x03,
629 : field2: 0,
630 : field3: 0,
631 : field4: 0,
632 : field5: 0,
633 : field6: 0,
634 : };
635 :
636 : pub const CHECKPOINT_KEY: Key = Key {
637 : field1: 0x03,
638 : field2: 0,
639 : field3: 0,
640 : field4: 0,
641 : field5: 0,
642 : field6: 1,
643 : };
644 :
645 : pub const AUX_FILES_KEY: Key = Key {
646 : field1: 0x03,
647 : field2: 0,
648 : field3: 0,
649 : field4: 0,
650 : field5: 0,
651 : field6: 2,
652 : };
653 :
654 : #[inline(always)]
655 0 : pub fn repl_origin_key(origin_id: RepOriginId) -> Key {
656 0 : Key {
657 0 : field1: REPL_ORIGIN_KEY_PREFIX,
658 0 : field2: 0,
659 0 : field3: 0,
660 0 : field4: 0,
661 0 : field5: 0,
662 0 : field6: origin_id as u32,
663 0 : }
664 0 : }
665 :
666 : /// Get the range of replorigin keys.
667 864 : pub fn repl_origin_key_range() -> Range<Key> {
668 864 : Key {
669 864 : field1: REPL_ORIGIN_KEY_PREFIX,
670 864 : field2: 0,
671 864 : field3: 0,
672 864 : field4: 0,
673 864 : field5: 0,
674 864 : field6: 0,
675 864 : }..Key {
676 864 : field1: REPL_ORIGIN_KEY_PREFIX,
677 864 : field2: 0,
678 864 : field3: 0,
679 864 : field4: 0,
680 864 : field5: 0,
681 864 : field6: 0x10000,
682 864 : }
683 864 : }
684 :
685 : // Reverse mappings for a few Keys.
686 : // These are needed by WAL redo manager.
687 :
688 : /// Non inherited range for vectored get.
689 : pub const NON_INHERITED_RANGE: Range<Key> = AUX_FILES_KEY..AUX_FILES_KEY.next();
690 : /// Sparse keyspace range for vectored get. Missing key error will be ignored for this range.
691 : pub const NON_INHERITED_SPARSE_RANGE: Range<Key> = Key::metadata_key_range();
692 :
693 : impl Key {
694 : // AUX_FILES currently stores only data for logical replication (slots etc), and
695 : // we don't preserve these on a branch because safekeepers can't follow timeline
696 : // switch (and generally it likely should be optional), so ignore these.
697 : #[inline(always)]
698 0 : pub fn is_inherited_key(self) -> bool {
699 0 : !NON_INHERITED_RANGE.contains(&self) && !NON_INHERITED_SPARSE_RANGE.contains(&self)
700 0 : }
701 :
702 : #[inline(always)]
703 0 : pub fn is_rel_fsm_block_key(self) -> bool {
704 0 : self.field1 == 0x00
705 0 : && self.field4 != 0
706 0 : && self.field5 == FSM_FORKNUM
707 0 : && self.field6 != 0xffffffff
708 0 : }
709 :
710 : #[inline(always)]
711 0 : pub fn is_rel_vm_block_key(self) -> bool {
712 0 : self.field1 == 0x00
713 0 : && self.field4 != 0
714 0 : && self.field5 == VISIBILITYMAP_FORKNUM
715 0 : && self.field6 != 0xffffffff
716 0 : }
717 :
718 : #[inline(always)]
719 0 : pub fn to_slru_block(self) -> anyhow::Result<(SlruKind, u32, BlockNumber)> {
720 0 : Ok(match self.field1 {
721 : 0x01 => {
722 0 : let kind = match self.field2 {
723 0 : 0x00 => SlruKind::Clog,
724 0 : 0x01 => SlruKind::MultiXactMembers,
725 0 : 0x02 => SlruKind::MultiXactOffsets,
726 0 : _ => anyhow::bail!("unrecognized slru kind 0x{:02x}", self.field2),
727 : };
728 0 : let segno = self.field4;
729 0 : let blknum = self.field6;
730 0 :
731 0 : (kind, segno, blknum)
732 : }
733 0 : _ => anyhow::bail!("unexpected value kind 0x{:02x}", self.field1),
734 : })
735 0 : }
736 :
737 : #[inline(always)]
738 0 : pub fn is_slru_block_key(self) -> bool {
739 0 : self.field1 == 0x01 // SLRU-related
740 0 : && self.field3 == 0x00000001 // but not SlruDir
741 0 : && self.field6 != 0xffffffff // and not SlruSegSize
742 0 : }
743 :
744 : #[inline(always)]
745 17523949 : pub fn is_rel_block_key(&self) -> bool {
746 17523949 : self.field1 == 0x00 && self.field4 != 0 && self.field6 != 0xffffffff
747 17523949 : }
748 :
749 : /// Guaranteed to return `Ok()` if [`Self::is_rel_block_key`] returns `true` for `key`.
750 : #[inline(always)]
751 18 : pub fn to_rel_block(self) -> anyhow::Result<(RelTag, BlockNumber)> {
752 18 : Ok(match self.field1 {
753 18 : 0x00 => (
754 18 : RelTag {
755 18 : spcnode: self.field2,
756 18 : dbnode: self.field3,
757 18 : relnode: self.field4,
758 18 : forknum: self.field5,
759 18 : },
760 18 : self.field6,
761 18 : ),
762 0 : _ => anyhow::bail!("unexpected value kind 0x{:02x}", self.field1),
763 : })
764 18 : }
765 : }
766 :
767 : impl std::str::FromStr for Key {
768 : type Err = anyhow::Error;
769 :
770 9 : fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
771 9 : Self::from_hex(s)
772 9 : }
773 : }
774 :
775 : #[cfg(test)]
776 : mod tests {
777 : use std::str::FromStr;
778 :
779 : use crate::key::is_metadata_key_slice;
780 : use crate::key::Key;
781 :
782 : use rand::Rng;
783 : use rand::SeedableRng;
784 :
785 : use super::AUX_KEY_PREFIX;
786 :
787 : #[test]
788 1 : fn display_fromstr_bijection() {
789 1 : let mut rng = rand::rngs::StdRng::seed_from_u64(42);
790 1 :
791 1 : let key = Key {
792 1 : field1: rng.gen(),
793 1 : field2: rng.gen(),
794 1 : field3: rng.gen(),
795 1 : field4: rng.gen(),
796 1 : field5: rng.gen(),
797 1 : field6: rng.gen(),
798 1 : };
799 1 :
800 1 : assert_eq!(key, Key::from_str(&format!("{key}")).unwrap());
801 1 : }
802 :
803 : #[test]
804 1 : fn test_metadata_keys() {
805 1 : let mut metadata_key = vec![AUX_KEY_PREFIX];
806 1 : metadata_key.extend_from_slice(&[0xFF; 15]);
807 1 : let encoded_key = Key::from_metadata_key(&metadata_key);
808 1 : let output_key = encoded_key.to_i128().to_be_bytes();
809 1 : assert_eq!(metadata_key, output_key);
810 1 : assert!(encoded_key.is_metadata_key());
811 1 : assert!(is_metadata_key_slice(&metadata_key));
812 1 : }
813 :
814 : #[test]
815 1 : fn test_possible_largest_key() {
816 1 : Key::from_i128(0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF);
817 1 : // TODO: put this key into the system and see if anything breaks.
818 1 : }
819 : }
|