락(Lock)

1)기반구조

  • 오라클내에는 다양한 유형의 리소스(테이블,파일,테이블스페이스,병렬실행 슬레이브)가 존재하며,
  • 장시간 동안 리소스를 보호해야 하는 다양한 이유가 존재한다.
  • 다양한 유형으 ㅣ리소스를 표현하기 위해, 오라클은 SGA내의 배열을 이용한다.
    ※ SGA내의 배열은 x$ksqrs구조와 v$resource뷰로나타나며, _enqueue_resources 파라미터에 의해 정의
h5. 배열내의 중요한 칼럼{code:sql}
Name Null? Type






--
KSQRSIDT VARCHAR2(2)
KSQRSIDl NUMBER
KSQRSID2 NUMBER
{code}
* ('PS',1,1)는 인스턴스 1번에서 수행되는 병렬 수행 슬레이브 P004를 의미
* ('TM',80942,0)은 object_id가 80942인 테이블을 의미
* ('TX';,65543,11546)은 트랜잭션이 사용하는 언두세그먼트는 1번(trunc(65543/65536)),
슬롯은 7번(mod(65543,65536))이며 해당슬롯은 11546번 재사용된 것을 의미
  • 자주사용되는 배열
    x$ksqeq(generic enqueue)
    x$ktadm(table/DML locks)
    x$ktcxb(transaction)구조
  • 리소스를 보호하기 위한 기본적인 아이디어
    x$ksqrs구조로부터 하나의 로우를 획득한 후 리소스를 식별하기 위한 표시를한다.
    x$ksqeq(또는 동등한)구조로부터 하나의 로우를 획득한 후 락모드를 설정하고, X$ksqrs구조의 로우와 연결하면된다.

2)그림으로표현한V$lock뷰

{code:sql}
select
sid, type, id1, id2, lmode, request, ctime, block
from v$lock
where
type = 'TM'
and idl = 8272
;

SID TY IDl ID2 LMODE REQUEST CTlME BLOCK




---

--


--
-
37 TM 82772 0 3 5 66 1
36 TM 82772 0 3 0 42 l
39 TM 82772 0 0 6 27 0
35 TM 82772 0 0 3 3 0


(자식테이블의 foreign key 칼럼에는 인덱스가 존재하지 않는다.)
1. 세션37 : 부모 테이블의 레코드 1과 관련된 자식 테이블의 레코드를 삭제한다.
2. 세션36 : 부모 테이블의 레코드 2와 관련된 자식 테이블의 레코드를 삭제한다.
3. 세션39 : exclusive모드로 자식 테이블에 락을 시도한다.(그리고 대기를 시작한다.)
4. 세션37 : 부모 테이블의 레코드 1을 삭제하려고 시도한다.(그리고 FK인덱스의 부재로인해 대기를 시작한다.)
5. 세션35 : 부모테이블의 레코드 3과 관련된 자식테이블의 레코드를 삭제한다(그리고 대기를 시작한다.) 
{panel:title=그림4-4 v$lock 뷰의 몇 개의 로우에 대한 그림|borderStyle=dashed|bgColor=#FFFFFF|titleBGColor=#F0F0F0}!4.jpg|vspace=4!{panel}
※ 오브젝트에 락을 설정하기 위해서는 waiters 또는 converters 리스트에 대기세션이 존재하지 않아야하고,
owners리스트 내의 세션들이 획득한 락 모드와 호환성이 있어야 한다.
* SID 35는 waiters리스트의 맨 뒤에 위치한다. 이미 SID 39가 존재하기 때문이다.
* SID 39역시 대기중이다. SID 37이 converters 리스트에 존재하기 때문이다.
* SID 37은 converters리스트에서 대기한다. SID 37은 락모들르 3에서 5로 변환하기를 원하지만 SID 36이 owner리스트에서 
모드 3으로 락을 획득한 상태이기 때문이다(모드 3으로 락을 획득한 세션이있다면, 모드 5로 락을 소유할 수 없다.)|
|* 프로세스가 커밋(또는 롤백)을 수행하면, 리스트는 다음과 같이 재배치 된다.
1. SID 36이 커밋을 수행하면,owners리스트는 빈상태가 된다. 이로인해 SID 37은 converters 리스트에서 owners 리스트로 이동하고, 
모드 5로 락을 획득하고 ctime을 다시 0으로 설정한다. SID 39와 35는 여전히 waiters리스트에 위치한다.
2. 그 후에 SID 37이 커밋을 수행하면, owners 리스트는 다시 빈 상태가 된다. 이로인해 SID 39는 owners 리스트로 이동하고, 
모드 6으로 락을 획득하고, ctime을 0으로 설정한다. SID 35는 waiters 리스트의 가장 앞에 위치하게 되지만 
owners 리스트로는 이동 할 수 없다. 이미 SID 39가 테이블에 대한 exclusive(모드6)락을 획득했기 때문이다.
3. 그 이후에 SID 39가 커밋을 수행하면, owners 리스트는 다시 빈 상태가 된다. 이로인해 SID 35는 owners리스트로 이동하고
모드 3으로 락을 획득하고 ctime을 0으로 설정한다.|
|※ 락을 획득하기 위해 대기중이라면, ctime칼럼은 대기시간을의미, 락을 획득하고있다면, 락을 소유한 시간을 의미
※ 아주 복잡한 락 패턴으로인해 상세한 정보를 필요로한다면, enqueue 트레이스로 확인을 하면된다.
alter session set event 'immediate trace name enqueues level 3'|                                    

h4. 3)데드락

