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