Cơ Chế Snapshot trong MVCC

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

  1. 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
  2. Ghi nhận giao dịch hoạt động: Theo dõi các transaction đang thực thi khi tạo snapshot
  3. Sao chép dữ liệu: Sử dụng kỹ thuật Copy-on-Write khi cần thiết
  4. Lưu trữ snapshot: Bảo quản trong bộ nhớ hoặc đĩa
  5. Sử dụng snapshot: Cung cấp view dữ liệu nhất quán trong giao dịch
  6. 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

Thẻ: MVCC Database-Snapshots OpenGauss transaction-management Database-Internals

Đăng vào ngày 30 tháng 6 lúc 04:22