libzdb --- mysql 的一个数据库连接池代码分析
谭富
2023-12-01
安装了re2c
运行bootstrap后生成了
autom4te.cache目录,m4目录
文件
config\compile
config\config.guess
config\config.sub
config\ltmain.sh
src\xconfig.h.in
test\Makefile.in
aclocal.m4
configure
Makefile.in
configure后生成了
src\stamp-h1 src\xconfig.h(由xconfig.h.in生成)
test\Makefile
tools\bin\filterh,由tools\filterh下的filterh\filterh.l生成
configure的时候执行了cd ./tools/filterh && $CC lex.yy.c -o ../bin/filterh && rm -f lex.yy.o
config.log config.status libtool Makefile zdb.pc(由zdb.pc.in生成)
make 创建了头文件到zdb目录,编译src目录下的代码,生成库到顶层目录。编译test目录下的多个程序
noinst_PROGRAMS,编译的二进制也被放在了.libs目录
filterh的作用是去掉//<<...//>>或者#<<...#>>之间的内容。\000-\377是八进制表示,从0到255
./tools/bin/filterh < src/zdb.h > zdb/zdb.h || exit 1
./tools/bin/filterh < src/db/ConnectionPool.h > zdb/ConnectionPool.h || exit 1
./tools/bin/filterh < src/db/Connection.h > zdb/Connection.h || exit 1
./tools/bin/filterh < src/db/ResultSet.h > zdb/ResultSet.h || exit 1
./tools/bin/filterh < src/net/URL.h > zdb/URL.h || exit 1
./tools/bin/filterh < src/db/PreparedStatement.h > zdb/PreparedStatement.h || exit 1
./tools/bin/filterh < src/exceptions/SQLException.h > zdb/SQLException.h || exit 1
./tools/bin/filterh < src/exceptions/Exception.h > zdb/Exception.h || exit 1
make all-recursive
make[1]: Entering directory `/home/liuwb/Desktop/code/libzdb-code'
Making all in .
make[2]: Entering directory `/home/liuwb/Desktop/code/libzdb-code'
/bin/bash ./libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I./src -I/usr/include/postgresql -I/usr/include/mysql -I/usr/include/mysql -I/usr/include/postgresql -Isrc -Isrc/util -Isrc/net -Isrc/db -Isrc/exceptions -I/usr/include/postgresql -I/usr/include/mysql -Wno-address -Wno-pointer-sign -g -O2 -Wall -Wunused -Wno-unused-label -funsigned-char -std=gnu99 -c -o src/util/Str.lo src/util/Str.c
libtool: compile: gcc -DHAVE_CONFIG_H -I. -I./src -I/usr/include/postgresql -I/usr/include/mysql -I/usr/include/mysql -I/usr/include/postgresql -Isrc -Isrc/util -Isrc/net -Isrc/db -Isrc/exceptions -I/usr/include/postgresql -I/usr/include/mysql -Wno-address -Wno-pointer-sign -g -O2 -Wall -Wunused -Wno-unused-label -funsigned-char -std=gnu99 -c src/util/Str.c -fPIC -DPIC -o src/util/.libs/Str.o
libtool: compile: gcc -DHAVE_CONFIG_H -I. -I./src -I/usr/include/postgresql -I/usr/include/mysql -I/usr/include/mysql -I/usr/include/postgresql -Isrc -Isrc/util -Isrc/net -Isrc/db -Isrc/exceptions -I/usr/include/postgresql -I/usr/include/mysql -Wno-address -Wno-pointer-sign -g -O2 -Wall -Wunused -Wno-unused-label -funsigned-char -std=gnu99 -c src/util/Str.c -o src/util/Str.o >/dev/null 2>&1
...
/usr/bin/re2c -b src/net/URL.re > src/net/URL.c
...
/bin/bash ./libtool --tag=CC --mode=link gcc -Wno-address -Wno-pointer-sign -g -O2 -Wall -Wunused -Wno-unused-label -funsigned-char -std=gnu99 -L/usr/lib/x86_64-linux-gnu -lmysqlclient -lpthread -lz -lm -ldl -L/usr/lib -lpq -version-info 11:0:0 -L/usr/lib -L/usr/lib/x86_64-linux-gnu -lmysqlclient -lpthread -lz -lm -ldl -o libzdb.la -rpath /usr/local/lib src/util/Str.lo src/util/Vector.lo src/util/StringBuffer.lo src/system/Mem.lo src/system/System.lo src/system/Time.lo src/db/ConnectionPool.lo src/db/Connection.lo src/db/ResultSet.lo src/db/PreparedStatement.lo src/exceptions/assert.lo src/exceptions/Exception.lo src/net/URL.lo src/db/mysql/MysqlConnection.lo src/db/mysql/MysqlResultSet.lo src/db/mysql/MysqlPreparedStatement.lo src/db/postgresql/PostgresqlConnection.lo src/db/postgresql/PostgresqlResultSet.lo src/db/postgresql/PostgresqlPreparedStatement.lo src/db/sqlite/SQLiteConnection.lo src/db/sqlite/SQLiteResultSet.lo src/db/sqlite/SQLitePreparedStatement.lo -lsqlite3 -lpthread
libtool: link: gcc -shared -fPIC -DPIC src/util/.libs/Str.o src/util/.libs/Vector.o src/util/.libs/StringBuffer.o src/system/.libs/Mem.o src/system/.libs/System.o src/system/.libs/Time.o src/db/.libs/ConnectionPool.o src/db/.libs/Connection.o src/db/.libs/ResultSet.o src/db/.libs/PreparedStatement.o src/exceptions/.libs/assert.o src/exceptions/.libs/Exception.o src/net/.libs/URL.o src/db/mysql/.libs/MysqlConnection.o src/db/mysql/.libs/MysqlResultSet.o src/db/mysql/.libs/MysqlPreparedStatement.o src/db/postgresql/.libs/PostgresqlConnection.o src/db/postgresql/.libs/PostgresqlResultSet.o src/db/postgresql/.libs/PostgresqlPreparedStatement.o src/db/sqlite/.libs/SQLiteConnection.o src/db/sqlite/.libs/SQLiteResultSet.o src/db/sqlite/.libs/SQLitePreparedStatement.o -L/usr/lib/x86_64-linux-gnu -L/usr/lib -lpq -lmysqlclient -lz -lm -ldl /usr/lib/x86_64-linux-gnu/libsqlite3.so -lpthread -g -O2 -Wl,-soname -Wl,libzdb.so.11 -o .libs/libzdb.so.11.0.0
libtool: link: (cd ".libs" && rm -f "libzdb.so.11" && ln -s "libzdb.so.11.0.0" "libzdb.so.11")
libtool: link: (cd ".libs" && rm -f "libzdb.so" && ln -s "libzdb.so.11.0.0" "libzdb.so")
libtool: link: ar cru .libs/libzdb.a src/util/Str.o src/util/Vector.o src/util/StringBuffer.o src/system/Mem.o src/system/System.o src/system/Time.o src/db/ConnectionPool.o src/db/Connection.o src/db/ResultSet.o src/db/PreparedStatement.o src/exceptions/assert.o src/exceptions/Exception.o src/net/URL.o src/db/mysql/MysqlConnection.o src/db/mysql/MysqlResultSet.o src/db/mysql/MysqlPreparedStatement.o src/db/postgresql/PostgresqlConnection.o src/db/postgresql/PostgresqlResultSet.o src/db/postgresql/PostgresqlPreparedStatement.o src/db/sqlite/SQLiteConnection.o src/db/sqlite/SQLiteResultSet.o src/db/sqlite/SQLitePreparedStatement.o
libtool: link: ranlib .libs/libzdb.a
libtool: link: ( cd ".libs" && rm -f "libzdb.la" && ln -s "../libzdb.la" "libzdb.la" )
make[2]: Leaving directory `/home/liuwb/Desktop/code/libzdb-code'
Making all in test
make[2]: Entering directory `/home/liuwb/Desktop/code/libzdb-code/test'
gcc -DHAVE_CONFIG_H -I. -I../src -I../src -I../src/util -I../src/net -I../src/db -I../src/exceptions -I/usr/include/postgresql -I/usr/include/mysql -Wno-address -Wno-pointer-sign -g -O2 -Wall -Wunused -Wno-unused-label -funsigned-char -std=gnu99 -c -o unit.o unit.c
/bin/bash ../libtool --tag=CC --mode=link gcc -Wno-address -Wno-pointer-sign -g -O2 -Wall -Wunused -Wno-unused-label -funsigned-char -std=gnu99 -L/usr/lib -L/usr/lib/x86_64-linux-gnu -lmysqlclient -lpthread -lz -lm -ldl -o unit unit.o ../libzdb.la -lsqlite3 -lpthread
libtool: link: gcc -Wno-address -Wno-pointer-sign -g -O2 -Wall -Wunused -Wno-unused-label -funsigned-char -std=gnu99 -o .libs/unit unit.o -L/usr/lib -L/usr/lib/x86_64-linux-gnu ../.libs/libzdb.so -lpq -lmysqlclient -lz -lm -ldl /usr/lib/x86_64-linux-gnu/libsqlite3.so -lpthread
...
make doc
doxygen config/Doxyfile
在doc/api-docs目录下生成了png,_8h.html,css,js,index.html文件
HTML_OUTPUT = doc/api-docs/
INPUT = zdb这个目录下的所有文件
RECURSIVE = YES 递归
FILE_PATTERNS = *.h 只生成头文件的文档
EXTRACT_ALL = YES 提取
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES
GENERATE_HTML = YES 生成html
MACRO_EXPANSION = YES 递归展开宏
简短描述:使用单行的 C++ 注释,或使用 <\brief> 标记。
详细描述:使用 JavaDoc 式的注释 /** … test … */(注意开头的两个星号 [*])或 Qt 式的注释 /*! … text … */。
体内描述:类、结构、联合体和名称空间等 C++ 元素都有自己的标记,比如 <\class>、<\struct>、<\union> 和 <\namespace>。
为了为全局函数、变量和枚举类型生成文档,必须先对对应的文件使用 <\file> 标记。
函数标记(<\fn>)、函数参数标记(<\param>)、变量名标记(<\var>)、用于 #define 的标记(<\def>)以及用来表示与一个代码片段相关的问题的标记(<\warning>)。
doxygen在生成网页的同时会自己生成png,css等, 用户也可以连接自己的png,如database.png
...
cp doc/api-docs/files.html doc/api-docs/index.html
mysql://localhost:3306/test?user=root&password=111111
(gdb) p *url
$2 = {port = 3306, ref = 0x0, path = 0x603aa6 "/test", host = 0x603b70 "localhost", user = 0x0, qptr = 0x0,
query = 0x603b90 "user=root&password=111111", portStr = 0x0, protocol = 0x603a90 "mysql", password = 0x0, toString = 0x0,
params = 0x603be0, paramNames = 0x0, data = 0x603a90 "mysql", buffer = 0x603ac5 "", marker = 0x603aac "user", ctx = 0x603abe "",
limit = 0x603ac5 "", token = 0x603abf "111111"}
(gdb) p url->query
$3 = 0x603b90 "user=root&password=111111"
(gdb) p *url->params
$8 = {name = 0x603ab6 "password", value = 0x603abf "111111", next = 0x603bc0}
(gdb) p *(param_t)0x603bc0
$9 = {name = 0x603aac "user", value = 0x603ab1 "root", next = 0x0}
set environment LD_LIBRARY_PATH :/usr/local/lib:/usr/lib64:../.libs
query = ([\040-\377]\[#])*; query只匹配到#以前
mysql://localhost:3306/test?user=root&password=111111\\[#]
r \ s
match any r which isn’t s. r and s must be regular expressions which can be expressed as character classes.
r / s
r but only if it is followed by s. Note that s is not part of the matched text. This type of regular expression is called “trailing context”. Trailing context can only be the end of a rule and not part of a named definition.
URL_new,创建一个URL_S,re2c就是为了解析这个uri
ConnectionPool_new,创建ConnectionPool_S
ConnectionPool_start---->fillPool(P)---->Connection_new(P, &P->error)---->setDelegate(C, error)
---->C->op = getOp(URL_getProtocol(C->url));
const struct Cop_T mysqlcops = {
"mysql",
MysqlConnection_onstop,
MysqlConnection_new,
MysqlConnection_free,
MysqlConnection_setQueryTimeout,
MysqlConnection_setMaxRows,
MysqlConnection_ping,
C语言实现TRY,CATCH,FINALLY
在Exception.c里,T代表Exception_T
typedef struct T {
const char *name;
} T;只有一个字段name
struct Exception_Frame {
int line;
jmp_buf env;
const char *func;
const char *file;
const T *exception; //Exception_T
Exception_Frame *prev; //上个节点
char message[EXCEPTION_MESSAGE_LENGTH + 1];
};
enum { Exception_entered=0, Exception_thrown, Exception_handled, Exception_finalized };
#define ThreadData_T pthread_key_t
pthread_setspecific(pthread_key_t key, const void *value)/pthread_getspecific可以在一个线程上绑定key和value
extern ThreadData_T Exception_stack; 定义在Exception.c中
void Exception_init(void);
pthread_once(&once_control, init_once);
执行一次init_once,即ThreadData_create(Exception_stack);,即pthread_key_create(&(key), NULL)
void Exception_throw(const T *e, const char *func, const char *file, int line, const char *cause, ...);
得到当前Exception_Frame,p
p->exception = e;//e是全局变量SQLException,给Exception_frame的exception字段赋值
p->func = func;
p->file = file;
p->line = line;
if (cause) {
va_start(ap, cause);
vsnprintf(p->message, EXCEPTION_MESSAGE_LENGTH, cause, ap);
va_end(ap);
}
pop_Exception_stack//Exception_stack指向当前Exception_Frame的上一个Exception_Frame
longjmp(p->env, Exception_thrown);Exception_thrown值是1,Exception_flag != Exception_entered
所以执行CATCH的else if (Exception_frame.exception == &(e)),要捕获的e和Exception_frame的exception相同
Exception_flag = Exception_handled;并执行用户的代码
#define pop_Exception_stack ThreadData_set(Exception_stack, ---->key
((Exception_Frame*)ThreadData_get(Exception_stack))->prev ---->value)
Exception_stack指向当前Exception_Frame的上一个Exception_Frame
#define RETURN switch((pop_Exception_stack,0)) default:return
switch的值是0,RETURN前需要将当前的Exception_Frame从ThreadData移除
TRY {...} CATCH(SQLException) {...} CATCH(XXException) {...} FINALLY {...} END_TRY;
TRY {...} CATCH(SQLException) {...} END_TRY;
TRY {...} FINALLY {...} END_TRY;
TRY {...} ELSE {...} END_TRY; 和TRY,CATCH类似
TRY {...} CATCH(SQLException) {...} FINALLY {...} END_TRY;
/*TRY*/
do {
volatile int Exception_flag;
Exception_Frame Exception_frame;
Exception_frame.message[0] = 0;
Exception_frame.prev = (Exception_Frame*)ThreadData_get(Exception_stack);
ThreadData_set(Exception_stack, &Exception_frame);
Exception_flag = setjmp(Exception_frame.env);
if (Exception_flag == Exception_entered) {
{...try statement
THROW(SQLException, "%s", Connection_getLastError(C));
Exception_throw(&(e), __func__, __FILE__, __LINE__, cause, ##__VA_ARGS__, NULL)
如果有catch发生异常跳到204行执行,没有异常执行202
如果没有catch,只有finally,发生异常跳到212,没有异常执行208
如果没有catch,也没有finally,发生异常跳到219,没有异常216
}//user code
/*CATCH*/
if (Exception_flag == Exception_entered)
pop_Exception_stack;
} else if (Exception_frame.exception == &(e)) {
Exception_flag = Exception_handled;
{...catch statement}//user code
/*FINALLY*/
if (Exception_flag == Exception_entered)
pop_Exception_stack;
}
{
if (Exception_flag == Exception_entered)
Exception_flag = Exception_finalized;
{...finally statement}//user code
/*END_TRY*/
if (Exception_flag == Exception_entered)
pop_Exception_stack;
}
if (Exception_flag == Exception_thrown)
/*RETHROW*/
Exception_throw(Exception_frame.exception, \
Exception_frame.func, Exception_frame.file, Exception_frame.line, NULL)
} while (0)