지식이 늘었다/Sqlite

SQLITE_BUSY 문제에 대한 해결방안

moneydeveloper 2020. 8. 10. 16:11
반응형

여러 Process 가 같은 Database 를 read/write 를 하는 경우 SQLITE_BUSY 가 return 되면서 원하는 동작을 하지 못하는 문제가 있었다.

 

어떻게 해결하였는지 기술하겠다. 

 

우선 SQLITE_BUSY 가 어떤 상황에서 발생하는지 referece 를 참조하자.

친절하게 예시까지 쓰여져있다. 

 

https://www.sqlite.org/rescode.html#busy

 

Result and Error Codes

Overview Many of the routines in the SQLite C-language Interface return numeric result codes indicating either success or failure, and in the event of a failure, providing some idea of the cause of the failure. This document strives to explain what each of

www.sqlite.org

간단하게 말하자면 "A Process 가 write transaction 을 걸어놓은 상태에 B Process 가 새로운 Write Transaction 을 시도할때 SQLITE_BUSY 에러가 발생"할 수 있다. 라고 설명하고 있다.

(실 사용중에 발생한 case 는 A Process 에서 Write transaction 이 걸려있는 상태에서 B Process 가 Read 를 시도할 때 발생하였었다.)

 

해결책 1 - busy timeout 을 설정.

sqlite 에서 제공해주는 api 를 이용하여 waiting 시간을 늘려주는 방식이다.

즉 A Process 가 transaction 을 잡고 있더라도 특정 시간 만큼 기다려보는 동작이다. 

 

값을 설정하기 위해서는 아래 function 을 사용한다. 

 

int sqlite3_busy_timeout(sqlite3*, int ms); 

//첫번째 인자 : db handle pointer

//두번째 인자 : 기다릴 시간 ( ms ) 

 

reference : https://www.sqlite.org/c3ref/busy_timeout.html

 

Set A Busy Timeout

This routine sets a busy handler that sleeps for a specified amount of time when a table is locked. The handler will sleep multiple times until at least "ms" milliseconds of sleeping have accumulated. After at least "ms" milliseconds of sleeping, the handl

www.sqlite.org

이 해결책에는 치명적인 오류가 존재한다. 

설정한 시간 이상 기다리게 된다면 ? 결국 SQLITE_BUSY 가 똑같이 return 된다.  완전한 해결책이라고 보기 어렵다.

그래서 다른 해결책이 필요하다.

 

해결책 2 - call back 함수를 이용.

sqlite 에서 api 를 제공해준다. sqlite_busy 가 return 될 시에 동작할 함수를 개발자가 직접 구현하여 call back 형식으로 등록 할 수 있다.

 

int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);

//첫번째 인자 : db handle pointer

//두번째 인자 : call back 함수 pointer.

//세번째 인자 : call back 함수 첫번째 인수.

// call back 함수의 첫번째 인자 : handler 의 세번째 인자

// call back 함수의 두번재 인자 : 몇번째 busy 인지에 대한 값,

https://www.sqlite.org/c3ref/busy_handler.html

 

Register A Callback To Handle SQLITE_BUSY Errors

The sqlite3_busy_handler(D,X,P) routine sets a callback function X that might be invoked with argument P whenever an attempt is made to access a database table associated with database connection D when another thread or process has the table locked. The s

www.sqlite.org

위와 같은 해결책이 존재하지만 결국 이 문제를 100% 회피할 방법은 존재하지 않는다.

만약 A Process 에서 Transaction 잡아놓고 절때 풀지 않는다면 ? B Process 에서는 DB 접근을 할 수 없게 된다. 물론 A Process 쪽에서 수정이 되어야 하겠지만 개발하면서 느끼는 건데 아무도 믿으면 안되는것 같다. 

 

그럼 어떻게 해야 할까?

 

"설계 할 때 실시간으로 여러 process 가 read / write 를 하는 DB를 만들지 말자"

 

이다. 

 

결론이 아쉽지만 process 간 데이터의 공유가 필요하다면 Database 관리는 한쪽에서만 하고 공유 메모리를 사용하거나 혹은 IPC를 통해 주고 받는방향으로 처리를 하는게 위와 같은 문제를 피할 수 있을 것이다. 

반응형