|{code:sql}
데드락 발생시, 트레이스 파일에서 처음으로 확인해야 할 부분은 deadlock graph이다
Dead10ck graph:         ---------B1ocker(s) -------- ---------Waiter(s) --------
Resource Name           process session ho1ds waits   process session ho1ds waits                
TX- 00030026-000040d6       13    38        x             12      50      x
TX- 00060002-00004113       12    50        x             13      38      x

세션 38은 TX락(언두세그먼트3번,슬롯38(0x26),시퀀스16,598)을 모두 6으로 획득,세션 50번은 대기중,
세션 50은 TX락(언두세그먼트6번,슬롯 2,시퀀스 16,659)을 획득, 세션 38은 대기중 |

# 다음과같은 코딩 에러들은 인덱스에 대한 충돌을 발생시킴에 따라 대기를 유발할 수 있다.
  • 두개의 세션이 동일한 primary key 값을 입력한다.
  • 한 세션은 자식 테이블에 한 로우를 입력하고 다른 세션은 부모 테이블에서 삭제한다.
  • 한 세션은 부모티에블에 한 로우를 입력했으나 커밋전 상태이고, 이시점에 다른 세션이
    해당로우를 자식 테이블에 입력한다.
  • 두개의 세션이 동일한 비트맵 인덱스 청크에 의해 관리되는 로우를 삭제하려고 시도한다.
# TX/4대기를 유발하는 몇가지 다른원인
  • 인덱스에 대한 충돌로 인해 다른 세션이 커밋할 때까지 대기한다면, TX락 모드4로 대기한다.
  • 액티브 트랜잭션들로인해 ITL을 모두 사용했고 ITL을 확장할 여우공간이 없을 때 또다른 트랜잭션이 블록을 변경하려고 하는경우
  • 분산 트랜잭션
  • 프리리스트 고갈
  • 테이블 스페이스를 read-only 모드로 변경하려면 모든 트랜잭션이 완료되기를 대기해야 한다.

4)락모드

모드이름(들)해당모드와 관련된 오퍼레이션
1Null Lock(NL)테이블과는 관련이 없다. 병렬 DML을 수행하는동안 PX슬레이브에 의해 소유된다.
반면에 QC는 exclusive락을 소유한다.
2Sub Share(SS)
Row Share (RS)
select for update(9.2.0.5까지)
Lock table in row share mode
FK가 생성된 테이블에 DML발생 시 부모 테이블에 해당 모드 락 설정(9.2.0.1부터)
3Sub Exclusive(SX)
Row Exclusive(RX)
DML(9.2.0.5부터는 select for update포함)
Lock table in row exclusive mode
FK가 생성된 테이블에 DML발생시 부모 테이블에 해당 모드 락 설정(11.1부터)
4share(S)Lock table in share mode
병렬DML수행시에 PX 슬레이브 세션에서 보여질 수 있다.
Foreign key락킹(인덱스가 존재하지 않는)문제의 일반적인 증상)
5Share Sub Exclusive(SSX)
Share Row Exclusive(SRX)
Lock table in share row exclusive mode
Foreign key 락킹의 일반적이지 않은 증상이며, delete cascade옵션을 사용할 때 보여진다
6Exclusive(X)Lock table in exclusive mode

※ 테이블 락과 관련해서, 모드4 또는 모드5의 락 대기가 발생한다면 foreign key 제약조건에 인덱스를 생성해야 한다.

5)락을위한래치

