-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpostgres_heap_page.hexpat
More file actions
151 lines (127 loc) · 3.38 KB
/
Copy pathpostgres_heap_page.hexpat
File metadata and controls
151 lines (127 loc) · 3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#pragma author "Anthonin Bonnefoy"
#pragma description "PostgreSQL Heap Page Format"
#pragma little endian
import std.core;
import std.mem;
import std.string;
using TransactionId = u32;
using XLogRecPtr = u64 [[format("format_xlogrecptr")]];
using OffsetNumber = u16;
fn format_xlogrecptr(auto rec_ptr) {
return std::format("{:X}/{:08X}", rec_ptr & 0xffffffff, rec_ptr >> 32);
};
struct PageHeaderData {
XLogRecPtr pd_lsn;
u16 pd_checksum;
u16 pd_flags;
u16 pd_lower;
u16 pd_upper;
u16 pd_special;
u16 pd_pagesize_version;
TransactionId pd_prune_xid;
};
struct BlockIdData {
u16 bi_hi;
u16 bi_lo;
} [[format("format_blk_id")]];
fn format_blk_id(auto blk) {
auto blk_id = (blk.bi_hi << 16) + blk.bi_lo;
return std::format("{}", blk_id);
};
struct ItemPointerData {
BlockIdData blkid;
OffsetNumber posid;
} [[format("format_item_pointer_data")]];
fn format_item_pointer_data(auto ptr) {
return std::format("({},{})", ptr.blkid, ptr.posid);
};
enum LP_FLAGS : u8 {
UNUSED = 0,
NORMAL = 1,
REDIRECT = 2,
DEAD = 3,
};
bitfield t_infomask {
hasnull :1;
hasvarwidth :1;
hasexternal :1;
hasoid :1;
xmax_keyshr_lock:1;
combo_cid :1;
xmax_excl_lock :1;
xmax_lock_only :1;
xmin_committed :1;
xmin_invalid :1;
xmax_committed :1;
xmax_invalid :1;
xmax_is_multi :1;
updated :1;
moved_off :1;
moved_in :1;
} [[fixed_size(2)]];
bitfield t_infomask2 {
natts : 11;
keys_updated : 1;
hot_updated : 1;
only_tuple : 1;
} [[fixed_size(2)]];
struct HeapTupleHeaderData {
TransactionId t_xmin;
TransactionId t_xmax;
u32 t_cid;
ItemPointerData t_ctid;
t_infomask2 t_infomask2;
t_infomask t_infomask;
u8 t_hoff;
if (t_infomask.hasnull > 0) {
u8 t_bits[1 + t_infomask2.natts / 8];
}
};
fn relative_to_page_start(u32 pointer) {
auto page_start = addressof(parent.parent.parent);
auto offset_from_page_start = page_start + (pointer & 0x7fff);
// pointer_base will add pointer to the result,
// substract it to have the correct address
return offset_from_page_start - pointer;
};
bitfield LinePointerHeader {
off : 15;
flags : 2;
len : 15;
} [[inline, format("format_lp_header")]];
fn lp_flags_to_str(auto lp_flags) {
match (lp_flags) {
(LP_FLAGS::UNUSED): return "UNUSED";
(LP_FLAGS::NORMAL): return "NORMAL";
(LP_FLAGS::REDIRECT): return "REDIRECT";
(LP_FLAGS::DEAD): return "DEAD";
(_): return "UNKNOWN";
}
};
fn format_lp_header(auto lp) {
return std::format("off: {}, {}, len: {}", lp.off, lp_flags_to_str(lp.flags), lp.len);
};
struct HeapTupleData {
HeapTupleHeaderData header;
std::mem::AlignTo<8>;
u8 data[parent.hdr.len - ($ - addressof(header))];
}[[format("format_heap_tuple_data")]];
fn format_heap_tuple_data(auto tpl) {
return std::format("{}", tpl.header.t_ctid);
};
struct LinePointer {
LinePointerHeader hdr;
if (hdr.len > 0) {
$ = $ - 4;
HeapTupleData *heap_data : u32 [[pointer_base("relative_to_page_start"), inline]];
}
} [[format("format_lp")]];
fn format_lp(auto lp) {
return std::format("{}", lp.hdr);
};
struct Page {
PageHeaderData header;
// Read line pointers until we reach the start of free space
LinePointer line_pointers[while (($ - addressof(header)) < header.pd_lower)];
} [[fixed_size(8192)]];
Page pages[while (!std::mem::eof())] @$;