---
# System prepended metadata

title: LEC 15 Transactions
tags: [memo, systems]

---

###### tags: `memo` `systems`
# LEC 15 Transactions

Slide URL: http://web.mit.edu/6.033/www/lec/s15-partial.pdf

## 前回までの話
- どうやって、フォールトトレラント(fault-tolerant)なシステムをつくるか
- ディスク障害の対処の話

## 今回の話
- フォールトトレランスを実現するための抽象化の導入
    - トランザクション
        - 原子性(atomicity)
        - 分離(isolation)
    - 原子性を実現する方法にshadow copiesがある

## 原子性 (Atomicity)
一連の処理が**起こる** or **起こらない**場合、その一連の処理は atomic であるという。原子性を保証できれば、故障についての原因究明が容易になる

### :one: atomic ではない場合
```python=
def transfer(bank, a, b, amount):
    bank[a] -= amount
    bank[b] += amount
```
2行目と3行目の間でクラッシュすれば、aの口座からお金が消えただけで、bの口座には何も振り込まれない

### :two: shadow copies を使う場合
```python=
def transfer(bank_file, a, b, amount):
    bank = read_accounts(bank_file)
    bank[a] -= amount
    bank[b] += amount
    write_accounts(bank, tmp_file) # shadow copy を作る
    rename(tmp_file, bank_file)
```
`rename()` は以下の通り
```python=
# src_file を dst_file にリネーム
def rename(src_file, dst_file):
    src_inode = src_file.dent.inode
    dst_inode = dst_file.dent.inode
    
    dst_file.dent.inode = src_inode
    
    src_file.dent.remove()
    dst_inode.deref()
```
- :heavy_check_mark: 5行目以前に障害があった場合
    - rename は実行されない
    - rename が実行されないなら、ゴミファイルが残るだけで特に害はない
- :heavy_check_mark: 6行目で障害があった場合
    - inodeが何を指すのかわからなくのでたちが悪い…
    - しかし、single-sector writes自体atomicなので心配することはない
    - 後続の問題に対処する必要はあるが…
- :thinking_face: 7行目以降に障害があった場合
    - dentの削除やinodeのderefなど、後処理がちゃんと実行されない

後処理がちゃんと実行されない問題は、ちまちま対処するより、ディスクチェックに任せた方がよいとのこと（起動時に行われるディスクチェックのことかな？）

```python=
def recover(disk):
    for inode in disk.inodes:
        inode.refcount = find_all_refs(disk.root_dir, inode)
    if exists(tmp_file):
        unlink(tmp_file)
```

## 分離(Isolation)
- 分離: 2つのアクションA1とA2が並列に実行された場合でも、結果がA1とA2を直列に実行した場合と一致する
- 雑なロックで一応は実現可能
    - しかし、パフォーマンスが犠牲に…

```python=
def transfer(bank_file, a, b, amount):
    acquire(lock)
    bank = read_accounts(bank_file)
    bank[a] -= amount
    bank[b] += amount
    write_accounts(bank, tmp_file)
    rename(tmp_file, bank_file)
    release(lock)
```

## トランザクション(Transaction)
- Transaction = Atomicity + Isolation
    - Atomicity: 以下の一連の処理は必ず起こる or 起こらない
    - Isolation: transferとwithdrawは並列に実行されても、結果は直列に実行した結果と一致する
```python=
with transaction():
    transfer(a, b, 20)
    withdraw(b, 10)
```