Thông tin cơ bản về Snapshot
Snapshot trong MVCC được định nghĩa qua cấu trúc dữ liệu chung:
extern THR_LOCAL PGDLLIMPORT SnapshotState CurrentSnapshot;
extern THR_LOCAL PGDLLIMPORT SnapshotState SelfSnapshot;
extern THR_LOCAL PGDLLIMPORT SnapshotState UniversalSnapshot;
extern THR_LOCAL PGDLLIMPORT SnapshotState ToastSnapshot;
#ifdef ENABLE_MULTIPLE_NODES
extern THR_LOCAL PGDLLIMPORT SnapshotState AsyncSnapshot;
#endif
Cấu trúc dữ liệu snapshot:
typedef struct SnapshotState {
VisibilityCheckMethod visibility_check;
TransactionId min_active_tx;
TransactionId latest_commit_tx;
SubTransactionId sub_id;
TransactionId* active_tx_list;
TransactionId* sub_active_list;
uint32 tx_count;
TimelineID timeline_id;
#ifdef PGXC_COORD
uint32 max_tx_capacity;
#endif
int32 sub_tx_count;
int32 max_sub_tx;
bool sub_mem_overflow;
CommitSeqNumber csn;
int prep_capacity;
int prep_count;
TransactionId* prep_array;
bool recovery_created;
bool is_static;
CommandId current_cid;
uint32 active_ref_count;
uint32 reg_ref_count;
void* usage_marker;
SnapshotCategory snapshot_category;
} SnapshotState;
Quy trình tạo Snapshot
- Khởi tạo giao dịch: Snapshot được tạo khi bắt đầu giao dịch để ghi nhận trạng thái cơ sở dữ liệu
- Ghi nhận giao dịch hoạt động: Theo dõi các transaction đang thực thi khi tạo snapshot
- Sao chép dữ liệu: Sử dụng kỹ thuật Copy-on-Write khi cần thiết
- Lưu trữ snapshot: Bảo quản trong bộ nhớ hoặc đĩa
- Sử dụng snapshot: Cung cấp view dữ liệu nhất quán trong giao dịch
- Dọn dẹp: Giải phóng tài nguyên khi giao dịch kết thúc
Ví dụ khởi tạo snapshot trong luồng xử lý:
void initialize_thread(ThreadRole role) {
...
initialize_snapshot_context(&thread_ctx.snapshot_ctx);
...
}
typedef struct SnapshotContext {
SnapshotState* CurrentSnapshot;
SnapshotState* SelfSnapshot;
SnapshotState* UniversalSnapshot;
SnapshotState* ToastSnapshot;
} SnapshotContext;
void initialize_snapshot_context(SnapshotContext* ctx) {
ctx->CurrentSnapshot = (SnapshotState*)allocate_mem(sizeof(SnapshotState));
ctx->CurrentSnapshot->visibility_check = SNAPSHOT_CURRENT;
ctx->SelfSnapshot = (SnapshotState*)allocate_mem(sizeof(SnapshotState));
ctx->SelfSnapshot->visibility_check = SNAPSHOT_SELF;
ctx->UniversalSnapshot = (SnapshotState*)allocate_mem(sizeof(SnapshotState));
ctx->UniversalSnapshot->visibility_check = SNAPSHOT_UNIVERSAL;
ctx->ToastSnapshot = (SnapshotState*)allocate_mem(sizeof(SnapshotState));
ctx->ToastSnapshot->visibility_check = SNAPSHOT_TOAST;
}
Phương pháp Mảng Giao dịch Hoạt động
Hệ thống duy trì mảng toàn cục chứa thông tin transaction đang thực thi:
typedef struct ActiveSnapshotElement {
SnapshotState snapshot;
int level;
struct ActiveSnapshotElement* next_element;
} ActiveSnapshotElement;
Hàm lấy snapshot hiện hoạt:
SnapshotState GetActiveSnapshot() {
#ifdef PGXC
if (!session->active_snapshot && IS_COORDINATOR && !FromCoordinator())
return NULL;
#endif
if (session->active_snapshot == NULL) {
report_error(ERROR, "Không có snapshot hoạt động");
}
return session->active_snapshot->snapshot;
}
Phương pháp Timestamp Logic
Sử dụng Commit Sequence Number (CSN) làm timestamp logic:
- COMMITSEQ_INPROGRESS(0x0): Giao dịch chưa hoàn tất
- COMMITSEQ_ABORTED(0x1): Giao dịch đã hủy
- COMMITSEQ_FROZEN(0x2): Giao dịch visible với mọi snapshot
- COMMITSEQ_BASE(0x3): Giá trị CSN khởi đầu
- COMMITSEQ_COMMITTING(1<<62): Giao dịch đang commit
Quy tắc kiểm tra visibility:
tstart ≤ CSN → Giao dịch chưa commit → Không visible
tstart > CSN → Giao dịch đã commit → Visible