Line data Source code
1 : use serde::{Deserialize, Serialize};
2 : use std::cmp::Ordering;
3 : use std::fmt;
4 :
5 : use postgres_ffi::pg_constants::GLOBALTABLESPACE_OID;
6 : use postgres_ffi::relfile_utils::forknumber_to_name;
7 : use postgres_ffi::Oid;
8 :
9 : ///
10 : /// Relation data file segment id throughout the Postgres cluster.
11 : ///
12 : /// Every data file in Postgres is uniquely identified by 4 numbers:
13 : /// - relation id / node (`relnode`)
14 : /// - database id (`dbnode`)
15 : /// - tablespace id (`spcnode`), in short this is a unique id of a separate
16 : /// directory to store data files.
17 : /// - forknumber (`forknum`) is used to split different kinds of data of the same relation
18 : /// between some set of files (`relnode`, `relnode_fsm`, `relnode_vm`).
19 : ///
20 : /// In native Postgres code `RelFileNode` structure and individual `ForkNumber` value
21 : /// are used for the same purpose.
22 : /// [See more related comments here](https:///github.com/postgres/postgres/blob/99c5852e20a0987eca1c38ba0c09329d4076b6a0/src/include/storage/relfilenode.h#L57).
23 : ///
24 : // FIXME: should move 'forknum' as last field to keep this consistent with Postgres.
25 : // Then we could replace the custom Ord and PartialOrd implementations below with
26 : // deriving them. This will require changes in walredoproc.c.
27 68642302 : #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize)]
28 : pub struct RelTag {
29 : pub forknum: u8,
30 : pub spcnode: Oid,
31 : pub dbnode: Oid,
32 : pub relnode: Oid,
33 : }
34 :
35 : /// Block number within a relation or SLRU. This matches PostgreSQL's BlockNumber type.
36 : pub type BlockNumber = u32;
37 :
38 : impl PartialOrd for RelTag {
39 6450103 : fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
40 6450103 : Some(self.cmp(other))
41 6450103 : }
42 : }
43 :
44 : impl Ord for RelTag {
45 6450103 : fn cmp(&self, other: &Self) -> Ordering {
46 6450103 : // Custom ordering where we put forknum to the end of the list
47 6450103 : let other_tup = (other.spcnode, other.dbnode, other.relnode, other.forknum);
48 6450103 : (self.spcnode, self.dbnode, self.relnode, self.forknum).cmp(&other_tup)
49 6450103 : }
50 : }
51 :
52 : /// Display RelTag in the same format that's used in most PostgreSQL debug messages:
53 : ///
54 : /// ```text
55 : /// <spcnode>/<dbnode>/<relnode>[_fsm|_vm|_init]
56 : /// ```
57 : impl fmt::Display for RelTag {
58 5618349 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 5618349 : if let Some(forkname) = forknumber_to_name(self.forknum) {
60 106001 : write!(
61 106001 : f,
62 106001 : "{}/{}/{}_{}",
63 106001 : self.spcnode, self.dbnode, self.relnode, forkname
64 106001 : )
65 : } else {
66 5512348 : write!(f, "{}/{}/{}", self.spcnode, self.dbnode, self.relnode)
67 : }
68 5618349 : }
69 : }
70 :
71 : impl RelTag {
72 14018 : pub fn to_segfile_name(&self, segno: u32) -> String {
73 14018 : let mut name = if self.spcnode == GLOBALTABLESPACE_OID {
74 825 : "global/".to_string()
75 : } else {
76 13193 : format!("base/{}/", self.dbnode)
77 : };
78 :
79 14018 : name += &self.relnode.to_string();
80 :
81 14018 : if let Some(fork_name) = forknumber_to_name(self.forknum) {
82 3612 : name += "_";
83 3612 : name += fork_name;
84 10406 : }
85 :
86 14018 : if segno != 0 {
87 0 : name += ".";
88 0 : name += &segno.to_string();
89 14018 : }
90 :
91 14018 : name
92 14018 : }
93 :
94 10406 : pub fn with_forknum(&self, forknum: u8) -> Self {
95 10406 : RelTag {
96 10406 : forknum,
97 10406 : spcnode: self.spcnode,
98 10406 : dbnode: self.dbnode,
99 10406 : relnode: self.relnode,
100 10406 : }
101 10406 : }
102 : }
103 :
104 : ///
105 : /// Non-relation transaction status files (clog (a.k.a. pg_xact) and
106 : /// pg_multixact) in Postgres are handled by SLRU (Simple LRU) buffer,
107 : /// hence the name.
108 : ///
109 : /// These files are global for a postgres instance.
110 : ///
111 : /// These files are divided into segments, which are divided into
112 : /// pages of the same BLCKSZ as used for relation files.
113 : ///
114 : #[derive(
115 0 : Debug,
116 0 : Clone,
117 : Copy,
118 0 : Hash,
119 0 : Serialize,
120 0 : Deserialize,
121 18923388 : PartialEq,
122 : Eq,
123 0 : PartialOrd,
124 0 : Ord,
125 4233 : strum_macros::EnumIter,
126 0 : strum_macros::FromRepr,
127 : )]
128 : #[repr(u8)]
129 : pub enum SlruKind {
130 : Clog = 0,
131 : MultiXactMembers,
132 : MultiXactOffsets,
133 : }
134 :
135 : impl SlruKind {
136 1845 : pub fn to_str(&self) -> &'static str {
137 1845 : match self {
138 621 : Self::Clog => "pg_xact",
139 621 : Self::MultiXactMembers => "pg_multixact/members",
140 603 : Self::MultiXactOffsets => "pg_multixact/offsets",
141 : }
142 1845 : }
143 : }
|