Open shinychan95 opened 2 years ago
트랜잭션 시작 중에 또 시작하면, 새로운 시작 지점부터 시작인건가. 아니면 이전 시작 지점으로 인식하는 건가? (테스트 케이스를 보면 이전 시작 시점으로 보이긴 한다)
롤백의 경우 (시작~커밋) 전으로 돌아가는 것으로 보이는데, 커밋이 없다면 어떡하나? 아무 영향 없는가?
롤백 조건에 진행 중인 트랜잭션이 없으면 false 라고 하는데, 커밋은 트랜잭션의 종료를 의미하는 것이 아닌가?
type SWT struct {
master []int // 커밋 전까지 롤백을 위한 원본 스택, pop 함수가 적용되지 않는다.
dev []int // push, top, pop 함수가 모두 적용되는 스택. 트랜잭션 단위로 관리해야 한다.
begins [][]int // 두 스택의 트랜잭션 시작 지점을 저장하는 배열
recovers [][]int // 트랜잭션 롤백 시 복구할 원소들
}
func main() {
var swt SWT
push := func(v int) {
swt.master = append(swt.master, v)
swt.dev = append(swt.dev, v)
}
top := func() int {
dLen := len(swt.dev)
if dLen == 0 {
return 0
}
return swt.dev[dLen - 1]
}
pop := func() {
dLen := len(swt.dev)
if dLen == 0 {
return
}
mLen := len(swt.master)
bLen := len(swt.begins)
if bLen == 0 { // 트랜잭션이 진행 중이지 않으면 원본에서도 제거
swt.master = swt.master[:mLen - 1]
swt.dev = swt.dev[:dLen - 1]
return
}
// 트랜잭션이 진행 중인 경우
if swt.begins[bLen - 1][0] > mLen - 1 { // 트랜잭션 이전 데이터가 pop 되는 경우
elem := swt.dev[dLen - 1]
swt.recovers[bLen - 1] = append(swt.recovers[bLen - 1], elem) // 복원 데이터에 추가한다.
swt.dev = swt.dev[:dLen - 1]
swt.begins[bLen - 1][1]-- // dev 브랜치의 복원 시점을 감소한다.
}
}
begin := func() {
swt.begins = append(swt.begins, []int{len(swt.master), len(swt.dev)})
swt.recovers = append(swt.recovers, []int{})
}
commit := func() bool {
bLen := len(swt.begins)
if bLen == 0 {
return false
}
swt.begins = swt.begins[:bLen - 1]
swt.recovers = swt.recovers[:bLen - 1]
return true
}
rollback := func() bool {
bLen := len(swt.begins)
if bLen == 0 {
return false
}
swt.master = swt.master[:swt.begins[bLen - 1][0]]
swt.dev = swt.dev[:swt.begins[bLen - 1][1]]
swt.dev = append(swt.dev, swt.recovers[bLen - 1]...) // dev 스택의 경우, 원본 스택에서 pop 수 만큼 뺀다 (예외)
swt.begins = swt.begins[:bLen - 1]
swt.recovers = swt.recovers[:bLen - 1]
return true
}
// TEST #1
push(42)
begin()
if top() != 42 { panic("error") }
pop()
if top() != 0 { panic("error") }
pop()
if top() != 0 { panic("error") }
push(5)
push(7)
if top() != 7 { panic("error") }
begin()
push(10)
push(3)
if top() != 3 { panic("error") }
commit()
if top() != 3 { panic("error") }
rollback()
if top() != 42 { panic("error")}
// FINISH
swt.master = nil
swt.dev = nil
swt.begins = nil
swt.recovers = nil
// TEST #2
push(1)
if top() != 1 { panic("error") }
push(2)
if top() != 2 { panic("error") }
push(3)
if top() != 3 { panic("error") }
begin()
if top() != 3 { panic("error") }
pop()
if top() != 2 { panic("error") }
push(4)
if top() != 4 { panic("error") }
push(5)
if top() != 5 { panic("error") }
begin()
if top() != 5 { panic("error") }
pop()
if top() != 4 { panic("error") }
push(6)
if top() != 6 { panic("error") }
push(7)
if top() != 7 { panic("error") }
begin()
if top() != 7 { panic("error") }
pop()
if top() != 6 { panic("error") }
push(8)
if top() != 8 { panic("error") }
push(9)
if top() != 9 { panic("error") }
rollback()
if top() != 7 { panic("error") }
rollback()
if top() != 5 { panic("error") }
rollback()
if top() != 3 { panic("error") }
}