TLA 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 custo Ord and PartialOrd implementations below with
26 : // deriving them.
27 CBC 149123060 : #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize)]
28 : pub struct RelTag {
29 : pub forknum: u8,
30 : pub spcnode: Oid,
31 : pub dbnode: Oid,
32 : pub relnode: Oid,
33 : }
34 :
35 : impl PartialOrd for RelTag {
36 4974562 : fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
37 4974562 : Some(self.cmp(other))
38 4974562 : }
39 : }
40 :
41 : impl Ord for RelTag {
42 4974562 : fn cmp(&self, other: &Self) -> Ordering {
43 4974562 : let mut cmp = self.spcnode.cmp(&other.spcnode);
44 4974562 : if cmp != Ordering::Equal {
45 UBC 0 : return cmp;
46 CBC 4974562 : }
47 4974562 : cmp = self.dbnode.cmp(&other.dbnode);
48 4974562 : if cmp != Ordering::Equal {
49 UBC 0 : return cmp;
50 CBC 4974562 : }
51 4974562 : cmp = self.relnode.cmp(&other.relnode);
52 4974562 : if cmp != Ordering::Equal {
53 4778700 : return cmp;
54 195862 : }
55 195862 : cmp = self.forknum.cmp(&other.forknum);
56 195862 :
57 195862 : cmp
58 4974562 : }
59 : }
60 :
61 : /// Display RelTag in the same format that's used in most PostgreSQL debug messages:
62 : ///
63 : /// ```text
64 : /// <spcnode>/<dbnode>/<relnode>[_fsm|_vm|_init]
65 : /// ```
66 : impl fmt::Display for RelTag {
67 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 3779084 : if let Some(forkname) = forknumber_to_name(self.forknum) {
69 83358 : write!(
70 83358 : f,
71 83358 : "{}/{}/{}_{}",
72 83358 : self.spcnode, self.dbnode, self.relnode, forkname
73 83358 : )
74 : } else {
75 3695726 : write!(f, "{}/{}/{}", self.spcnode, self.dbnode, self.relnode)
76 : }
77 3779084 : }
78 : }
79 :
80 : impl RelTag {
81 8412 : pub fn to_segfile_name(&self, segno: u32) -> String {
82 8412 : let mut name = if self.spcnode == GLOBALTABLESPACE_OID {
83 495 : "global/".to_string()
84 : } else {
85 7917 : format!("base/{}/", self.dbnode)
86 : };
87 :
88 8412 : name += &self.relnode.to_string();
89 :
90 8412 : if let Some(fork_name) = forknumber_to_name(self.forknum) {
91 2167 : name += "_";
92 2167 : name += fork_name;
93 6245 : }
94 :
95 8412 : if segno != 0 {
96 UBC 0 : name += ".";
97 0 : name += &segno.to_string();
98 CBC 8412 : }
99 :
100 8412 : name
101 8412 : }
102 :
103 6245 : pub fn with_forknum(&self, forknum: u8) -> Self {
104 6245 : RelTag {
105 6245 : forknum,
106 6245 : spcnode: self.spcnode,
107 6245 : dbnode: self.dbnode,
108 6245 : relnode: self.relnode,
109 6245 : }
110 6245 : }
111 : }
112 :
113 : ///
114 : /// Non-relation transaction status files (clog (a.k.a. pg_xact) and
115 : /// pg_multixact) in Postgres are handled by SLRU (Simple LRU) buffer,
116 : /// hence the name.
117 : ///
118 : /// These files are global for a postgres instance.
119 : ///
120 : /// These files are divided into segments, which are divided into
121 : /// pages of the same BLCKSZ as used for relation files.
122 : ///
123 23042162 : #[derive(Debug, Clone, Copy, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
124 : pub enum SlruKind {
125 : Clog,
126 : MultiXactMembers,
127 : MultiXactOffsets,
128 : }
129 :
130 : impl SlruKind {
131 1935 : pub fn to_str(&self) -> &'static str {
132 1935 : match self {
133 639 : Self::Clog => "pg_xact",
134 657 : Self::MultiXactMembers => "pg_multixact/members",
135 639 : Self::MultiXactOffsets => "pg_multixact/offsets",
136 : }
137 1935 : }
138 : }
|