디버깅은 실행중인 프로세스를 컨트롤할 수 있어 문제점을 찾거나 현재 로직을 확인 할 때 유용한 방법입니다.
이번에는 GDB를 활용하여 CUBRID server 프로세스를 디버깅해보도록 하겠습니다.
GDB 사용에 앞서 CUBRID 빌드가 되어 있어야 합니다.
CUBRID 빌드 관련 내용은 아래 링크를 확인하세요.
디버깅을 위해서는 'debug' 모드로 빌드해주세요.
1 2 | [root]vi build.sh build_mode="debug" | cs |
빌드시 에러가 발생한다면 표준에러만 파일로 리다이렉션하여 확인하는 것이 좋습니다.
1 2 | [root]vi build.sh 2> error.out vi error.out | cs |
빌드가 완료가 되었다면 bash_profile 파일에 PATH 관련 정보를 추가 저장합니다. CUBRID 위치는 build시 저장한 위치로 변경하세요.
1 2 3 4 5 6 7 8 9 10 | cd ~ [root]vi .bash_profile export CUBRID=/cubrid10.1/CUBRID export CUBRID_DATABASES=$CUBRID/databases export PATH=$PATH:$CUBRID/bin export LD_LIBRARY_PATH=$CUBRID/lib:$LD_LIBRARAY_PATH CLASSPATH=$CUBRID/jdbc/cubrid_jdbc.jar export CLASSPATH [root]source .bash_profile | cs |
demo DB를 생성합니다.
1 2 3 4 5 6 | cd $CUBRID mkdir databases cd databases mkdir demodb cd demodb ../../demo/make_cubrid_demo.sh | cs |
CUBRID service를 구동합니다.
1 2 | cubrid service start cubrid server start demodb | cs |
이제 디버깅 할 준비가 끝났습니다.
이번에는 cub_server 프로세스의 'log_flush_thread' 쓰레드에서 'group_commit' 파라메터가 어떻게 구현되어 있는지 확인해 보겠습니다.
'log_flush_thread'는 active log를 log volume에 flush하는 쓰레드로 주기적으로 혹은 요청을 받아 처리하게 되어있습니다.
cub_server 프로세스를 GDB로 디버깅을 시작합니다.
1 2 | [root] ps -ef | grep cub_server [root] gdb –tui cub_server 67310 | cs |
cub_server 프로세스는 gdb에 의해 멈춰 있는 상황입니다.
Thread를 확인해 봅니다.
1 | (gdb) thread apply all bt | cs |
'thread apply all bt' 명령어를 사용하면 상당히 많은 thread를 확인 할 수 있는데 그중 2번 thread가 'thread_log_flush_thread' 임을 확인 할 수 있습니다.
'thread 2' 로 해당 thread로 들어 갑니다.
1 | (gdb) thread 2 | cs |
GDB에는 'step', 'next', 'break' , 'continue' 등의 명령이 있습니다. 여기서는 이 네가지 명령에 대해서 설명하겠습니다.
step : 한줄씩 실행함. function으로 들어감.
next : 한줄씩 실행함. function으로 들어가지 않음.
break : 특정 위치에서 멈춤.
continue : break 이전까지 실행함.
특정함수를 Break 하고 continue 하도록 하겠습니다.
1 2 | (gdb) b logpb_flush_pages_direct (gdb) c | cs |
'log_flush_thread' 가 루프를 통해 동일 로직이 반복되는 것이지요.
지정한 Break point 를 제거 하겠습니다.
1 2 | (gdb) info b (gdb) d 1 | cs |
'next'을 사용하여 디버깅을 계속해 봅니다.
1 2 | (gdb) n (gdb) n | cs |
디버깅 중에 'GROUP_COMMIT_INTERVAL_MSECS' 파라메터와 관련있는 부분을 찾았습니다.
gc_interval 변수에 값을 넣고 있는데요. 해당 값을 확인해봅니다.
1 | (gdb) p gc_interval | cs |
해당 파라메터를 설정하지 않아 default 값인 '0'이 나오네요.
파라메터를 설정하고 디버깅하면 해당 값이 있을 때 어떻게 동작하는 지 확인 할 수 있겠습니다.
그전에 소스코드를 TEXT 에디터로 확인해 보는 것도 좋겠죠.
backtrace 명령어를 사용하여 현재 소스 코드 위치를 확인합니다.
/src/thread/thread.c 파일에 3737줄을 찾으면 해당 코드가 있겠네요.
'gc_interval' 변수에 집중하여 어떻게 구현되어 있는지 확인하면 더 효과적이겠습니다.
이후에는 직접 진행하면서 분석해보시기 바랍니다.
디버깅 위주의 내용을 적다보니 제가 분석하는 순서와는 조금 다른 점이 있는데요.
위에 내용이라면 먼저 'GROUP_COMMIT_INTERVAL_MSECS' 파라메터를 TEXT EDITOR등을 활용해서 전체 소스 검색을 하겠습니다.
그리고 'log_flush_thread'에 해당 내용이 있는 것을 찾고, 확인 후 디버깅을 시작하겠습니다.
지금까지 간단하게 알아본 cub_server 디버깅 방법이었습니다.