{panel:title=그림4-5 Enqueue와 enqueue resourceborderStyle=dashedbgColor=#FFFFFFtitleBGColor=#F0F0F0}!3.jpgvspace=4!{panel}
h5. # 락 획득 절차
* 해시값을 생성하기 위해 리소스 식별자(type,id1,id2)를 사용한다.
해시테이블의 크기는 2*sessions+35 정도이므로, '소수' 또는 "2의 지수승"의 일반적인 형식을 사용하지 않는다.
* 해시버킷은 enqueue hash chains 래치에 의해 보호된다. 래치의 수는 CPU의 수와 일치하며,
해시버킷은 래치를 통해 "라운드-로빈"방식으로 공유된다.
* 락을 설정하려는 리소스에 해당되는 x$ksqrs구조의 한 로우가 이미 해시 체인에 링크되었는지를 확인하려면,
래치를 획득한 후 버킷을 검색(체인을 따라가면서검색)하면된다.
* enqueue 리소스를 사용할 준비가 되었다면, 연관된 enqueue구조(x$ksqeq구조등)로부터 하나의 로우를 획득한다.
하지만 동시에 동일한 enqueue로우를 다른 세션이 획득하는 것을 방지하기 위해 관련된 enqueue래치를 획득해야만 한다.
* 획득할 필요가 있는 래치는 세션이 사용하려는 enqueue의 유형에 따라 다르다. 예를들어, x$ksqeq구조로부터 로우를
획득하려면 enqueue 래치를 획득해야하고, x$ktadm 구조로부터 로우를 획득하려면 dml allocation 래치를 획득해야한다.
그리고 안전하게 enqueue 로우를 획득하자마자 래치를 릴리즈 해야한다.
* enqueue리소스를 사용할 준비가 되지 않았다면(enqueue hash chains 래치를 획득한 채로)x$ksqrs구조로부터
하나의 로우를 획득하고, 세션이 사용하려는 리소스를 표현하도록 표시하고, 해시 체인에 연결한 후 해당 로우와
연결된 enqueue로우를 획득한다.
* 이 모든것이 완료되면 enqueue hash chains래치를 릴리즈한다.

6)KGL Lock(및 Pin)

  • 라이브러리 캐시 내의 모든 오브젝트는 라이브러리 캐시 해시 버킷 내에 위치하며,
  • 버킷 번호는 오브젝트의 이름으로부터 계산된다.
  • 해시 버킷들은 라이브러리 캐시 래치의 수에따라 균등히 분배되며,
  • 래치의 최대 개수는 67개이다.
# 라이브 러리 캐시 오브젝트를 등록하기 위한 락과 enqueue 리소스를 등록하기 위한 락과의 가장 중요한 차이점은
  • 라이브러리 캐시와 관련된 락 구조는 두개의 set이 있다는 것이다.
  • 두개의 set은 KGL lock과 KGL pin이며
    이를 위해 owner 및 waiters 두개의 큐만을 사용한다.

7)Lock과 Pin

  • KGL lock(x$kglk구조 및 v$open_cursor뷰에서 확인가능)의 가장 중요한 역할은 동시성을 향상 시키는 것
  • 세션이 오브젝트(및SQL문)에 대한 KGL lock을 가지고 있다면,
  • 이는 parent 커서와 이와 관련된 child 커서에 대한 락을 가지고 있다는 것을 의미
  • 이러한 경우 오라클 코드는 오브젝틀르 획득하기 위해 library cache hash chain래치를 획득하고
  • 해시체인을 검색하는 대신, 해당 오브젝트의 주소로 직접 접근하는 것을 허용하는 메커니즘을 가지고 있다.
  • 11g에서는 KGL lock/KGL pin 메커니즘은 점진적으로 뮤텍스 메커니즘으로 대체되고있다.

MUTEX, PART 2

  • 라이브러리 캐시내의 locking과 pinning 매커니즘은 두개의 문제에 영향을 미친다.
    1. 모든일을 처리하기 위한 충분한 래치가 존재하지않는다.
    2. 관련 오브젝트를 메모리내에 생성하고, 적절히 표시하고, 링크드 리스트 내에 삽입(또는 반대로
    링크드 리스트로부터 제거한 후 shared pool에반납)하기 위해 너무나 많은일을 수행한다.
  • 11.2에서는 이와 관련된 메모리와 링크드 리스트를제거(즉, 해시 체인을 보호하기 위해 사용된 래치들을 제거)
    하였고 모두 뮤텍스로 대체되었다.
  • 뮤텍스는 마이크로-래치이며 매우 짧은 코드로 구현되었다.
  • 뮤텍스를 사용한다면 131072개의 버킷을 최대 67개의 래치로 보호하는 대신 버킷당 하나의 뮤텍스로 보호 할 수 있다.
  • 단점 : KGL lock과 KGL pin구조는 lock또는 pin을 소유한 세션 정보를 제공한다. 하지만 뮤텍스는 매우작으므로
    이와 관련된 정보를 제공하지 않는다.
    세션은 자신이 소유한 뮤텍스를 확인할 수 있지만 뮤텍스는 자신을 소유한 세션을 알 수 없다.
  • 래치는 process에 의해 소유되지만 뮤텍스는 session에 의해 소유된다.
  • 하나의 프로세스는 다수의 세션을 위해 동작 할 수 있다.
  • 동일한 프로세스 내에서 동작하는 두개의 세션간에 뮤텍스로 인한 데드락이 발생 할 수 있다.