ssuperjun 님의 블로그
[과제5-4] DB 모니터링 프로그램 Python 변환 4편: Python 코드 작성 본문
[설계 계획]
C의 전역 변수, 구조체 → Python 클래스, 전역 리스트, dataclass
pthread → threading.Thread
signal → signal, time.sleep
MySQL C API → pymysql (prepared statement 유사 지원, bind 없이 바로 execute 가능)
로그 파일 → logging 또는 open(..., "a")
C스타일 error handling (goto, label) → try-except-finally
[코드 순서]
- import 및 전역 상수 정의
- @dataclass class DBHost
- init_table(user_id) -> List[DBHost]
- thread_main(user_id)
- thread_process_list(thread_idx, db_host_slice, log_db_conn)
- main()
디버그 및 예외 추적을 용이하게 하기 위해, try 블록 안의 코드 블록을 길게 만들지 않기
[고려한 점]
사용자 ID에 해당하는 서버 목록을 DB에서 불러오는 부분에서, C코드는 실패 시 segfault를 발생시켰지만
Python 코드는 segfault를 방지하고 실패하더라도 에러 로그를 파일에 남기기 위해, C 코드와는 실행 순서를 달리 함
[코드]
# process2.py
import sys
import signal
import pymysql
import threading
import time
import datetime
import logging
from dataclasses import dataclass
from typing import List
# ---------- 설정값 ----------
# MyMON DB 접속 정보
# 모니터링 대상 서버 목록이 저장된 일종의 메타 DB
MYMON_HOST = "10.생략" # 유출 안되게 주의
MYMON_USER = "admin_2026"
MYMON_PASSWD = ""
MYMON_DB = "MYMON"
MYMON_PORT = 13306
# 로그 DB 접속 정보
# 수집된 정보를 기록하는 DB
MYSQL_LOG_HOST = "10."
MYSQL_LOG_USER = "admin_2026"
MYSQL_LOG_PASSWD = ""
MYSQL_LOG_DB = "log"
MYSQL_LOG_PORT = 13306
# ServiceDB(수집 대상 서버) 접속 정보
# ThreadProcessList() 내부에서 각 dbHost[i]에 접속할 때 사용됨. dbHost[i]는 InitTable()에서 선언된 DB 호스트 정보 배열
MYSQL_USER = "admin"
MYSQL_PASSWD = ""
MYSQLHOST_NUM = 2000 # 감시할 서버 최대 개수
INTERVALTIME_SEC = 1 # 수집 주기 (1초)
THREADCOUNT = 15 # 최대 스레드 개수
HOSTNAME_LEN = 25
IP_LEN = 15
LOGFILE_LEN = 18
# ---------- 디버그 모드 ----------
DEBUG = False # 필요 시 True로 설정
# ---------- 구조체 ----------
@dataclass
class dbHost_struct:
host: str
port: int
ip: str
service: str
@dataclass
class Interval_Server:
nStart: int
nEnd: int
# ---------- 전역 변수 ----------
dbHost: List[dbHost_struct] = [] # 감시할 서버 정보 리스트
g_IntervalServer: List[Interval_Server] = [] # 스레드별 서버 인덱스 범위
g_nServerCnt = 0 # 감시할 서버 개수
g_strCurrTime = "" # 수집 시간 (로그 timestamp)
g_strCurrDate = ""
g_strPrevTime = ""
g_nCount = 0 # 수집 횟수
strUserID = "" # 사용자 ID (argv[1]에 해당)
g_fCheckLog = None # 로그 파일 핸들
g_nTimeout = 2 # MySQL 접속 타임아웃 (초)
# ---------- 로그 설정 ----------
logging.basicConfig(
filename='monitor.log',
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s'
)
# ---------- 시간 문자열 생성 ----------
def get_time_strings():
now = datetime.datetime.now()
g_strCurrTime = now.strftime('%Y%m%d%H%M%S')
g_strCurrDate = now.strftime('%Y%m%d')
return g_strCurrTime, g_strCurrDate
# 감시(모니터링)할 서버 목록을 MyMon DB에서 조회하여 dbHost 배열에 저장
# ThreadMain 함수 첫부분에 한번만 등장할 예정
def InitTable() -> int:
global dbHost, g_nServerCnt, strUserID, g_mysql
strQuery = (
"SELECT host, "
" port, "
" SUBSTRING_INDEX(ip, '|', -1), "
" service_detail "
" FROM MYMON.serverinfo B, MYMON.admin_user C "
" WHERE B.status = 1 "
" AND B.db_charged = CONVERT(C.admin_name USING euckr) "
" AND MONITORING <> '' "
" AND repl_state != 'MM' "
f" AND C.kerberos_id = '{strUserID}' "
" ORDER BY 1"
)
# MyMON DB connect
try:
g_mysql = pymysql.connect(
host=MYMON_HOST,
user=MYMON_USER,
password=MYMON_PASSWD,
database=MYMON_DB,
port=MYMON_PORT,
charset='utf8',
connect_timeout=g_nTimeout
)
except pymysql.MySQLError as e:
print(f"[InitTable] Failed to connect to database: Error: {e}")
return -1
# Cursor create
# 커서: 쿼리 결과를 순회하고 조작하는 객체
try:
cursor = g_mysql.cursor()
except Exception as e:
print(f"[InitTable] Failed to create cursor: Error: {e}")
g_mysql.close()
return -1
# SET NAMES
# UTF-8 문자셋 설정
try:
cursor.execute("SET NAMES utf8")
except Exception as e:
print(f"[InitTable] Failed to set charset: Error: {e}")
cursor.close()
g_mysql.close()
return -1
# Execute query
try:
cursor.execute(strQuery)
rows = cursor.fetchall()
except Exception as e:
print(f"[InitTable] Failed to query database item: Error: {e}")
cursor.close()
g_mysql.close()
return -1
cursor.close()
g_mysql.close()
# Result check
# 쿼리 실행은 됐지만, 쿼리 결과가 없는 경우
if not rows:
print("[InitTable] Select Server Error: result is empty")
return -1
# 쿼리 결과를 받아서, 각 레코드를 순회하며 dbHost[] 배열에 저장
# 이 배열은 이후 ThreadProcessList 함수에서 수집 루프에 사용됨
dbHost.clear()
for row in rows:
dbHost.append(
dbHost_struct(
host=row[0],
port=int(row[1]),
ip=row[2],
service=row[3]
)
)
g_nServerCnt = len(dbHost)
return 0
# 핵심 수집 실행 로직
# 각 스레드별로 수집 대상 서버 목록을 InitTable 함수에서 받아와서, 수집 작업을 병렬 처리한 뒤 결과를 LogDB에 기록
# InitTable 함수 1번 호출, ThreadProcessList 함수 반복 호출됨
def ThreadMain(dummy_arg=None):
global g_IntervalServer, g_nServerCnt, dbHost
global g_strCurrTime, g_strCurrDate, g_nCount, g_fCheckLog
# 현재 시간 문자열 준비
now = datetime.datetime.now()
g_strCurrTime = now.strftime("%Y%m%d%H%M%S")
g_strCurrDate = now.strftime("%Y%m%d")
# 로그 파일명 생성
strFileNameLog = f"./log/_myproc_{strUserID}.log.{now.strftime('%Y%m%d')}"
# 스크립트 실행 디렉토리 안에 log 디렉토리가 없으면 에러
try:
g_fCheckLog = open(strFileNameLog, "a")
except Exception as e:
print(f"Cannot create log file Error! {e}")
exit(-1)
# 서버 목록 초기화
# 사용자 ID에 해당하는 서버 목록을 DB에서 불러옴 - dbHost[], g_nServerCnt
# 이 부분 실패 시 에러 로그를 파일에 남기기 위해, C 코드와는 실행 순서를 달리 함 -> segmentation fault(segfault) 방지
if InitTable() == -1:
print("### MyMon ServerDB tb_serverinfo Table Error!! ###")
g_fCheckLog.write(f"{now.strftime('%Y-%m-%d %H:%M:%S')}, MyMon ServerDB tb_serverinfo Table Error!!\n")
g_fCheckLog.close()
exit(-1)
# 스레드 수 결정
if g_nServerCnt > THREADCOUNT:
nThreadCount = THREADCOUNT
else:
nThreadCount = 1
nIntervalCount = g_nServerCnt // nThreadCount
# 스레드별 할당 범위 설정
g_IntervalServer = [Interval_Server(0, 0) for _ in range(nThreadCount)]
for i in range(nThreadCount):
start_idx = i * nIntervalCount
end_idx = start_idx + nIntervalCount - 1
if i == nThreadCount - 1: # 마지막 스레드는 나머지 포함
end_idx = g_nServerCnt - 1
g_IntervalServer[i] = Interval_Server(nStart=start_idx, nEnd=end_idx)
# 실행 시간 측정 시작
start_time = time.time()
threads = []
for i in range(nThreadCount):
t = threading.Thread(target=ThreadProcessList, args=(i,))
threads.append(t)
t.start()
for t in threads:
t.join()
# 실행 시간 측정 종료
end_time = time.time()
dElapsedTime = end_time - start_time
per_server = dElapsedTime / g_nServerCnt if g_nServerCnt > 0 else 0
# 로그 기록
log_line = f"\n{now.strftime('%Y-%m-%d %H:%M:%S')}, Server:{g_nServerCnt}, Elapsed:{dElapsedTime:.3f}, perServer:{per_server:.3f}\n"
print(log_line.strip())
g_fCheckLog.write(log_line)
g_fCheckLog.close()
# 스레드별로 각자 맡은 대상 서버에 접속해 정보 수집, 로그DB에 기록
def ThreadProcessList(nOrder: int):
global dbHost, g_IntervalServer, g_strCurrTime, g_strCurrDate, g_nCount
# Log DB 연결
try:
log_db = pymysql.connect(
host=MYSQL_LOG_HOST,
user=MYSQL_LOG_USER,
password=MYSQL_LOG_PASSWD,
database=MYSQL_LOG_DB,
port=MYSQL_LOG_PORT,
charset='utf8',
cursorclass=pymysql.cursors.Cursor,
connect_timeout=g_nTimeout
)
except pymysql.MySQLError as e:
print(f"Failed to connect to meta database: Error: {e}")
time.sleep(1)
return
# 서버 범위 가져오기
nStart = g_IntervalServer[nOrder].nStart
nEnd = g_IntervalServer[nOrder].nEnd
for i in range(nStart, nEnd + 1):
host = dbHost[i].host
port = dbHost[i].port
ip = dbHost[i].ip
service = dbHost[i].service
# 대상 서버 접속 시도
try:
svc_db = pymysql.connect(
host=host,
user=MYSQL_USER,
password=MYSQL_PASSWD,
database='mysql',
port=port,
charset='utf8',
cursorclass=pymysql.cursors.Cursor,
connect_timeout=g_nTimeout
)
except pymysql.MySQLError as e:
if port != 0:
print(f" > [{host}:{port}], Failed to connect to database: Error: {e}")
continue
# 특정 서버 제외 (ifsr-dev*)
if host.startswith("ifsr-dev"):
svc_db.close()
continue
try:
# 쿼리 실행: processlist, innodb status, version, innodb lock
# ================================
# SHOW FULL PROCESSLIST
# ================================
cursor = None
try:
cursor = svc_db.cursor() # 대상 서버 커서(쿼리 결과를 순회하는 객체) 생성
except Exception as e:
print(f" * processList cursor create failed: {host} {port}")
print(f" * MySQL Error Message: {e}")
svc_db.close()
continue
try:
cursor.execute("SHOW FULL PROCESSLIST") # C 코드에선 strProcess 문자열을 사용했으나, 여기선 바로 쿼리문을 넣음. 가독성
result = cursor.fetchall()
except Exception as e:
print(f" * Query processList Result result is null: {host} {port}")
print(f" * MySQL Error Message: {e}")
cursor.close()
svc_db.close()
continue # goto QUERYERROR;과 같은 효과
if not result:
print(f" * processList mysql_num_rows is Zero: {host} {port}")
cursor.close()
svc_db.close()
continue
for row in result:
# row mapping (SHOW FULL PROCESSLIST)
# 0: Id, 1: User, 2: Host, 3: db, 4: Command, 5: Time, 6: State, 7: Info
# ----------------
# Filter conditions (C 코드 그대로)
# ----------------
if (
(row[1] == "system user" and (row[6] or "").startswith("Waiting for master")) or
row[1] == "event_scheduler" or
(row[4] == "Sleep" and int(row[5] or 0) < 20000) or
row[4] == "Binlog Dump"
):
continue
# ----------------
# 값 매핑
# ----------------
str_logtime = g_strCurrTime
str_logdate = g_strCurrDate
str_host = host
nPort = port
str_Pid = str(row[0] or "0")
str_user = row[1] or "NULL"
# ip:port → ip 분리
str_ip = row[2] or "NULL"
if ":" in str_ip:
str_ip = str_ip.split(":")[0]
str_db = row[3] or "NULL"
str_command = row[4] or "NULL"
str_ExecTime = str(row[5] or "0")
str_state = row[6] or "NULL"
str_query = row[7] or "NULL"
nCount = g_nCount
# ----------------
# Warning log 출력 (C 코드 조건 그대로)
# ----------------
if (
(str_state.startswith("Locked") and int(str_ExecTime) > 5) or
str_state.startswith("Killed") or
(str_state.startswith("Sending") and int(str_ExecTime) > 5) or
(str_state.startswith("Waiting") and int(str_ExecTime) > 5) or
(str_command.startswith("Query") and int(str_ExecTime) > 5) or
(str_state.startswith("Sorting") and int(str_ExecTime) > 5)
):
warn_msg = (
f"\n {str_host}:{nPort} [{service}] - "
f"State: {str_state}, Time: {str_ExecTime}, "
f"User: {str_user}@{str_ip}\n"
f" DataBase: {str_db}\n"
f" Query : {str_query}\n"
)
print(warn_msg, end="")
if g_fCheckLog:
g_fCheckLog.write(warn_msg)
# ----------------
# INSERT INTO processlist
# ----------------
try:
log_cursor = log_db.cursor()
except Exception as e:
print(f" * processlist insert cursor error: {e}")
continue
try:
log_cursor.execute(
"""
INSERT INTO processlist
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,COMPRESS(%s),%s)
""",
(
str_logtime,
str_logdate,
str_host,
nPort,
str_Pid,
str_user,
str_ip,
str_db,
str_command,
str_ExecTime,
str_state,
str_query,
nCount,
),
)
log_db.commit()
except Exception as e:
print(f" * processlist insert failed: {host} {port}")
print(f" * MySQL Error Message: {e}")
finally:
log_cursor.close()
cursor.close()
# ================================
# SHOW ENGINE INNODB STATUS
# ================================
try:
cursor = svc_db.cursor()
cursor.execute("SHOW ENGINE INNODB STATUS")
result = cursor.fetchall()
except Exception as e:
print(f" * InnoDB Status query failed: {host} {port}")
print(f" * MySQL Error Message: {e}")
cursor.close()
continue
if not result:
print(f" * InnoDB Status result is empty: {host} {port}")
cursor.close()
continue
for row in result:
# ----------------
# 버전별 InnoDB Status 위치 분기
# ----------------
if row[0] and row[0].startswith("InnoDB"):
# MySQL 5.1+
str_status = row[2] if row[2] else "NULL"
nFlag = 1
else:
# MySQL 5.0
str_status = row[0] if row[0] else "NULL"
nFlag = 0
str_logtime = g_strCurrTime
str_logdate = g_strCurrDate
str_host = host
nPort = port
# ----------------
# INSERT INTO innodb
# ----------------
try:
log_cursor = log_db.cursor()
except Exception as e:
print(f" * innodb insert cursor error: {e}")
cursor.close()
continue
try:
log_cursor.execute(
"""
INSERT INTO innodb
VALUES (%s, %s, %s, %s, COMPRESS(%s))
""",
(
str_logtime,
str_host,
nPort,
str_status,
),
)
log_db.commit()
except Exception as e:
print(f" * innodb insert failed: {host} {port}")
print(f" * MySQL Error Message: {e}")
finally:
log_cursor.close()
cursor.close()
# ================================
# SHOW MYSQL VERSION
# ================================
try:
cursor = svc_db.cursor()
cursor.execute("SELECT VERSION()")
result = cursor.fetchone()
except Exception as e:
print(f" * VERSION query failed: {host} {port}")
print(f" * MySQL Error Message: {e}")
cursor.close()
continue
if not result:
print(f" * VERSION result is empty: {host} {port}")
cursor.close()
continue
str_version = result[0]
cursor.close()
# ----------------
# MySQL 버전 파싱
# ----------------
# 예: "5.7.35-log" or "8.0.32"
if str_version.startswith("5.7") or str_version.startswith("5.6"):
str_lock_query = """
SELECT r.trx_mysql_thread_id as waiting_thread,
r.trx_id as waiting_trx_id,
r.trx_query as waiting_query,
b.trx_mysql_thread_id as blocking_thread,
b.trx_id as blocking_trx_id,
b.trx_query as blocking_query
FROM information_schema.innodb_lock_waits w
JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id
"""
elif str_version.startswith("8.0"):
str_lock_query = """
SELECT r.trx_mysql_thread_id AS waiting_thread,
r.trx_id AS waiting_trx_id,
r.trx_query AS waiting_query,
b.trx_mysql_thread_id AS blocking_thread,
b.trx_id AS blocking_trx_id,
b.trx_query AS blocking_query
FROM performance_schema.data_lock_waits dw
JOIN information_schema.innodb_trx r ON r.trx_id = dw.requesting_trx_id
JOIN information_schema.innodb_trx b ON b.trx_id = dw.blocking_trx_id
"""
else:
print(f" * MySQL Version [{str_version}] not supported for LOCK analysis: {host} {port}")
continue
# ================================
# SHOW INNODB LOCK
# ================================
if nFlag == 0: # MySQL 5.0 이하는 LOCK 분석 스킵
continue
try:
cursor = svc_db.cursor()
cursor.execute(str_lock_query)
result = cursor.fetchall()
except Exception as e:
print(f" * InnoDB Lock query failed: {host} {port}")
print(f" * MySQL Error Message: {e}")
cursor.close()
continue
if not result:
print(f" * InnoDB Lock result is empty: {host} {port}")
cursor.close()
continue
for row in result:
str_logtime = g_strCurrTime
str_logdate = g_strCurrDate
str_host = host
nPort = port
try:
log_cursor = log_db.cursor()
except Exception as e:
print(f" * innodb_lock insert cursor error: {e}")
continue
try:
waiting_thread = int(row[0]) if row[0] else 0
waiting_trx_id = row[1] or "0"
waiting_query = row[2] or "0"
blocking_thread = int(row[3]) if row[3] else 0
blocking_trx_id = row[4] or "0"
blocking_query = row[5] or "0"
log_cursor.execute(
'''
INSERT INTO innodb_lock
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
''',
(
str_logtime,
str_logdate,
str_host,
nPort,
waiting_trx_id,
waiting_thread,
0, # waiting_time (optional)
waiting_query,
blocking_trx_id,
blocking_thread,
0, # blocking_time (optional)
blocking_query,
)
)
log_db.commit()
except Exception as e:
print(f" * innodb_lock insert failed: {host} {port}")
print(f" * MySQL Error Message: {e}")
finally:
log_cursor.close() # log_db 커서 종료
cursor.close() # 대상 서버 커서 종료
finally: # 예외 발생 여부와 상관없이 항상 접속 종료
svc_db.close() # 대상 서버 접속 종료
log_db.close() # Log DB 접속 종료
# 시그널 핸들러: SIGALRM 수신 시 ThreadMain 호출
def signal_handler(signum, frame):
global g_nCount
ThreadMain(1)
g_nCount += 1
# 프로그램 진입점. signal handler 설정, 주기적 호출 준비
# ThreadMain 함수 호출
# 실행 명령어 python process2.py admin01 실행 시, argv[1]은 "admin01"
def main():
global strUserID, g_nCount
if len(sys.argv) != 2:
print("Usage: python process2.py <admin_id>")
sys.exit(1)
strUserID = sys.argv[1]
# 최초 1회 수집 수행
ThreadMain(1)
# 디버그 모드: 무한히 직접 호출
if DEBUG:
while True:
ThreadMain(1)
g_nCount += 1
time.sleep(INTERVALTIME_SEC) # C 코드에선 sleep 없이 바로 호출했으나, 여기선 약간의 지연 추가
return
# 시그널 핸들러 등록
signal.signal(signal.SIGALRM, signal_handler)
while True:
# INTERVALTIME_SEC 초 후 SIGALRM 발생 예약
signal.alarm(INTERVALTIME_SEC)
signal.pause() # SIGALRM 대기
if __name__ == "__main__":
main()
[프롬프트]
C 코드를 Python으로 변환하고 싶어. process2.c를 process2.py로 바꿔줘. process2.c는 모니터링 프로그램이고 다음과 같은 특징이 있어.
여러 MySQL 서버에 접속해 아래의 정보를 주기적으로 수집하고, 로그 DB에 기록
[주요 기능]
특정 관리자의 책임 서버 목록을 조회 (DB에서)
각 서버의 SHOW PROCESSLIST, SHOW ENGINE INNODB STATUS, INNODB LOCK 정보를 수집
쓰레드로 병렬 수집 (최대 15개 쓰레드)
수집된 결과를 로그 파일과 DB에 저장
수집 주기는 INTERVALTIME_SEC (1초로 설정해둠)
주요 흐름 요약
1. 실행 (main)
→ 사용자 ID(argv[1])을 인자로 받아 관리 대상 서버 목록 조회 준비
2. InitTable
→ MYMON DB에서 admin_user와 serverinfo 테이블을 조인하여 대상 서버 정보 획득
→ 구조체 배열 dbHost[]에 저장
3. ThreadMain
→ 현재 시간 기반 로그 파일 생성
→ 수집 대상 서버를 쓰레드 수에 맞게 분할
→ pthread_create()로 ThreadProcessList() 실행
4. ThreadProcessList
→ 각 서버에 대해:
* SHOW FULL PROCESSLIST → 비정상 쿼리/긴 쿼리 감지 및 로깅
* SHOW ENGINE INNODB STATUS → InnoDB 내부 상태 수집
* INNODB_LOCK_WAITS, INNODB_TRX → 락 대기 정보 수집
→ 모든 결과는 log DB에 insert (stmt 방식 + compress)
[함수별 내용]
[main 함수]
프로그램 진입점. signal handler 설정, 주기적 호출 준비
[흐름]
사용자 ID(argv[1])를 strUserID에 저장
시그널 핸들러 설정: SIGALRM 시 ThreadMain 함수 호출
무한 루프: SIGALRM 시그널을 주기적으로 발생시켜 ThreadMain 호출
디버그 모드일 경우, 무한 루프에서 ThreadMain을 계속 호출하고 g_nCount 증가로 호출 횟수 추적
[InitTable 함수]
감시(모니터링)할 서버 목록을 MyMon DB에서 조회하여 dbHost 배열에 저장
[흐름]
사용자 ID(strUserID)에 해당하는 감시 대상 서버 목록 조회 쿼리 저장
MyMon DB에 연결
앞서 만든 쿼리를 실행
쿼리 실행 성공한 경우, 쿼리 결과를 받아서, 각 레코드를 순회하며 dbHost[] 배열에 저장. 이 배열은 이후 ThreadProcessList 함수에서 수집 루프에 사용됨
쿼리 실행은 됐지만, 쿼리 결과가 없을 경우 에러 핸들링
[ThreadMain 함수]
각 스레드별로 수집 대상 서버 목록을 InitTable 함수에서 받아와서, 수집 작업(ThreadProcessList 함수)을 병렬 처리한 뒤 결과를 LogDB에 기록
[흐름]
InitTable 함수를 호출해 서버 목록 초기화(사용자 ID에 해당하는 서버 목록을 DB에서 불러옴 - dbHost[], g_nServerCnt)
현재 시간 정보를 얻어와서 로그 파일 이름 생성
스레드 생성 개수: 감시할 서버 개수가 많다면 THREADCOUNT(15)개, 적다면 1개
스레드별로 수집할 서버 범위 설정
Thread Run: 각 스레드는 ThreadProcessList 함수 실행, g_IntervalServer[i] 범위의 서버들을 수집 처리
Thread Wait: 모든 스레드가 종료될 때까지 대기
수행시간 등 로그 파일에 기록
리소스 해제
[ThreadProcessList(void *arg) 함수]
[코드 흐름]
변수들 미리 선언
스레드별로 각자 맡은 대상 서버에 접속해 정보 수집, 로그DB에 기록
Show processlist, SHOW ENGINE INNODB STATUS, SHOW MYSQL VERSION, SHOW INNODB LOCK 구현 부분은 분량이 많지만, 흐름 자체가 동일했음
[구체적인 흐름]
스레드가 대상 서버 접속에 성공한 경우
에러 처리: 쿼리 실행 실패 경우, 쿼리 결과가 null인 경우, 쿼리 결과는 정상적으로 받아왔지만, row 수가 0인 경우
쿼리 결과를 정상적으로 가져왔다면, 각 row(쿼리 실행 결과의 row 하나는 곧 프로세스 하나의 레코드를 의미)별로 처리
stmt과 bind를 사용하여 쿼리 준비, 실행
[참고]
SHOW INNODB LOCK 구현부의 경우, 실행할 InnoDB Lock 쿼리는 SHOW MYSQL VERSION 구현부에서 생성, 저장됨
'인턴' 카테고리의 다른 글
| [과제5-6] DB 모니터링 프로그램 Python 변환 6편: 추가 구현, 조사 (1) | 2026.01.19 |
|---|---|
| [과제5-5] DB 모니터링 프로그램 Python 변환 5편: Python 의존성 패키지 설치, 코드 실행 테스트 (0) | 2026.01.17 |
| [과제5-3] DB 모니터링 프로그램 Python 변환 3편: MySQL Client 설치, C 의존성 패키지 설치, C 코드 실행 테스트 (0) | 2026.01.17 |
| [과제5-2] DB 모니터링 프로그램 Python 변환 2편: process2.c 코드 분석 (0) | 2026.01.17 |
| [과제5-1] DB 모니터링 프로그램 Python 변환 1편: 과제 개요, 파일 용도 분석, Python 변환 (0) | 2026.01.17 |