MongoDB 4.0 提供了level == “snapshot” 的readConcern。 該level 的readConcern 本質上和Primary Secondary 無關, 主要解決的問題是:
時間點1: session 1 打開一個cursor 用于讀資料
時間點2: session 2 修改了 session 1 要讀的資料,并且commit 了
時間點3: session 1 讀到了 session 2 修改的資料。
最終造成了 session 1 讀取到的資料 并不是 “時間點1” 的資料。
snapshot 正是用于解決上述問題。
使用方法
需要啟動一個transaction 并指定readConcern level == “snapshot”
session.startTransaction({readConcern: {level: "snapshot"}})
var cursor = coll.find({..})
while (cursor.hasNext()) {
printjson(cursor.next());
}
session.commitTransaction()
實作原理
一個正常的讀請求的邏輯如下:
while (!batch.full() && wtCursor.hasNext()) {
next = wtCursor.next();
if (filter.matches(next) {
batch.add(next);
}
if (timeToYield()) {
checkForInterrupt();
wtCursor.saveState();
releaseLocksAndWTSnapshot();
reacquireLocksAndWTSnapshot();
wtCursor.restoreState();
}
}
對于一般的的cursor,即使在同一個batch 内部,MongoDB 也會在yield 的時候 release/reacquireLocksAndWTSnapshot. 導緻讀的不同階段也會讀取到不同時間點的snapshot 資料。主要用于減少因為snapshot 對記憶體産生的額外壓力。
對于snapshot cursor, MongoDB 不會做上述的2個步驟。對記憶體多了一些壓力,但提供了snapshot read 的結果