cmu15545筆記-索引併發控制(Concurrent Indexes)

咪啪魔女發表於2024-11-14

目錄
  • Overview
    • Lock和Latch辨析
    • 設計目標
    • 大致分類
  • Hash Table Latches
    • Page Latches
    • Slot Latches
  • B+Tree Latches
    • 併發問題
    • Latch Crabbing/Couping
    • Optimistic Coupling(樂觀鎖)
  • Leaf Node Scan

Overview

Lock和Latch辨析

  • Lock:抽象的,邏輯的,整體統籌
  • Latch:具體的,原語性的,自我管理

本節主要探討Latch

image-20241114092741280

設計目標

  • 記憶體佔用少,無競態時執行迅速
  • 等待時間過長時取消排程

大致分類

  1. 自旋鎖(Test-and-Set Spin Latch)
  2. 阻塞互斥鎖(Blocking OS Mutex)
  3. 讀寫鎖(Reader-Writer Latches)
特性 Test-and-Set Spinlock Blocking OS Mutex Reader-Writer Locks
實現 基於原子操作的自旋等待 作業系統級阻塞 允許多讀單寫
鎖爭用時的處理 自旋等待,消耗 CPU 阻塞等待,減少 CPU 消耗 讀操作可以併發,寫操作排他
適用場景 短期鎖、輕度鎖爭用 長期鎖、重度鎖爭用 讀多寫少
優點 無上下文切換,效能高 避免自旋消耗,適合長時間等待 讀寫併發,適合讀多寫少
缺點 CPU 資源消耗高,鎖持有時間長時效率低 上下文切換開銷較高 寫者飢餓問題

image-20241114094213574

C++中的mutex -> pthread -> Linux futex(fast user mutex):先在使用者空間用自旋鎖,如果獲取不到鎖,陷入核心態呼叫阻塞鎖進入阻塞佇列。

image-20241114095322180

image-20241114095559863

Hash Table Latches

兩種粒度:Page Latches和Slot Latches

Page Latches

image image
image image
  • T1給page1上讀鎖,T2等待(如左上圖)
  • T1檢視page2無讀鎖,給page2上讀鎖,釋放page1讀鎖;T2訪問page1,上寫鎖(如右上圖)
  • T2訪問page2,但由於有T1讀鎖,等待(如左下圖)
  • T1釋放page2讀鎖,T2結束等待,給page2上寫鎖,寫入E|val(如右下圖)

Slot Latches

整體過程和Page Latches類似,只不過粒度變了。

image image
image image
  • T1給Slot A上讀鎖,T2給Slot C上寫鎖
  • T1訪問Slot C,但是由於有T2的寫鎖,釋放Slot A寫鎖,在C等待(如左上圖)
  • T2訪問Slot D,釋放Slot C寫鎖,給Slot D上寫鎖;T1可以訪問Slot C,上讀鎖(如右上圖)
  • 重複上述兩個步驟(左下圖和右下圖)

B+Tree Latches

併發問題

相比於雜湊表,B+樹併發的難點在於樹的結構會發生分裂或合併。

image image
image image
  • T1找到了需要刪除的值44(如左上圖)
  • 刪除了值44,此時需要偷(steal)左兄弟的值41進行合併,保證葉子結點半滿,但是T1被排程,進入休眠(如右上圖)
  • T2找到了需要刪除的值41,準備讀取值41,但是此時T2被排程,進入休眠(如左下圖)
  • T1喚醒,進行結點合併,41移動到了新的位置
  • T2被喚醒,讀取41,但是資料已經被移動(如右下圖)

Latch Crabbing/Couping

具體步驟:

  • 得到父結點的鎖
  • 得到子結點的鎖
  • 如果子結點是安全的,釋放之前的鎖,否則不釋放
  • 安全的定義:
    • 對於查詢:不做要求
    • 對於插入:不滿
    • 對於刪除:多於半滿

例:查詢

image image
image image

例:刪除

image image
image image

例:插入

image image

Optimistic Coupling(樂觀鎖)

觀察:在插入和刪除操作中,都會給根結點上寫鎖,造成系統在根結點處是序列的,有效能瓶頸。

實際上一個頁儲存一個結點,頁大小很大,大多數時候不需要結點分裂,刪除時結點也可以延遲合併,說明B+樹結構大多數時候不會變化,上寫鎖的代價太大。

基本思想:上讀鎖,發現衝突後重新上寫鎖。

步驟:

  • 查詢:不變
  • 插入/刪除:
    • 和查詢一樣,在路徑上加讀鎖,到達葉子結點後加寫鎖
    • 如果葉子結點不安全,重做;否則直接執行相關操作
image image
image image

Leaf Node Scan

葉子結點掃描順序:

  • 垂直方向:自頂向底
  • 水平方向:沒有限制

掃描方向衝突:

  1. 水平掃描方向不一致導致衝突
  2. 水平掃描和垂直掃描衝突

水平掃描方向不一致:讀鎖沒有衝突,互換讀鎖即可。

image-20241114113049848

水平掃描方向不一致:帶寫鎖時會有衝突,選擇自我終結。

image-20241114113141531

為什麼選擇自我終結:根本原因是latch是低階原語,不涉及全域性資訊,唯一知道的只有自己的資訊,所以選擇自我終結。

  • 涉及到讀寫磁碟,等待時間不定
  • 不知道其他程序進行到什麼程度,也不知道其他程序是什麼狀況

為什麼水平方向不能強制一個方向掃描:影響效率,在資料規模變大時更為明顯。
比如where子句是 where id > 100000,如果強制從左到右,得掃描100000條資料

水平掃描和垂直掃描方向不一致:

垂直到達葉子結點的操作,在遇到水平進行的操作時,同樣會遇到上述問題,處理方式也相同。

相關文章