Tổng quan về XLOG
XLOG là nhật ký ghi lại (redo log) của PostgreSQL, dùng để phục hồi dữ liệu khi hệ thống khởi động lại. XLOG thuộc loại nhật ký vật lý logic (physical logical log), nó ghi lại sự thay đổi của các trang dữ liệu trong cơ sở dữ liệu. Trong bài viết này, chúng ta sẽ tìm hiểu chi tiết cách XLOG hoạt động, đặc biệt là quá trình ghi dữ liệu cho một thao tác chèn (insert).
Các câu hỏi cần giải quyết:
- Thao tác insert ghi những gì vào XLOG?
- Dữ liệu trong XLOG được tổ chức như thế nào?
- Physical logical log là gì?
- Dữ liệu được ghi vào XLOG theo cách nào?
Cấu trúc XLOG
Một bản ghi XLOG bao gồm nhiều phần khác nhau. Để minh họa, chúng ta sử dụng ví dụ sau:
DROP TABLE IF EXISTS test;
CREATE TABLE test(a int);
INSERT INTO test VALUES(1);
Với thao tác insert trên, XLOG được tạo ra từ bốn phần chính:
Phần 1: Đầu XLOG (XLOG Header)
Đây là phần phức tạp nhất của XLOG, chứa thông tin cơ bản về bản ghi.
Cấu trúc XLogRecord:
typedef struct XLogRecord {
uint32 xl_tot_len; // Tổng độ dài của bản ghi
TransactionId xl_xid; // ID giao dịch
XLogRecPtr xl_prev; // Con trỏ đến bản ghi trước đó
uint8 xl_info; // Các cờ thông tin
RmgrId xl_rmid; // ID quản lý tài nguyên
pg_crc32c xl_crc; // Mã kiểm tra lỗi CRC
} XLogRecord;
Bên cạnh XLogRecord, còn có các cấu trúc bổ sung như XLogRecordBlockHeader, RelFileNode, BlockNumber và mainrdata_len.
Phần 2: xl_heap_header
xl_heap_header là phiên bản rút gọn của HeapTupleHeaderData, chỉ lưu trữ thông tin cần thiết:
typedef struct xl_heap_header {
uint16 t_infomask2;
uint16 t_infomask;
uint8 t_hoff;
} xl_heap_header;
Phần 3: Dữ liệu cụ thể của tuple
Phần này chứa dữ liệu thực tế của tuple được chèn vào bảng, giống hệt với dữ liệu được ghi vào trang dữ liệu.
Phần 4: xl_heap_insert
xl_heap_insert xác định vị trí vật lý của tuple trên trang:
typedef struct xl_heap_insert {
OffsetNumber offnum; // Vị trí offset của tuple
uint8 flags;
} xl_heap_insert;
Logical Log vs Physical Log
Nhật ký vật lý logic (physical logical log) ghi lại vị trí logic của tuple trên trang dữ liệu, thay vì vị trí vật lý chính xác. Điều này giúp tránh vấn đề khi thực hiện vacuum hoặc tái tổ chức trang dữ liệu.
Quá trình ghi dữ liệu vào XLOG
Việc ghi dữ liệu vào XLOG bao gồm hai bước chính:
- Đăng ký dữ liệu cần ghi.
- Gọi hàm XLogInsert để ghi dữ liệu vào log buffer.
Đăng ký dữ liệu
Các hàm đăng ký dữ liệu bao gồm:
XLogRegisterData((char *) &xlrec, SizeOfHeapInsert);
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
XLogRegisterBufData(0, (char *) heaptup->t_data + SizeofHeapTupleHeader,
heaptup->t_len - SizeofHeapTupleHeader);
Trong đó:
xlrec: Dữ liệu của cấu trúcxl_heap_insert.xlhdr: Dữ liệu của cấu trúcxl_heap_header.heaptup->t_data: Dữ liệu thực tế của tuple.
Hàm XLogRegisterData
Hàm này thêm dữ liệu vào phần "main chunk" của bản ghi WAL:
void XLogRegisterData(char *data, int len) {
XLogRecData *rdata;
Assert(begininsert_called);
// Logic xử lý dữ liệu...
}
Sau khi đăng ký xong, dữ liệu sẽ được tổ chức thành một bản ghi hoàn chỉnh và sẵn sàng để ghi vào log buffer.