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 : #[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 0 : fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
40 0 : Some(self.cmp(other))
41 0 : }
42 : }
43 :
44 : impl Ord for RelTag {
45 0 : fn cmp(&self, other: &Self) -> Ordering {
46 0 : // Custom ordering where we put forknum to the end of the list
47 0 : let other_tup = (other.spcnode, other.dbnode, other.relnode, other.forknum);
48 0 : (self.spcnode, self.dbnode, self.relnode, self.forknum).cmp(&other_tup)
49 0 : }
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 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 0 : if let Some(forkname) = forknumber_to_name(self.forknum) {
60 0 : write!(
61 0 : f,
62 0 : "{}/{}/{}_{}",
63 0 : self.spcnode, self.dbnode, self.relnode, forkname
64 0 : )
65 : } else {
66 0 : write!(f, "{}/{}/{}", self.spcnode, self.dbnode, self.relnode)
67 : }
68 0 : }
69 : }
70 :
71 : impl RelTag {
72 0 : pub fn to_segfile_name(&self, segno: u32) -> String {
73 0 : let mut name = if self.spcnode == GLOBALTABLESPACE_OID {
74 0 : "global/".to_string()
75 : } else {
76 0 : format!("base/{}/", self.dbnode)
77 : };
78 :
79 0 : name += &self.relnode.to_string();
80 :
81 0 : if let Some(fork_name) = forknumber_to_name(self.forknum) {
82 0 : name += "_";
83 0 : name += fork_name;
84 0 : }
85 :
86 0 : if segno != 0 {
87 0 : name += ".";
88 0 : name += &segno.to_string();
89 0 : }
90 :
91 0 : name
92 0 : }
93 :
94 0 : pub fn with_forknum(&self, forknum: u8) -> Self {
95 0 : RelTag {
96 0 : forknum,
97 0 : spcnode: self.spcnode,
98 0 : dbnode: self.dbnode,
99 0 : relnode: self.relnode,
100 0 : }
101 0 : }
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 : Debug,
116 : Clone,
117 : Copy,
118 : Hash,
119 : Serialize,
120 0 : Deserialize,
121 : PartialEq,
122 : Eq,
123 : PartialOrd,
124 : Ord,
125 0 : strum_macros::EnumIter,
126 0 : strum_macros::FromRepr,
127 : enum_map::Enum,
128 : )]
129 : #[repr(u8)]
130 : pub enum SlruKind {
131 : Clog = 0,
132 : MultiXactMembers,
133 : MultiXactOffsets,
134 : }
135 :
136 : impl SlruKind {
137 0 : pub fn to_str(&self) -> &'static str {
138 0 : match self {
139 0 : Self::Clog => "pg_xact",
140 0 : Self::MultiXactMembers => "pg_multixact/members",
141 0 : Self::MultiXactOffsets => "pg_multixact/offsets",
142 : }
143 0 : }
144 : }
|