1
1
mirror of https://github.com/wader/fq.git synced 2024-11-23 09:56:07 +03:00

postgres: pg_btree begin impl

This commit is contained in:
Pavel Safonov 2022-09-19 15:45:54 +03:00
parent f122f72373
commit dd84d3218c
3 changed files with 184 additions and 0 deletions

View File

@ -103,6 +103,7 @@ const (
OPUS_PACKET = "opus_packet"
PCAP = "pcap"
PCAPNG = "pcapng"
PG_BTREE = "pg_btree"
PG_WAL = "pg_wal"
PG_WALPAGE = "pg_wal_page"
PG_MULTIXACTOFF = "pg_multixact_offsets"

View File

@ -0,0 +1,146 @@
package postgres14
import (
"github.com/wader/fq/format/postgres/common"
"github.com/wader/fq/pkg/decode"
)
const (
BTREE_MAGIC = 0x053162
)
// struct BTMetaPageData {
/* 0 | 4 */ // uint32 btm_magic
/* 4 | 4 */ // uint32 btm_version
/* 8 | 4 */ // BlockNumber btm_root
/* 12 | 4 */ // uint32 btm_level
/* 16 | 4 */ // BlockNumber btm_fastroot
/* 20 | 4 */ // uint32 btm_fastlevel
/* 24 | 4 */ // uint32 btm_last_cleanup_num_delpages
/* XXX 4-byte hole */
/* 32 | 8 */ // float8 btm_last_cleanup_num_heap_tuples
/* 40 | 1 */ // _Bool btm_allequalimage
/* XXX 7-byte padding */
//
/* total size (bytes): 48 */
func DecodePgBTree(d *decode.D) any {
d.SeekAbs(0)
btree := &BTreeD{
PageSize: common.HeapPageSize,
}
decodeBTreePages(btree, d)
return nil
}
type BTreeD struct {
PageSize uint64
page *BTreePage
}
type BTreePage struct {
heap HeapPage
bytesPosBegin uint64 // bytes pos of page's beginning
bytesPosEnd uint64 // bytes pos of page's ending
bytesPosSpecial uint64 // bytes pos of page's special
}
type HeapPage struct {
PdLower uint16
PdUpper uint16
PdSpecial uint16
PdPagesizeVersion uint16
}
func decodeBTreePages(btree *BTreeD, d *decode.D) {
for i := 0; ; i++ {
if end, _ := d.TryEnd(); end {
return
}
page := &BTreePage{}
if btree.page != nil {
// use prev page
page.bytesPosBegin = btree.page.bytesPosEnd
}
page.bytesPosEnd = common.TypeAlign(btree.PageSize, page.bytesPosBegin+1)
btree.page = page
if i == 0 {
// first page contains meta information
d.FieldStruct("heap_page", func(d *decode.D) {
decodeBTreeMetaPage(btree, d)
})
continue
}
if i > 0 {
return
}
}
}
func decodeBTreeMetaPage(btree *BTreeD, d *decode.D) {
d.FieldStruct("page_header", func(d *decode.D) {
decodePageHeader(btree, d)
})
d.FieldStruct("meta_page_data", func(d *decode.D) {
decodeBTMetaPageData(btree, d)
})
}
func decodePageHeader(btree *BTreeD, d *decode.D) {
heap := btree.page.heap
d.FieldStruct("pd_lsn", func(d *decode.D) {
/* 0 | 4 */ // uint32 xlogid;
/* 4 | 4 */ // uint32 xrecoff;
d.FieldU32("xlogid", common.HexMapper)
d.FieldU32("xrecoff", common.HexMapper)
})
d.FieldU16("pd_checksum")
d.FieldU16("pd_flags")
heap.PdLower = uint16(d.FieldU16("pd_lower"))
heap.PdUpper = uint16(d.FieldU16("pd_upper"))
heap.PdSpecial = uint16(d.FieldU16("pd_special"))
heap.PdPagesizeVersion = uint16(d.FieldU16("pd_pagesize_version"))
d.FieldU32("pd_prune_xid")
// ItemIdData pd_linp[];
//page.ItemsEnd = int64(page.PagePosBegin*8) + int64(page.PdLower*8)
//d.FieldArray("pd_linp", func(d *decode.D) {
// DecodeItemIds(heap, d)
//})
}
func decodeBTMetaPageData(btree *BTreeD, d *decode.D) {
/* 0 | 4 */ // uint32 btm_magic
/* 4 | 4 */ // uint32 btm_version
/* 8 | 4 */ // BlockNumber btm_root
/* 12 | 4 */ // uint32 btm_level
/* 16 | 4 */ // BlockNumber btm_fastroot
/* 20 | 4 */ // uint32 btm_fastlevel
/* 24 | 4 */ // uint32 btm_last_cleanup_num_delpages
/* XXX 4-byte hole */
/* 32 | 8 */ // float8 btm_last_cleanup_num_heap_tuples
/* 40 | 1 */ // _Bool btm_allequalimage
/* XXX 7-byte padding */
btmMagic := d.FieldU32("btm_magic")
d.FieldU32("btm_version")
d.FieldU32("btm_root")
d.FieldU32("btm_level")
d.FieldU32("btm_fastroot")
d.FieldU32("btm_fastlevel")
d.FieldU32("btm_last_cleanup_num_delpages")
d.FieldU32("hole0")
d.FieldF64("btm_last_cleanup_num_heap_tuples")
d.FieldU8("btm_allequalimage")
d.FieldU56("padding0")
if btmMagic != BTREE_MAGIC {
d.Fatalf("invalid btmMagic = %X, must be %X\n", btmMagic, BTREE_MAGIC)
}
}

View File

@ -0,0 +1,37 @@
package postgres
import (
"github.com/wader/fq/format"
"github.com/wader/fq/format/postgres/flavours/postgres14"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
)
func init() {
interp.RegisterFormat(decode.Format{
Name: format.PG_BTREE,
Description: "PostgreSQL btree index file",
DecodeFn: decodePgBTree,
DecodeInArg: format.PostgresIn{
Flavour: "default",
},
RootArray: true,
RootName: "pages",
})
}
func decodePgBTree(d *decode.D, in any) any {
d.Endian = decode.LittleEndian
pgIn, ok := in.(format.PostgresIn)
if !ok {
d.Fatalf("DecodeInArg must be PostgresIn!\n")
}
switch pgIn.Flavour {
case PG_FLAVOUR_POSTGRES14, PG_FLAVOUR_POSTGRES:
return postgres14.DecodePgBTree(d)
}
return nil
}