forked from huawei/openGauss-server
Compare commits
247 Commits
undorecycl
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
064464c40d | |
|
|
68732254fc | |
|
|
ca568d528b | |
|
|
92e8042b7b | |
|
|
47d827797b | |
|
|
6ce1316fcb | |
|
|
d3b89834a6 | |
|
|
27d13a7fda | |
|
|
54c37c438d | |
|
|
1667b7097f | |
|
|
bb95d131f3 | |
|
|
2e3138ee3b | |
|
|
3a01cfd610 | |
|
|
d6b4dae70f | |
|
|
360e802abf | |
|
|
7d0c403139 | |
|
|
c4379e1f7e | |
|
|
c4296f02bb | |
|
|
c0906c50ef | |
|
|
3dc6446442 | |
|
|
b24a6f0745 | |
|
|
a45c2878b2 | |
|
|
208c7133b2 | |
|
|
3b6930c9fd | |
|
|
4c780da35d | |
|
|
a64a9be96d | |
|
|
d2461962c1 | |
|
|
96fc5d9222 | |
|
|
2d4e46f02b | |
|
|
0479fb1064 | |
|
|
c11087954e | |
|
|
6222d3d018 | |
|
|
a7c40a3799 | |
|
|
101001c72f | |
|
|
a4969dddbc | |
|
|
e338a73024 | |
|
|
330153cd88 | |
|
|
a75168ec6f | |
|
|
6e3d6f09d4 | |
|
|
70b4e5154f | |
|
|
0c7d7a750e | |
|
|
22837de14e | |
|
|
1f98d1d9a0 | |
|
|
1fd2a7a10f | |
|
|
cf99a0753b | |
|
|
3b20740c1c | |
|
|
6962802cc9 | |
|
|
90dc7ce262 | |
|
|
1a4c7c588a | |
|
|
092c13012c | |
|
|
0c63707f5e | |
|
|
40e0f4b53f | |
|
|
8cf2f05840 | |
|
|
a35d773da0 | |
|
|
704877f632 | |
|
|
c59197ebe9 | |
|
|
8de0f268bd | |
|
|
70a1854ad9 | |
|
|
defd901624 | |
|
|
7b49a450dc | |
|
|
01163f2e40 | |
|
|
5eb65aa4ca | |
|
|
95b7221f15 | |
|
|
200c9b14a7 | |
|
|
95cd0ad4c7 | |
|
|
8790761995 | |
|
|
ae7a0bc797 | |
|
|
a6ce672068 | |
|
|
9e915d9fbf | |
|
|
76e3f4dad6 | |
|
|
8e9089b6fe | |
|
|
4b7af41aff | |
|
|
313e3c4e00 | |
|
|
43c3001415 | |
|
|
d9cde8c89b | |
|
|
91a7306a88 | |
|
|
eb4c1bd953 | |
|
|
991925bfe1 | |
|
|
6021c26abe | |
|
|
817264937d | |
|
|
62e2170f65 | |
|
|
19adb21866 | |
|
|
3446cb0aba | |
|
|
3c0a229006 | |
|
|
5f8ca172c7 | |
|
|
22b3c75a36 | |
|
|
8f463f2f77 | |
|
|
95fafe1ce0 | |
|
|
59ad28eed7 | |
|
|
4c345b1d31 | |
|
|
62e6f3a028 | |
|
|
c7eae459f2 | |
|
|
f9b4d9a702 | |
|
|
11e6760776 | |
|
|
272ebd125f | |
|
|
3a2a690ee8 | |
|
|
d0a5914e3f | |
|
|
dc65ea0040 | |
|
|
4728c88126 | |
|
|
cd677d1243 | |
|
|
3fde3abb91 | |
|
|
7679dfe93b | |
|
|
78d7d8e54f | |
|
|
8cd2925f93 | |
|
|
a4e1b350cb | |
|
|
32cdbbabff | |
|
|
cdc8d9748f | |
|
|
9017a1a64e | |
|
|
751e1c4267 | |
|
|
ac1d40fca2 | |
|
|
a7af1741d2 | |
|
|
8d84b37543 | |
|
|
bab8f82a0e | |
|
|
3c1a1c2bef | |
|
|
8902cfd59a | |
|
|
e7dd9fa2a1 | |
|
|
2812c3315c | |
|
|
5c988a09f4 | |
|
|
bcfff28219 | |
|
|
72a82e2182 | |
|
|
c7e4a74544 | |
|
|
cf86dd46f5 | |
|
|
edf79014bf | |
|
|
fb3e4435e0 | |
|
|
88840f46d2 | |
|
|
54de7afd7d | |
|
|
907997d5a6 | |
|
|
55ae2df08c | |
|
|
340b61c47f | |
|
|
4761d514e6 | |
|
|
0ac4f9bd4b | |
|
|
1a3fad4d43 | |
|
|
730e66cdf0 | |
|
|
00dd058431 | |
|
|
36efc4cbb7 | |
|
|
38ca00c31c | |
|
|
2165635b9a | |
|
|
e06c03a579 | |
|
|
4cd25670b5 | |
|
|
f70898ecf5 | |
|
|
95466298fa | |
|
|
119d5d39da | |
|
|
537cba6247 | |
|
|
14c4068daa | |
|
|
cf8e1541b1 | |
|
|
58d5c900c9 | |
|
|
25332da4aa | |
|
|
fd0098411a | |
|
|
b4f33b07cf | |
|
|
caccfc026d | |
|
|
30621924cf | |
|
|
abb0cee0fc | |
|
|
0c2af1d742 | |
|
|
09e299ac8a | |
|
|
7dc9903be8 | |
|
|
bc0dc304c8 | |
|
|
5f334a5656 | |
|
|
4ec1513e05 | |
|
|
fb0026b93b | |
|
|
ce56fb62b6 | |
|
|
2b198387ab | |
|
|
72f4d68de6 | |
|
|
62e3bed09b | |
|
|
7d4d95a5ad | |
|
|
240f61c595 | |
|
|
a0d1a547f8 | |
|
|
df804a8a91 | |
|
|
91917dcfaf | |
|
|
e2163187ca | |
|
|
1d7eadd778 | |
|
|
b335ef9af7 | |
|
|
572d99d03c | |
|
|
0b0959fc69 | |
|
|
238ee19a59 | |
|
|
d199d90a71 | |
|
|
2a77a3cebc | |
|
|
214d01ddb6 | |
|
|
4f024161f0 | |
|
|
82d5ac65b0 | |
|
|
7edda5e2a4 | |
|
|
e10c482649 | |
|
|
0a29277070 | |
|
|
96dad83a1d | |
|
|
d433ee097a | |
|
|
a590e0b47f | |
|
|
7f8b900e69 | |
|
|
f14255f040 | |
|
|
5af581f12a | |
|
|
26793e3bf2 | |
|
|
dbcf479205 | |
|
|
ae11cad2c3 | |
|
|
57bc5c4a37 | |
|
|
fb449157d0 | |
|
|
6c5898646e | |
|
|
c1335bebc9 | |
|
|
b2c6e04eab | |
|
|
16d32d3978 | |
|
|
3e14e85fdf | |
|
|
438bba32ff | |
|
|
d82eba4790 | |
|
|
4b7080c8ef | |
|
|
5e1d9b79f6 | |
|
|
51c355c7b6 | |
|
|
4c0a495a18 | |
|
|
cbb8fd609b | |
|
|
475170ca0c | |
|
|
7f9a1f5428 | |
|
|
c04e377cdc | |
|
|
6380ca0f4d | |
|
|
4898f04a3c | |
|
|
11a1a5c9ad | |
|
|
a30ae9d5ad | |
|
|
0b70c7ab70 | |
|
|
f719422916 | |
|
|
88dcc7f99e | |
|
|
dbd9958443 | |
|
|
38b5a0ac95 | |
|
|
a548f5c3c6 | |
|
|
eb4e54d4eb | |
|
|
3f7a909887 | |
|
|
d8b89ceea5 | |
|
|
2250adfd4b | |
|
|
fd34b5da2a | |
|
|
7f97d633f1 | |
|
|
6ba4c95f5f | |
|
|
5755feee5d | |
|
|
cd5d44d66c | |
|
|
2d657cddbe | |
|
|
ccd674c159 | |
|
|
8292238381 | |
|
|
5054ddd002 | |
|
|
48a5033c18 | |
|
|
811a9afcd9 | |
|
|
bb0aa02eb0 | |
|
|
02c14696bf | |
|
|
877f0b69e3 | |
|
|
120ddcc6d8 | |
|
|
2cc80a5727 | |
|
|
6d8bec171c | |
|
|
9f7da01725 | |
|
|
ea938c947e | |
|
|
498d7ac08d | |
|
|
40b717d9dd | |
|
|
94aeb766e5 | |
|
|
8577a61c7b | |
|
|
59db2a14cc | |
|
|
e7795cd01c |
|
|
@ -142,72 +142,72 @@ int SYS_NAME(sysconf)(int name)
|
|||
{
|
||||
switch (name) {
|
||||
case _SC_PAGESIZE:
|
||||
return getpagesize();
|
||||
return getpagesize(); // 返回系统页面大小
|
||||
case _SC_OPEN_MAX: {
|
||||
struct kernel_rlimit limit = {0};
|
||||
if (sys_getrlimit(RLIMIT_NOFILE, &limit) >= 0) {
|
||||
return limit.rlim_cur;
|
||||
struct kernel_rlimit limit = {0}; // 创建一个kernel_rlimit结构体,并初始化为0
|
||||
if (sys_getrlimit(RLIMIT_NOFILE, &limit) >= 0) { // 调用sys_getrlimit函数,将RLIMIT_NOFILE资源限制信息存储在limit中
|
||||
return limit.rlim_cur; // 返回当前进程的最大打开文件数
|
||||
} else {
|
||||
/* Default maximum open files for per process */
|
||||
return 8192;
|
||||
return 8192; // 返回默认的最大打开文件数为8192
|
||||
}
|
||||
}
|
||||
default:
|
||||
errno = ENOSYS;
|
||||
errno = ENOSYS; // 如果name不匹配_SC_PAGESIZE和_SC_OPEN_MAX,则设置errno为ENOSYS表示函数未实现
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int SYS_NAME(sigemptyset)(struct kernel_sigset_t* set)
|
||||
{
|
||||
errno_t rc = memset_s(set->sig, sizeof(set->sig), 0, sizeof(set->sig));
|
||||
errno_t rc = memset_s(set->sig, sizeof(set->sig), 0, sizeof(set->sig)); // 使用memset_s函数将set->sig的值设置为0
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SYS_NAME(sigfillset)(struct kernel_sigset_t* set)
|
||||
{
|
||||
errno_t rc = memset_s(set->sig, sizeof(set->sig), 0xFF, sizeof(set->sig));
|
||||
errno_t rc = memset_s(set->sig, sizeof(set->sig), 0xFF, sizeof(set->sig)); // 使用memset_s函数将set->sig的值设置为0xFF
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SYS_NAME(sigaddset)(struct kernel_sigset_t* set, int __signum)
|
||||
{
|
||||
int signo = (int)(8 * sizeof(set->sig));
|
||||
int signo = (int)(8 * sizeof(set->sig)); // 计算消息信号集的位数
|
||||
|
||||
if (__signum < 1 || __signum > signo) {
|
||||
errno = EINVAL;
|
||||
errno = EINVAL; // 如果__signum小于1或大于signo,设置errno为EINVAL表示无效参数
|
||||
return -1;
|
||||
} else {
|
||||
set->sig[(__signum - 1) / (8 * sizeof(set->sig[0]))] |= 1UL << ((__signum - 1) % (8 * sizeof(set->sig[0])));
|
||||
set->sig[(__signum - 1) / (8 * sizeof(set->sig[0]))] |= 1UL << ((__signum - 1) % (8 * sizeof(set->sig[0]))); // 将__signum对应的位设置为1
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int SYS_NAME(sigdelset)(struct kernel_sigset_t* set, int __signum)
|
||||
{
|
||||
int signo = (int)(8 * sizeof(set->sig));
|
||||
int signo = (int)(8 * sizeof(set->sig)); // 计算消息信号集的位数
|
||||
|
||||
if (__signum < 1 || __signum > signo) {
|
||||
errno = EINVAL;
|
||||
errno = EINVAL; // 如果__signum小于1或大于signo,设置errno为EINVAL表示无效参数
|
||||
return -1;
|
||||
} else {
|
||||
set->sig[(__signum - 1) / (8 * sizeof(set->sig[0]))] &= ~(1UL << ((__signum - 1) % (8 * sizeof(set->sig[0]))));
|
||||
set->sig[(__signum - 1) / (8 * sizeof(set->sig[0]))] &= ~(1UL << ((__signum - 1) % (8 * sizeof(set->sig[0])))); // 将__signum对应的位设置为0
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int SYS_NAME(sigismember)(struct kernel_sigset_t* set, int __signum)
|
||||
{
|
||||
int signo = (int)(8 * sizeof(set->sig));
|
||||
int signo = (int)(8 * sizeof(set->sig)); // 计算消息信号集的位数
|
||||
|
||||
if (__signum < 1 || __signum > signo) {
|
||||
errno = EINVAL;
|
||||
errno = EINVAL; // 如果__signum小于1或大于signo,设置errno为EINVAL表示无效参数
|
||||
return -1;
|
||||
} else {
|
||||
return !!(set->sig[(__signum - 1) / (8 * sizeof(set->sig[0]))] &
|
||||
(1UL << ((__signum - 1) % (8 * sizeof(set->sig[0])))));
|
||||
(1UL << ((__signum - 1) % (8 * sizeof(set->sig[0]))))); // 检查__signum对应的位是否为1,返回结果
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +215,7 @@ long SYS_NAME(sigprocmask)(int how, struct kernel_sigset_t* set, struct kernel_s
|
|||
{
|
||||
long ret = 0;
|
||||
|
||||
ret = SYS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG + 7) / 8);
|
||||
ret = SYS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG + 7) / 8); // 调用SYS_NAME(rt_sigprocmask)函数设置信号屏蔽字
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -428,7 +428,7 @@ __syscall5(
|
|||
|
||||
long SYS_NAME(waitpid)(pid_t pid, int* status, int options)
|
||||
{
|
||||
return SYS_NAME(wait4)(pid, status, options, 0);
|
||||
return SYS_NAME(wait4)(pid, status, options, 0); // 调用SYS_NAME(wait4)函数等待子进程结束
|
||||
}
|
||||
|
||||
long SYS_NAME(signal)(int __signum, void (*handler)(int))
|
||||
|
|
@ -436,22 +436,23 @@ long SYS_NAME(signal)(int __signum, void (*handler)(int))
|
|||
struct kernel_sigaction _sa;
|
||||
struct kernel_sigaction old;
|
||||
|
||||
errno_t rc = memset_s(&_sa, sizeof(_sa), 0, sizeof(_sa));
|
||||
errno_t rc = memset_s(&_sa, sizeof(_sa), 0, sizeof(_sa)); // 使用memset_s函数将_sa的值设置为0
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
sys_sigfillset(&_sa.sa_mask);
|
||||
_sa.sa_flags |= SA_RESTORER | SA_RESTART;
|
||||
_sa.handle.sa_handler_ = handler;
|
||||
sys_sigfillset(&_sa.sa_mask); // 将_sa.sa_mask的所有位都设置为1
|
||||
_sa.sa_flags |= SA_RESTORER | SA_RESTART; // 设置_sa.sa_flags的标志位
|
||||
_sa.handle.sa_handler_ = handler; // 设置_sa.handle.sa_handler_为传入的handler函数
|
||||
|
||||
return SYS_NAME(rt_sigaction)(__signum, &_sa, &old, (KERNEL_NSIG + 7) / 8);
|
||||
return SYS_NAME(rt_sigaction)(__signum, &_sa, &old, (KERNEL_NSIG + 7) / 8); // 调用SYS_NAME(rt_sigaction)函数设置信号处理动作
|
||||
}
|
||||
|
||||
long SYS_NAME(_clone)(
|
||||
int (*fn)(void*), void* child_stack, int flags, void* arg, int* parent_tidptr, void* newtls, int* child_tidptr)
|
||||
/*
|
||||
long SYS_NAME(_clone)(int (fn)(void), void* child_stack, int flags, void* arg, int* parent_tidptr, void* newtls, int* child_tidptr)函数用于创建一个新的进程,并在新进程中执行指定的函数。
|
||||
*/
|
||||
long SYS_NAME(_clone)(int (*fn)(void*), void* child_stack, int flags, void* arg, int* parent_tidptr, void* newtls, int* child_tidptr)
|
||||
{
|
||||
register long ___res __asm__("r5");
|
||||
|
||||
{
|
||||
if (fn == NULL || child_stack == NULL) {
|
||||
if (fn == NULL || child_stack == NULL) { // 如果传入的函数指针为NULL,或者子进程栈指针为NULL,则返回EINVAL错误码
|
||||
___res = -EINVAL;
|
||||
goto _clone_exit;
|
||||
}
|
||||
|
|
@ -459,24 +460,25 @@ long SYS_NAME(_clone)(
|
|||
/* stash first 4 arguments on stack first because we can only load
|
||||
* them after all function calls.
|
||||
*/
|
||||
int tmp_flags = flags;
|
||||
int* tmp_stack = (int*)child_stack;
|
||||
void* tmp_ptid = parent_tidptr;
|
||||
void* tmp_tls = newtls;
|
||||
int tmp_flags = flags; // 复制flags的值 `tmp_flags`变量用于保存`flags`的值。
|
||||
|
||||
register int* ___ctid __asm__("r4") = child_tidptr;
|
||||
int* tmp_stack = (int*)child_stack; // 将子进程栈指针转换为int类型指针并保存为tmp_stack
|
||||
void* tmp_ptid = parent_tidptr; // 保存parent_tidptr的值
|
||||
void* tmp_tls = newtls; // 保存newtls的值
|
||||
|
||||
register int* ___ctid __asm__("r4") = child_tidptr; // 将child_tidptr保存到___ctid寄存器变量中
|
||||
|
||||
/* Push "arg" and "fn" onto the stack that will be
|
||||
* used by the child.
|
||||
*/
|
||||
*(--tmp_stack) = (int)arg;
|
||||
*(--tmp_stack) = (int)fn;
|
||||
*(--tmp_stack) = (int)arg; // 将arg的值存入子进程栈中
|
||||
*(--tmp_stack) = (int)fn; // 将fn的值存入子进程栈中
|
||||
|
||||
/* We must load r0..r3 last after all possible function calls. */
|
||||
register int ___flags __asm__("r0") = tmp_flags;
|
||||
register void* ___stack __asm__("r1") = tmp_stack;
|
||||
register void* ___ptid __asm__("r2") = tmp_ptid;
|
||||
register void* ___tls __asm__("r3") = tmp_tls;
|
||||
register int ___flags __asm__("r0") = tmp_flags; // 将tmp_flags保存到___flags寄存器变量中
|
||||
register void* ___stack __asm__("r1") = tmp_stack; // 将tmp_stack保存到___stack寄存器变量中
|
||||
register void* ___ptid __asm__("r2") = tmp_ptid; // 将tmp_ptid保存到___ptid寄存器变量中
|
||||
register void* ___tls __asm__("r3") = tmp_tls; // 将tmp_tls保存到___tls寄存器变量中
|
||||
|
||||
/* example: %r0 = syscall(%r0 = flags,
|
||||
* %r1 = child_stack,
|
||||
|
|
@ -484,28 +486,29 @@ long SYS_NAME(_clone)(
|
|||
* %r3 = newtls,
|
||||
* %r4 = child_tidptr)
|
||||
*/
|
||||
__SYS_REG(clone)
|
||||
__SYS_REG(clone) // 定义宏__SYS_REG(clone)
|
||||
|
||||
__asm__ __volatile__(
|
||||
"push {r7}\n"
|
||||
"mov r7,%1\n" __syscall(clone) "\n"
|
||||
"push {r7}\n" // 将r7寄存器的值保存到栈中
|
||||
"mov r7,%1\n" __syscall(clone) "\n" // 调用系统调用clone
|
||||
|
||||
"movs %0,r0\n"
|
||||
"bne 1f\n"
|
||||
"movs %0,r0\n" // 将r0的值保存到___res中,并设置条件码
|
||||
"bne 1f\n" // 如果条件码不等于0,则跳转到标号1处
|
||||
|
||||
"ldr r0,[sp, #4]\n"
|
||||
"mov lr,pc\n"
|
||||
"ldr pc,[sp]\n"
|
||||
"ldr r0,[sp, #4]\n" // 将sp加上4,得到地址,然后将该地址处的内容保存到r0寄存器中
|
||||
"mov lr,pc\n" // 将pc的值保存到lr寄存器中
|
||||
"ldr pc,[sp]\n" // 将sp的值保存到pc寄存器中
|
||||
|
||||
"mov r7,%2\n" __syscall(exit) "\n"
|
||||
"mov r7,%2\n" __syscall(exit) "\n" // 调用系统调用exit
|
||||
|
||||
"1: pop {r7}\n"
|
||||
: "=r"(___res)
|
||||
: "r"(__sysreg), "i"(__NR_exit), "r"(___stack), "r"(___flags), "r"(___ptid), "r"(___tls), "r"(___ctid)
|
||||
: "cc", "lr", "memory");
|
||||
"1: pop {r7}\n" // 将栈中的值保存到r7寄存器中
|
||||
: "=r"(___res) // 输出结果保存到___res寄存器变量中
|
||||
: "r"(__sysreg), "i"(__NR_exit), "r"(___stack), "r"(___flags), "r"(___ptid), "r"(___tls), "r"(___ctid) // 输入参数
|
||||
: "cc", "lr", "memory"); // 修改了条件码,lr寄存器内容以及内存
|
||||
}
|
||||
|
||||
_clone_exit:
|
||||
___syscall_return(int, ___res);
|
||||
___syscall_return(int, ___res); // 调用___syscall_return函数返回结果
|
||||
}
|
||||
|
||||
#elif (defined(__aarch64__))
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -72,7 +72,7 @@ select_package_command
|
|||
export PLAT_FORM_STR=$(sh "${ROOT_DIR}/src/get_PlatForm_str.sh")
|
||||
if [ "${PLAT_FORM_STR}"x == "Failed"x -o "${PLAT_FORM_STR}"x == ""x ]
|
||||
then
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) platform."
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64), Asianux platform."
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
|
|
@ -96,16 +96,21 @@ elif [[ "$PLAT_FORM_STR" =~ "kylin" ]]; then
|
|||
if [ "$PLATFORM_ARCH"X == "aarch64"X ];then
|
||||
GAUSSDB_EXTRA_FLAGS=" -D__USE_NUMA"
|
||||
fi
|
||||
elif [[ "$PLAT_FORM_STR" =~ "asianux" ]]; then
|
||||
dist_version="Asianux"
|
||||
if [ "$PLATFORM_ARCH"X == "aarch64"X ];then
|
||||
GAUSSDB_EXTRA_FLAGS=" -D__USE_NUMA"
|
||||
fi
|
||||
else
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64) platform."
|
||||
echo "We only support openEuler(aarch64), EulerOS(aarch64), CentOS, Kylin(aarch64), Asianux platform."
|
||||
echo "Kernel is $kernel"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
##add platform architecture information
|
||||
if [ "$PLATFORM_ARCH"X == "aarch64"X ] ; then
|
||||
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] ; then
|
||||
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64) platform."
|
||||
if [ "$dist_version" != "openEuler" ] && [ "$dist_version" != "EulerOS" ] && [ "$dist_version" != "Kylin" ] && [ "$dist_version" != "Asianux" ]; then
|
||||
echo "We only support NUMA on openEuler(aarch64), EulerOS(aarch64), Kylin(aarch64), Asianux platform."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ Complete list of usable sgml source files in this directory.
|
|||
<!ENTITY alterOperator SYSTEM "alter_operator.sgml">
|
||||
<!ENTITY alterOperatorClass SYSTEM "alter_opclass.sgml">
|
||||
<!ENTITY alterOperatorFamily SYSTEM "alter_opfamily.sgml">
|
||||
<!ENTITY alterProcedure SYSTEM "alter_procedure.sgml">
|
||||
<!ENTITY alterRole SYSTEM "alter_role.sgml">
|
||||
<!ENTITY alterSchema SYSTEM "alter_schema.sgml">
|
||||
<!ENTITY alterServer SYSTEM "alter_server.sgml">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<refentry id="sql-alterprocedure">
|
||||
<indexterm zone="sql-alterprocedure">
|
||||
<primary>ALTER PROCEDURE</primary>
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>ALTER PROCEDURE</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
<refmiscinfo>SQL - Language Statements</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>ALTER PROCEDURE</refname>
|
||||
<refpurpose>change the definition of a procedure</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
||||
<replaceable class="parameter">action</replaceable> [ ... ] [ RESTRICT ]
|
||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
||||
RENAME TO <replaceable>new_name</replaceable>
|
||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
||||
OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
|
||||
ALTER PROCEDURE <replaceable>name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) ]
|
||||
SET SCHEMA <replaceable>new_schema</replaceable>
|
||||
|
||||
<phrase>where <replaceable class="parameter">action</replaceable> is one of:</phrase>
|
||||
|
||||
[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
||||
SET <replaceable class="parameter">configuration_parameter</replaceable> { TO | = } { <replaceable class="parameter">value</replaceable> | DEFAULT }
|
||||
SET <replaceable class="parameter">configuration_parameter</replaceable> FROM CURRENT
|
||||
RESET <replaceable class="parameter">configuration_parameter</replaceable>
|
||||
RESET ALL
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
</refentry>
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
DROP TABLE [ IF EXISTS ]
|
||||
{[schema.]table_name} [, ...] [ CASCADE | RESTRICT ] [ PURGE ]};
|
||||
{[schema.]table_name} [, ...] [ CASCADE | RESTRICT ] [ PURGE ];
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
</refentry>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,22 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Huawei Technologies Co.,Ltd.
|
||||
* 版权所有 (c) 2019华为技术有限公司
|
||||
*
|
||||
* openGauss is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* openGauss在Mulan PSL v2下获得许可。
|
||||
* 您可以根据Mulan PSL v2的条款和条件使用此软件。
|
||||
* 您可以在以下网址获得Mulan PSL v2的副本:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
* 此软件基于"按原样"提供,没有任何形式的明示或暗示保证,
|
||||
* 包括但不限于保证适销性、特定用途的适用性和非侵权性。
|
||||
* 有关更多详细信息,请参阅Mulan PSL v2。
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* cgexcp.cpp
|
||||
* Cgroup exceptional data process
|
||||
* Cgroup异常数据处理
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* 标识
|
||||
* src/bin/gs_cgroup/cgexcp.cpp
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
|
|
@ -47,11 +46,11 @@
|
|||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
* function name: cgexcp_skewpercent_is_invalid
|
||||
* description : check skew percent whether is invalid
|
||||
* return value : 0: valid, 1: invalid
|
||||
*/
|
||||
/*
|
||||
* 函数名:cgexcp_skewpercent_is_invalid
|
||||
* 功能:检查偏移百分比是否无效
|
||||
* 返回值:0表示有效,1表示无效
|
||||
*/
|
||||
static int cgexcp_skewpercent_is_invalid(const except_data_t* except)
|
||||
{
|
||||
if ((except->skewpercent > 0 && except->qualitime > 0) || (except->skewpercent <= 0 && except->qualitime <= 0))
|
||||
|
|
@ -59,38 +58,36 @@ static int cgexcp_skewpercent_is_invalid(const except_data_t* except)
|
|||
|
||||
return 1;
|
||||
}
|
||||
/**
|
||||
* 函数名称:cgexcp_exception_save
|
||||
* 描述:将异常数据保存到配置文件中
|
||||
* 返回值:
|
||||
* -1:异常
|
||||
* 0:正常
|
||||
*/
|
||||
static int cgexcp_exception_save(gscgroup_grp_t* grp) {
|
||||
char* p = NULL; // 保存解析字符串的指针
|
||||
char* q = NULL; // 保存','字符的指针
|
||||
char eflag; // 异常标志
|
||||
unsigned long val; // 异常值
|
||||
int err = 0; // 错误码
|
||||
|
||||
/*
|
||||
* function name: cgexcp_exception_save
|
||||
* description : save the exceptional data into the config file
|
||||
* return value :
|
||||
* -1: abnormal
|
||||
* 0: normal
|
||||
*
|
||||
*/
|
||||
static int cgexcp_exception_save(gscgroup_grp_t* grp)
|
||||
{
|
||||
char *p = NULL;
|
||||
char *q = NULL;
|
||||
char eflag;
|
||||
unsigned long val;
|
||||
int err = 0;
|
||||
p = cgutil_opt.edata;
|
||||
eflag = cgutil_opt.eflag;
|
||||
p = cgutil_opt.edata; // 获取解析字符串
|
||||
eflag = cgutil_opt.eflag; // 获取异常标志
|
||||
|
||||
do {
|
||||
while (*p == ' ') {
|
||||
while (*p == ' ') { // 跳过空格字符
|
||||
p++;
|
||||
}
|
||||
|
||||
q = strchr(p, ',');
|
||||
q = strchr(p, ','); // 查找','字符
|
||||
if (q != NULL) {
|
||||
*q++ = '\0';
|
||||
*q++ = '\0'; // 将','字符置为字符串结束符
|
||||
}
|
||||
if (strncasecmp("BlockTime=", p, sizeof("BlockTime=") - 1) == 0) {
|
||||
EXCP_PARSE_KEY(p, val);
|
||||
if (strncasecmp("BlockTime=", p, sizeof("BlockTime=") - 1) == 0) { // 判断是否为"BlockTime="字符串
|
||||
EXCP_PARSE_KEY(p, val); // 解析异常值
|
||||
|
||||
if (val > UINT_MAX) {
|
||||
if (val > UINT_MAX) { // 判断异常值是否超出范围
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'BlockTime\', "
|
||||
"value limit exceeded, it should be 0~%u!\n",
|
||||
|
|
@ -99,7 +96,7 @@ static int cgexcp_exception_save(gscgroup_grp_t* grp)
|
|||
break;
|
||||
}
|
||||
|
||||
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) {
|
||||
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) { // 判断异常标志位是否为"penalty"
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'BlockTime\' "
|
||||
"for \"penalty\" is invalid!\n");
|
||||
|
|
@ -107,137 +104,84 @@ static int cgexcp_exception_save(gscgroup_grp_t* grp)
|
|||
break;
|
||||
}
|
||||
|
||||
grp->except[eflag - 1].blocktime = (unsigned int)val;
|
||||
} else if (strncasecmp("ElapsedTime=", p, sizeof("ElapsedTime=") - 1) == 0) {
|
||||
EXCP_PARSE_KEY(p, val);
|
||||
|
||||
if (val > UINT_MAX) {
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'ElapsedTime\', "
|
||||
"value limit exceeded, it should be 0~%u!\n",
|
||||
UINT_MAX);
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) {
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'ElapsedTime\', "
|
||||
"for \"penalty\" is invalid!\n");
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
grp->except[eflag - 1].elapsedtime = (unsigned int)val;
|
||||
} else if (strncasecmp("SpillSize=", p, sizeof("SpillSize=") - 1) == 0) {
|
||||
EXCP_PARSE_KEY(p, val);
|
||||
|
||||
if (val > UINT_MAX) {
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'SpillSize\', "
|
||||
"value limit exceeded, it should be 0~%u!\n",
|
||||
UINT_MAX);
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) {
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'SpillSize\', "
|
||||
"for \"penalty\" is invalid!\n");
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
grp->except[eflag - 1].spoolsize = (int64)val;
|
||||
} else if (strncasecmp("BroadcastSize=", p, sizeof("BroadcastSize=") - 1) == 0) {
|
||||
EXCP_PARSE_KEY(p, val);
|
||||
|
||||
if (val > UINT_MAX) {
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'BroadcastSize\', "
|
||||
"value limit exceeded, it should be 0~%u!\n",
|
||||
UINT_MAX);
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) {
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'BroadcastSize\', "
|
||||
"for \"penalty\" is invalid!\n");
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
grp->except[eflag - 1].broadcastsize = (int64)val;
|
||||
} else if (strncasecmp("AllCpuTime=", p, sizeof("AllCpuTime=") - 1) == 0) {
|
||||
EXCP_PARSE_KEY(p, val);
|
||||
|
||||
if (val > UINT_MAX) {
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'AllCpuTime\', "
|
||||
"value limit exceeded, it should be 0~%u!\n",
|
||||
UINT_MAX);
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
grp->except[eflag - 1].allcputime = (unsigned int)val;
|
||||
} else if (strncasecmp("QualificationTime=", p, sizeof("QualificationTime=") - 1) == 0) {
|
||||
EXCP_PARSE_KEY(p, val);
|
||||
|
||||
if (val > UINT_MAX) {
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'QualificationTime\', "
|
||||
"value limit exceeded, it should be 0~%u!\n",
|
||||
UINT_MAX);
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
grp->except[eflag - 1].qualitime = (unsigned int)val;
|
||||
} else if (strncasecmp("CPUSkewPercent=", p, sizeof("CPUSkewPercent=") - 1) == 0) {
|
||||
EXCP_PARSE_KEY(p, val);
|
||||
|
||||
if (val > 100) {
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'CPUSkewPercent\', "
|
||||
"value '%u' is invalid, it must be 0~100!\n",
|
||||
(unsigned int)val);
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
grp->except[eflag - 1].skewpercent = (unsigned int)val;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: exception key string '%s' doesn't be supported!\n", p);
|
||||
err = -1;
|
||||
break;
|
||||
grp->except[eflag - 1].blocktime = (unsigned int)val; // 将异常值保存到对应的异常数据结构中
|
||||
}
|
||||
p = q;
|
||||
} while ((q != NULL) && *q);
|
||||
else if (strncasecmp("ElapsedTime=", p, sizeof("ElapsedTime=") - 1) == 0) { // 判断是否为"ElapsedTime="字符串
|
||||
EXCP_PARSE_KEY(p, val); // 解析异常值
|
||||
|
||||
if (cgexcp_skewpercent_is_invalid(&grp->except[eflag - 1])) {
|
||||
grp->except[eflag - 1].skewpercent = 0;
|
||||
grp->except[eflag - 1].qualitime = 0;
|
||||
fprintf(stderr,
|
||||
"ERROR: exception key string '%s' is invalid, "
|
||||
"\'CPUSkewPercent\' must be specified together with \'QualificationTime\'!\n",
|
||||
cgutil_opt.edata);
|
||||
if (val > UINT_MAX) { // 判断异常值是否超出范围
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'ElapsedTime\', "
|
||||
"value limit exceeded, it should be 0~%u!\n",
|
||||
UINT_MAX);
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) { // 判断异常标志位是否为"penalty"
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'ElapsedTime\', "
|
||||
"for \"penalty\" is invalid!\n");
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
grp->except[eflag - 1].elapsedtime = (unsigned int)val; // 将异常值保存到对应的异常数据结构中
|
||||
}
|
||||
else if (strncasecmp("SpillSize=", p, sizeof("SpillSize=") - 1) == 0) { // 判断是否为"SpillSize="字符串
|
||||
EXCP_PARSE_KEY(p, val); // 解析异常值
|
||||
|
||||
if (val > UINT_MAX) { // 判断异常值是否超出范围
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'SpillSize\', "
|
||||
"value limit exceeded, it should be 0~%u!\n",
|
||||
UINT_MAX);
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) { // 判断异常标志位是否为"penalty"
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'SpillSize\', "
|
||||
"for \"penalty\" is invalid!\n");
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
grp->except[eflag - 1].spoolsize = (int64)val; // 将异常值保存到对应的异常数据结构中
|
||||
}
|
||||
else if (strncasecmp("BroadcastSize=", p, sizeof("BroadcastSize=") - 1) == 0) { // 判断是否为"BroadcastSize="字符串
|
||||
EXCP_PARSE_KEY(p, val); // 解析异常值
|
||||
|
||||
if (val > UINT_MAX) { // 判断异常值是否超出范围
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'BroadcastSize\', "
|
||||
"value limit exceeded, it should be 0~%u!\n",
|
||||
UINT_MAX);
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_EXCEPT_FLAG(eflag, EXCEPT_PENALTY)) { // 判断异常标志位是否为"penalty"
|
||||
fprintf(stderr,
|
||||
"ERROR: threshold \'BroadcastSize\', "
|
||||
"for \"penalty\" is invalid!\n");
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
grp->except[eflag - 1].broadcastsize = (int64)val; // 将异常值保存到对应的异常数据结构中
|
||||
}
|
||||
} while (q != NULL);
|
||||
|
||||
return err; // 返回错误码
|
||||
}
|
||||
|
||||
/*
|
||||
* function name: cgexcp_class_exception
|
||||
* description : deal with the class exception
|
||||
* return value :
|
||||
* -1: abnormal
|
||||
* 0: normal
|
||||
* 函数名称:cgexcp_class_exception
|
||||
* 功能描述:处理类异常
|
||||
* 返回值:
|
||||
* -1:异常
|
||||
* 0:正常
|
||||
*
|
||||
*/
|
||||
int cgexcp_class_exception(void)
|
||||
|
|
@ -249,7 +193,7 @@ int cgexcp_class_exception(void)
|
|||
char* tmpstr = NULL;
|
||||
size_t wdname_len;
|
||||
|
||||
/* check if the class exists */
|
||||
/* 检查类是否存在 */
|
||||
for (i = CLASSCG_START_ID; i <= CLASSCG_END_ID; i++) {
|
||||
if (cgutil_vaddr[i]->used == 0)
|
||||
continue;
|
||||
|
|
@ -260,7 +204,7 @@ int cgexcp_class_exception(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* back up the config file */
|
||||
/* 备份配置文件 */
|
||||
if (-1 == cgconf_backup_config_file()) {
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -274,7 +218,7 @@ int cgexcp_class_exception(void)
|
|||
if (cgutil_vaddr[i]->used == 0 || cgutil_vaddr[i]->ginfo.wd.cgid != cls)
|
||||
continue;
|
||||
|
||||
/* workload name with level or no level */
|
||||
/* 判断工作负载名称是否有级别或者没有级别 */
|
||||
if (tmpstr != NULL)
|
||||
cmp = strcmp(cgutil_vaddr[i]->grpname, cgutil_opt.wdname);
|
||||
else {
|
||||
|
|
@ -293,22 +237,37 @@ int cgexcp_class_exception(void)
|
|||
cgconf_remove_backup_conffile();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: the specified workload %s doesn't exist!\n", cgutil_opt.wdname);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "错误:指定的工作负载 %s 不存在!\n", cgutil_opt.wdname);
|
||||
cgconf_remove_backup_conffile();
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (-1 == cgexcp_exception_save(cgutil_vaddr[cls])) {
|
||||
cgconf_remove_backup_conffile();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: the specified class %s doesn't exist!\n", cgutil_opt.clsname);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "错误:指定的类 %s 不存在!\n", cgutil_opt.clsname);
|
||||
cgconf_remove_backup_conffile();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 示例说明:
|
||||
// 该函数用于处理类异常,首先检查指定的类是否存在,然后备份配置文件,接着根据不同的条件判断是否需要处理工作负载的异常。
|
||||
// 如果指定了异常中止标志位并且指定了工作负载名称,那么根据工作负载名称和类的关联关系找到对应的工作负载,并将其异常信息保存。
|
||||
// 如果没有指定工作负载名称,直接根据类的信息保存异常信息。
|
||||
// 如果指定的类不存在,则输出错误信息并返回异常。
|
||||
|
||||
// 语言块功能解析:
|
||||
// 1. 备份配置文件:cgconf_backup_config_file()函数用于备份配置文件。
|
||||
// 2. 判断工作负载名称是否有级别或者没有级别:根据工作负载名称判断是否有级别,如果有则使用strcmp()函数进行比较,如果没有则使用strncmp()函数进行比较。
|
||||
// 3. 异常信息保存:cgexcp_exception_save()函数用于保存异常信息。
|
||||
// 4. 移除备份的配置文件:cgconf_remove_backup_conffile()函数用于移除备份的配置文件。
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -27,7 +27,14 @@
|
|||
#include "securec_check.h"
|
||||
#include "cipher.h"
|
||||
#include "crypt.h"
|
||||
|
||||
/*
|
||||
function name: crypt_malloc_zero
|
||||
description: Distribute internal memory
|
||||
arguments: An integer that designates the size of internal memory distributed
|
||||
return value: A pointer of type void*
|
||||
Note:If the size of internal memory distributed is zero, it's unreasonable. The size should be greater than zero.
|
||||
At the same time, if malloc fails, program would exit.
|
||||
*/
|
||||
void* crypt_malloc_zero(size_t size)
|
||||
{
|
||||
void* ret = NULL;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,14 @@
|
|||
static int check_key_num(const char* password);
|
||||
static void create_child_dir(const char* pathdir);
|
||||
|
||||
|
||||
/*
|
||||
function name: check_path
|
||||
description: Check if the string delivered has the character that should not be included
|
||||
arguments: A pointer to string that its type is const char
|
||||
return value: void
|
||||
Note:none
|
||||
*/
|
||||
void check_path(const char *path_name)
|
||||
{
|
||||
const char* danger_character_list[] = {"|",
|
||||
|
|
@ -69,6 +77,14 @@ void check_path(const char *path_name)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function name: check_key_num
|
||||
description: Check if the password is a null string, if so, then the password is invalid.
|
||||
At the same time, the function check if the length of password exceeds MAX_CRYPT_LEN, if so, print the error.
|
||||
arguments: A pointer to string that its type is const char
|
||||
return value: An integer that its type is static int
|
||||
Note:The length of password should not be zero, and never exceeds MAX_CRYPT_LEN
|
||||
*/
|
||||
static int check_key_num(const char* password)
|
||||
{
|
||||
int key_len = 0;
|
||||
|
|
|
|||
|
|
@ -1229,6 +1229,12 @@ parse_next_sync_groups(char **pgroup, char *result)
|
|||
static int
|
||||
transform_az_name(char *config_value, char *allAZString, int allAZStringBufLen, const char *data_dir)
|
||||
{
|
||||
if (strcmp(config_value, "''") == 0) {
|
||||
errno_t rc = strncpy_s(allAZString, allAZStringBufLen, config_value, strlen(config_value));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
char *azString = NULL;
|
||||
char *buf = allAZString;
|
||||
int buflen = allAZStringBufLen;
|
||||
|
|
|
|||
|
|
@ -5923,7 +5923,7 @@ int main(int argc, char** argv)
|
|||
&option_index)) != -1)
|
||||
#endif
|
||||
#else
|
||||
while ((c = getopt_long(argc, argv, "b:cD:e:fi:G:l:m:M:N:o:O:p:P:r:R:v:x:sS:t:u:U:wWZ:dqL:T:Q:", long_options,
|
||||
while ((c = getopt_long(argc, argv, "b:cD:e:fi:G:l:m:M:N:o:O:p:P:r:R:v:x:sS:t:u:U:wWZ:C:dqL:T:Q:", long_options,
|
||||
&option_index)) != -1)
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ char* all_data_nodename_list = NULL;
|
|||
const uint32 USTORE_UPGRADE_VERSION = 92368;
|
||||
const uint32 PACKAGE_ENHANCEMENT = 92444;
|
||||
const uint32 SUBSCRIPTION_VERSION = 92580;
|
||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92607;
|
||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92606;
|
||||
|
||||
#ifdef DUMPSYSLOG
|
||||
char* syslogpath = NULL;
|
||||
|
|
@ -4454,16 +4454,7 @@ void getSubscriptions(Archive *fout)
|
|||
}
|
||||
|
||||
if (!isExecUserSuperRole(fout)) {
|
||||
res = ExecuteSqlQuery(fout,
|
||||
"SELECT count(*) FROM pg_subscription "
|
||||
"WHERE subdbid = (SELECT oid FROM pg_catalog.pg_database"
|
||||
" WHERE datname = current_database())",
|
||||
PGRES_TUPLES_OK);
|
||||
uint64 n = (res != NULL) ? strtoul(PQgetvalue(res, 0, 0), NULL, 10) : 0;
|
||||
if (n > 0) {
|
||||
write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
|
||||
}
|
||||
PQclear(res);
|
||||
write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -10795,6 +10786,11 @@ static void dumpDirectory(Archive* fout)
|
|||
char* dirpath = NULL;
|
||||
char* diracl = NULL;
|
||||
|
||||
if (!isExecUserSuperRole(fout)) {
|
||||
write_msg(NULL, "WARNING: directory not dumped because current user is not a superuser\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure we are in proper schema */
|
||||
selectSourceSchema(fout, "pg_catalog");
|
||||
|
||||
|
|
@ -21404,6 +21400,11 @@ static void dumpSynonym(Archive* fout)
|
|||
PQExpBuffer q;
|
||||
PQExpBuffer delq;
|
||||
|
||||
if (!isExecUserSuperRole(fout)) {
|
||||
write_msg(NULL, "WARNING: synonym not dumped because current user is not a superuser\n");
|
||||
return;
|
||||
}
|
||||
|
||||
selectSourceSchema(fout, "pg_catalog");
|
||||
query = createPQExpBuffer();
|
||||
printfPQExpBuffer(query,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@
|
|||
it will be backuped up in external dirs */
|
||||
parray *pgdata_nobackup_dir = NULL;
|
||||
|
||||
/* list of logical replication slots */
|
||||
parray *logical_replslot = NULL;
|
||||
|
||||
static int standby_message_timeout_local = 10 ; /* 10 sec = default */
|
||||
static XLogRecPtr stop_backup_lsn = InvalidXLogRecPtr;
|
||||
static XLogRecPtr stop_stream_lsn = InvalidXLogRecPtr;
|
||||
|
|
@ -89,10 +92,11 @@ static void backup_cleanup(bool fatal, void *userdata);
|
|||
|
||||
static void *backup_files(void *arg);
|
||||
|
||||
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs);
|
||||
static void do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs,
|
||||
bool backup_replslots);
|
||||
|
||||
static void pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
||||
PGNodeInfo *nodeInfo, PGconn *conn);
|
||||
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots);
|
||||
static void pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn, PGNodeInfo *nodeInfo);
|
||||
static int checkpoint_timeout(PGconn *backup_conn);
|
||||
|
||||
|
|
@ -558,7 +562,7 @@ static void sync_files(parray *database_map, const char *database_path, parray *
|
|||
* Move files from 'pgdata' to a subdirectory in 'backup_path'.
|
||||
*/
|
||||
static void
|
||||
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs)
|
||||
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs, bool backup_replslots)
|
||||
{
|
||||
int i;
|
||||
char database_path[MAXPGPATH];
|
||||
|
|
@ -591,7 +595,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
|||
securec_check_c(rc, "\0", "\0");
|
||||
|
||||
/* Call pg_start_backup function in openGauss connect */
|
||||
pg_start_backup(label, smooth_checkpoint, ¤t, nodeInfo, backup_conn);
|
||||
pg_start_backup(label, smooth_checkpoint, ¤t, nodeInfo, backup_conn, backup_replslots);
|
||||
|
||||
/* Obtain current timeline */
|
||||
#if PG_VERSION_NUM >= 90600
|
||||
|
|
@ -624,10 +628,10 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
|||
/* list files with the logical path. omit $PGDATA */
|
||||
if (fio_is_remote(FIO_DB_HOST))
|
||||
fio_list_dir(backup_files_list, instance_config.pgdata,
|
||||
true, true, false, backup_logs, true, 0);
|
||||
true, true, false, backup_logs, true, 0, backup_replslots);
|
||||
else
|
||||
dir_list_file(backup_files_list, instance_config.pgdata,
|
||||
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST);
|
||||
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST, backup_replslots);
|
||||
|
||||
/*
|
||||
* Get database_map (name to oid) for use in partial restore feature.
|
||||
|
|
@ -749,6 +753,11 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
|||
}
|
||||
pgdata_nobackup_dir = NULL;
|
||||
|
||||
if (logical_replslot) {
|
||||
free_dir_list(logical_replslot);
|
||||
}
|
||||
logical_replslot = NULL;
|
||||
|
||||
/* Cleanup */
|
||||
if (backup_list)
|
||||
{
|
||||
|
|
@ -849,7 +858,7 @@ static void do_after_backup()
|
|||
*/
|
||||
int
|
||||
do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
||||
bool no_validate, bool no_sync, bool backup_logs)
|
||||
bool no_validate, bool no_sync, bool backup_logs, bool backup_replslots)
|
||||
{
|
||||
PGconn *backup_conn = NULL;
|
||||
PGNodeInfo nodeInfo;
|
||||
|
|
@ -925,7 +934,7 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
|||
add_note(¤t, set_backup_params->note);
|
||||
|
||||
/* backup data */
|
||||
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs);
|
||||
do_backup_instance(backup_conn, &nodeInfo, no_sync, backup_logs, backup_replslots);
|
||||
pgut_atexit_pop(backup_cleanup, NULL);
|
||||
|
||||
/* compute size of wal files of this backup stored in the archive */
|
||||
|
|
@ -1034,13 +1043,15 @@ confirm_block_size(PGconn *conn, const char *name, int blcksz)
|
|||
*/
|
||||
static void
|
||||
pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
||||
PGNodeInfo *nodeInfo, PGconn *conn)
|
||||
PGNodeInfo *nodeInfo, PGconn *conn, bool backup_replslots)
|
||||
{
|
||||
PGresult *res;
|
||||
const char *params[2];
|
||||
uint32 lsn_hi;
|
||||
uint32 lsn_lo;
|
||||
int ret;
|
||||
int i;
|
||||
XLogRecPtr startLsn;
|
||||
|
||||
params[0] = label;
|
||||
|
||||
|
|
@ -1068,7 +1079,33 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup,
|
|||
XLogDataFromLSN(ret, PQgetvalue(res, 0, 0), &lsn_hi, &lsn_lo);
|
||||
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
|
||||
/* Calculate LSN */
|
||||
backup->start_lsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
|
||||
startLsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
|
||||
|
||||
if (backup_replslots) {
|
||||
logical_replslot = parray_new();
|
||||
/* query for logical replication slots of subscriptions */
|
||||
res = pgut_execute(conn,
|
||||
"SELECT slot_name, restart_lsn FROM pg_catalog.pg_get_replication_slots()"
|
||||
"WHERE slot_type = 'logical' AND plugin = 'pgoutput'", 0, NULL);
|
||||
if (PQntuples(res) == 0) {
|
||||
elog(LOG, "logical replication slots for subscriptions not found");
|
||||
} else {
|
||||
XLogRecPtr repslotLsn;
|
||||
|
||||
for (i = 0; i < PQntuples(res); i++) {
|
||||
XLogDataFromLSN(ret, PQgetvalue(res, i, 1), &lsn_hi, &lsn_lo);
|
||||
securec_check_for_sscanf_s(ret, 2, "\0", "\0");
|
||||
repslotLsn = ((uint64) lsn_hi )<< 32 | lsn_lo;
|
||||
startLsn = Min(startLsn, repslotLsn);
|
||||
|
||||
char* slotname = pg_strdup(PQgetvalue(res, i, 0));
|
||||
parray_append(logical_replslot, slotname);
|
||||
}
|
||||
elog(WARNING, "logical replication slots for subscriptions will be backed up. "
|
||||
"If don't use them after restoring, please drop them to avoid affecting xlog recycling.");
|
||||
}
|
||||
}
|
||||
backup->start_lsn = startLsn;
|
||||
|
||||
PQclear(res);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,13 +42,6 @@ const char *pgdata_exclude_dir[] =
|
|||
(const char *)"pg_stat_tmp",
|
||||
(const char *)"pgsql_tmp",
|
||||
|
||||
/*
|
||||
* It is generally not useful to backup the contents of this directory even
|
||||
* if the intention is to restore to another master. See backup.sgml for a
|
||||
* more detailed description.
|
||||
*/
|
||||
(const char *)"pg_replslot",
|
||||
|
||||
/* Contents removed on startup, see dsm_cleanup_for_mmap(). */
|
||||
(const char *)"pg_dynshmem",
|
||||
|
||||
|
|
@ -68,7 +61,7 @@ const char *pgdata_exclude_dir[] =
|
|||
(const char *)"pg_subtrans",
|
||||
|
||||
/* end of list */
|
||||
NULL, /* pg_log will be set later */
|
||||
NULL, /* pg_log and pg_replslot will be set later */
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -128,17 +121,20 @@ may be removed int the future */
|
|||
|
||||
static int pgCompareString(const void *str1, const void *str2);
|
||||
|
||||
static char dir_check_file(pgFile *file, bool backup_logs);
|
||||
static char dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots);
|
||||
static char check_in_tablespace(pgFile *file, bool in_tablespace);
|
||||
static char check_db_dir(pgFile *file);
|
||||
static char check_digit_file(pgFile *file);
|
||||
static char check_nobackup_dir(pgFile *file);
|
||||
static void dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
||||
bool exclude, bool follow_symlink, bool backup_logs,
|
||||
bool skip_hidden, int external_dir_num, fio_location location);
|
||||
bool skip_hidden, int external_dir_num, fio_location location,
|
||||
bool backup_replslots);
|
||||
static void opt_path_map(ConfigOption *opt, const char *arg,
|
||||
TablespaceList *list, const char *type);
|
||||
|
||||
char check_logical_replslot_dir(const char *rel_path);
|
||||
|
||||
/* Tablespace mapping */
|
||||
static TablespaceList tablespace_dirs = {NULL, NULL};
|
||||
/* Extra directories mapping */
|
||||
|
|
@ -538,7 +534,7 @@ db_map_entry_free(void *entry)
|
|||
void
|
||||
dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink,
|
||||
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num,
|
||||
fio_location location)
|
||||
fio_location location, bool backup_replslots)
|
||||
{
|
||||
pgFile *file;
|
||||
|
||||
|
|
@ -565,7 +561,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink
|
|||
parray_append(files, file);
|
||||
|
||||
dir_list_file_internal(files, file, root, exclude, follow_symlink,
|
||||
backup_logs, skip_hidden, external_dir_num, location);
|
||||
backup_logs, skip_hidden, external_dir_num, location, backup_replslots);
|
||||
|
||||
if (!add_root)
|
||||
pgFileFree(file);
|
||||
|
|
@ -589,7 +585,7 @@ dir_list_file(parray *files, const char *root, bool exclude, bool follow_symlink
|
|||
* - datafiles
|
||||
*/
|
||||
static char
|
||||
dir_check_file(pgFile *file, bool backup_logs)
|
||||
dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots)
|
||||
{
|
||||
int i;
|
||||
int sscanf_res;
|
||||
|
|
@ -652,6 +648,29 @@ dir_check_file(pgFile *file, bool backup_logs)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Backup pg_replslot if it is specified.
|
||||
* It is generally not useful to backup the contents of this directory even
|
||||
* if the intention is to restore to another master. See backup.sgml for a
|
||||
* more detailed description.
|
||||
*/
|
||||
if (!backup_replslots) {
|
||||
if (strcmp(file->rel_path, PG_REPLSLOT_DIR) == 0) {
|
||||
/* Skip */
|
||||
elog(VERBOSE, "Excluding directory content: %s", file->rel_path);
|
||||
return CHECK_EXCLUDE_FALSE;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Check file that under pg_replslot and judge whether it
|
||||
* belonged to logical replication slots for subscriptions.
|
||||
*/
|
||||
if (strcmp(file->rel_path, PG_REPLSLOT_DIR) != 0 &&
|
||||
path_is_prefix_of_path(PG_REPLSLOT_DIR, file->rel_path)) {
|
||||
return check_logical_replslot_dir(file->rel_path);
|
||||
}
|
||||
}
|
||||
|
||||
ret = check_nobackup_dir(file);
|
||||
if (ret != -1) { /* -1 means need backup */
|
||||
return ret;
|
||||
|
|
@ -749,6 +768,35 @@ static char check_nobackup_dir(pgFile *file)
|
|||
return ret;
|
||||
}
|
||||
|
||||
char check_logical_replslot_dir(const char *rel_path)
|
||||
{
|
||||
char ret = CHECK_FALSE;
|
||||
int i = 0;
|
||||
char *tmp = pg_strdup(rel_path);
|
||||
char *p;
|
||||
#define DIRECTORY_DELIMITER "/"
|
||||
|
||||
if (logical_replslot) {
|
||||
/* extract slot name from rel_path, such as sub1 from pg_replslot/sub1/snap */
|
||||
p = strtok(tmp, DIRECTORY_DELIMITER);
|
||||
if (p != NULL) {
|
||||
p = strtok(NULL, DIRECTORY_DELIMITER);
|
||||
}
|
||||
|
||||
for (i = 0; p != NULL && i < (int)parray_num(logical_replslot); i++) {
|
||||
char *slotName = (char *)parray_get(logical_replslot, i);
|
||||
if (strcmp(p, slotName) == 0) {
|
||||
pfree(tmp);
|
||||
return CHECK_TRUE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = CHECK_TRUE;
|
||||
}
|
||||
pfree(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char check_db_dir(pgFile *file)
|
||||
{
|
||||
char ret = -1;
|
||||
|
|
@ -889,7 +937,8 @@ bool SkipSomeDirFile(pgFile *file, struct dirent *dent, bool skipHidden)
|
|||
static void
|
||||
dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
||||
bool exclude, bool follow_symlink, bool backup_logs,
|
||||
bool skip_hidden, int external_dir_num, fio_location location)
|
||||
bool skip_hidden, int external_dir_num, fio_location location,
|
||||
bool backup_replslots)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
|
|
@ -937,7 +986,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
|||
|
||||
if (exclude)
|
||||
{
|
||||
check_res = dir_check_file(file, backup_logs);
|
||||
check_res = dir_check_file(file, backup_logs, backup_replslots);
|
||||
if (check_res == CHECK_FALSE)
|
||||
{
|
||||
/* Skip */
|
||||
|
|
@ -963,7 +1012,7 @@ dir_list_file_internal(parray *files, pgFile *parent, const char *parent_dir,
|
|||
*/
|
||||
if (S_ISDIR(file->mode))
|
||||
dir_list_file_internal(files, file, child, exclude, follow_symlink,
|
||||
backup_logs, skip_hidden, external_dir_num, location);
|
||||
backup_logs, skip_hidden, external_dir_num, location, backup_replslots);
|
||||
}
|
||||
|
||||
if (errno && errno != ENOENT)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ typedef struct
|
|||
bool exclusive_backup;
|
||||
bool skip_hidden;
|
||||
int external_dir_num;
|
||||
bool backup_replslots;
|
||||
} fio_list_dir_request;
|
||||
|
||||
typedef struct
|
||||
|
|
@ -1794,7 +1795,7 @@ cleanup:
|
|||
/* Compile the array of files located on remote machine in directory root */
|
||||
void fio_list_dir(parray *files, const char *root, bool exclude,
|
||||
bool follow_symlink, bool add_root, bool backup_logs,
|
||||
bool skip_hidden, int external_dir_num)
|
||||
bool skip_hidden, int external_dir_num, bool backup_replslots)
|
||||
{
|
||||
fio_header hdr;
|
||||
fio_list_dir_request req;
|
||||
|
|
@ -1811,6 +1812,7 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
|
|||
req.exclusive_backup = exclusive_backup;
|
||||
req.skip_hidden = skip_hidden;
|
||||
req.external_dir_num = external_dir_num;
|
||||
req.backup_replslots = backup_replslots;
|
||||
|
||||
hdr.cop = FIO_LIST_DIR;
|
||||
hdr.size = sizeof(req);
|
||||
|
|
@ -1870,7 +1872,14 @@ void fio_list_dir(parray *files, const char *root, bool exclude,
|
|||
securec_check_ss_c(nRet, "\0", "\0");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check file that under pg_replslot and judge whether it
|
||||
* belonged to logical replication slots for subscriptions.
|
||||
*/
|
||||
if (backup_replslots && strcmp(buf, PG_REPLSLOT_DIR) != 0 &&
|
||||
path_is_prefix_of_path(PG_REPLSLOT_DIR, buf) && check_logical_replslot_dir(file->rel_path) != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
parray_append(files, file);
|
||||
}
|
||||
|
|
@ -1914,7 +1923,7 @@ static void fio_list_dir_impl(int out, char* buf)
|
|||
|
||||
dir_list_file(file_files, req->path, req->exclude, req->follow_symlink,
|
||||
req->add_root, req->backup_logs, req->skip_hidden,
|
||||
req->external_dir_num, FIO_LOCAL_HOST);
|
||||
req->external_dir_num, FIO_LOCAL_HOST, req->backup_replslots);
|
||||
|
||||
/* send information about files to the main process */
|
||||
for (i = 0; i < (int)parray_num(file_files); i++)
|
||||
|
|
|
|||
|
|
@ -163,5 +163,7 @@ extern z_off_t fio_gzseek(gzFile f, z_off_t offset, int whence);
|
|||
extern const char* fio_gzerror(gzFile file, int *errnum);
|
||||
#endif
|
||||
|
||||
extern char check_logical_replslot_dir(const char *rel_path);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ void help_pg_probackup(void)
|
|||
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
|
||||
printf(_(" [--remote-libpath=libpath]\n"));
|
||||
printf(_(" [--ttl=interval] [--expire-time=time]\n"));
|
||||
printf(_(" [--backup-pg-replslot]\n"));
|
||||
printf(_(" [--help]\n"));
|
||||
|
||||
printf(_("\n %s restore -B backup-path --instance=instance_name\n"), PROGRAM_NAME);
|
||||
|
|
@ -420,6 +421,7 @@ static void help_backup(void)
|
|||
printf(_(" [--remote-port=port] [--ssh-options=ssh_options]\n"));
|
||||
printf(_(" [--remote-libpath=libpath]\n"));
|
||||
printf(_(" [--ttl=interval] [--expire-time=time]\n\n"));
|
||||
printf(_(" [--backup-pg-replslot]\n"));
|
||||
|
||||
printf(_(" -B, --backup-path=backup-path location of the backup storage area\n"));
|
||||
printf(_(" --instance=instance_name name of the instance\n"));
|
||||
|
|
@ -441,6 +443,7 @@ static void help_backup(void)
|
|||
printf(_(" --note=text add note to backup\n"));
|
||||
printf(_(" (example: --note='backup before app update to v13.1')\n"));
|
||||
printf(_(" --archive-timeout=timeout wait timeout for WAL segment archiving (default: 5min)\n"));
|
||||
printf(_(" --backup-pg-replslot] backup of '%s' directory\n"), PG_REPLSLOT_DIR);
|
||||
|
||||
printf(_("\n Logging options:\n"));
|
||||
printf(_(" --log-level-console=log-level-console\n"));
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ int rw_timeout = 0;
|
|||
|
||||
/* backup options */
|
||||
bool backup_logs = false;
|
||||
bool backup_replslots = false;
|
||||
bool smooth_checkpoint;
|
||||
char *remote_agent;
|
||||
static char *backup_note = NULL;
|
||||
|
|
@ -186,6 +187,7 @@ static ConfigOption cmd_options[] =
|
|||
{ 'b', 145, "wal", &delete_wal, SOURCE_CMD_STRICT },
|
||||
{ 'b', 146, "expired", &delete_expired, SOURCE_CMD_STRICT },
|
||||
{ 's', 172, "status", &delete_status, SOURCE_CMD_STRICT },
|
||||
{ 'b', 186, "backup-pg-replslot", &backup_replslots, SOURCE_CMD_STRICT},
|
||||
|
||||
{ 'b', 147, "force", &force, SOURCE_CMD_STRICT },
|
||||
{ 'b', 148, "compress", &compress_shortcut, SOURCE_CMD_STRICT },
|
||||
|
|
@ -550,7 +552,7 @@ static int do_actual_operate()
|
|||
elog(ERROR, "required parameter not specified: BACKUP_MODE "
|
||||
"(-b, --backup-mode)");
|
||||
|
||||
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs);
|
||||
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs, backup_replslots);
|
||||
}
|
||||
case RESTORE_CMD:
|
||||
return do_restore_or_validate(current.backup_id,
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ extern const char *PROGRAM_FULL_PATH;
|
|||
#define HEADER_MAP "page_header_map"
|
||||
#define HEADER_MAP_TMP "page_header_map_tmp"
|
||||
#define PG_RELATIVE_TBLSPC_DIR "pg_location"
|
||||
#define PG_REPLSLOT_DIR "pg_replslot"
|
||||
|
||||
/* Timeout defaults */
|
||||
#define ARCHIVE_TIMEOUT_DEFAULT 300
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ extern bool smooth_checkpoint;
|
|||
it will be backuped up in external dirs */
|
||||
extern parray *pgdata_nobackup_dir;
|
||||
|
||||
/* list of logical replication slots */
|
||||
extern parray *logical_replslot;
|
||||
|
||||
/* remote probackup options */
|
||||
extern char* remote_agent;
|
||||
|
||||
|
|
@ -89,7 +92,7 @@ extern const char *pgdata_exclude_dir[];
|
|||
|
||||
/* in backup.c */
|
||||
extern int do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
||||
bool no_validate, bool no_sync, bool backup_logs);
|
||||
bool no_validate, bool no_sync, bool backup_logs, bool backup_replslots);
|
||||
extern BackupMode parse_backup_mode(const char *value);
|
||||
extern const char *deparse_backup_mode(BackupMode mode);
|
||||
extern void process_block_change(ForkNumber forknum, const RelFileNode rnode,
|
||||
|
|
@ -239,7 +242,8 @@ extern const char* deparse_compress_alg(int alg);
|
|||
/* in dir.c */
|
||||
extern void dir_list_file(parray *files, const char *root, bool exclude,
|
||||
bool follow_symlink, bool add_root, bool backup_logs,
|
||||
bool skip_hidden, int external_dir_num, fio_location location);
|
||||
bool skip_hidden, int external_dir_num, fio_location location,
|
||||
bool backup_replslots = false);
|
||||
|
||||
extern void create_data_directories(parray *dest_files,
|
||||
const char *data_dir,
|
||||
|
|
@ -432,7 +436,8 @@ extern int fio_send_file(const char *from_fullpath, const char *to_fullpath, FIL
|
|||
pgFile *file, char **errormsg);
|
||||
|
||||
extern void fio_list_dir(parray *files, const char *root, bool exclude, bool follow_symlink,
|
||||
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num);
|
||||
bool add_root, bool backup_logs, bool skip_hidden, int external_dir_num,
|
||||
bool backup_replslots = false);
|
||||
|
||||
extern bool pgut_rmtree(const char *path, bool rmtopdir, bool strict);
|
||||
|
||||
|
|
|
|||
|
|
@ -8641,7 +8641,7 @@
|
|||
),
|
||||
AddFuncGroup(
|
||||
"pg_stat_get_wal_senders", 1,
|
||||
AddBuiltinFunc(_0(3099), _1("pg_stat_get_wal_senders"), _2(0), _3(false), _4(true), _5(pg_stat_get_wal_senders), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(10), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(0), _21(22, 20, 23, 25, 25, 25, 25, 1184, 1184, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 23, 23, 25, 25), _22(22, 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o'), _23(22, "pid", "sender_pid", "local_role", "peer_role", "peer_state", "state", "catchup_start", "catchup_end", "sender_sent_location", "sender_write_location", "sender_flush_location", "sender_replay_location", "receiver_received_location", "receiver_write_location", "receiver_flush_location", "receiver_replay_location", "sync_percent", "sync_state", "sync_group", "sync_priority", "sync_most_available", "channel"), _24(NULL), _25("pg_stat_get_wal_senders"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("statistics: information about currently active replication"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
|
||||
AddBuiltinFunc(_0(3099), _1("pg_stat_get_wal_senders"), _2(0), _3(false), _4(true), _5(pg_stat_get_wal_senders), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(10), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(0), _21(21, 20, 23, 25, 25, 25, 25, 1184, 1184, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 23, 25, 25), _22(21, 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o', 'o'), _23(21, "pid", "sender_pid", "local_role", "peer_role", "peer_state", "state", "catchup_start", "catchup_end", "sender_sent_location", "sender_write_location", "sender_flush_location", "sender_replay_location", "receiver_received_location", "receiver_write_location", "receiver_flush_location", "receiver_replay_location", "sync_percent", "sync_state", "sync_priority", "sync_most_available", "channel"), _24(NULL), _25("pg_stat_get_wal_senders"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("statistics: information about currently active replication"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
|
||||
),
|
||||
AddFuncGroup(
|
||||
"pg_stat_get_wlm_ec_operator_info", 1,
|
||||
|
|
|
|||
|
|
@ -6230,7 +6230,7 @@ Datum GetPartBoundaryByTuple(Relation rel, HeapTuple tuple)
|
|||
return Timestamp2Boundarys(rel, Align2UpBoundary(value, partMap->intervalValue, boundaryTs));
|
||||
}
|
||||
|
||||
Oid AddNewIntervalPartition(Relation rel, void* insertTuple)
|
||||
Oid AddNewIntervalPartition(Relation rel, void* insertTuple, bool isDDL)
|
||||
{
|
||||
Relation pgPartRel = NULL;
|
||||
Oid newPartOid = InvalidOid;
|
||||
|
|
@ -6327,7 +6327,13 @@ Oid AddNewIntervalPartition(Relation rel, void* insertTuple)
|
|||
*/
|
||||
CommandCounterIncrement();
|
||||
|
||||
UpdatePgObjectChangecsn(RelationGetRelid(rel), rel->rd_rel->relkind);
|
||||
/*
|
||||
* If add interval partition in the DDL, do not need to change the csn
|
||||
* because the scn has been changed in the DDL.
|
||||
*/
|
||||
if (!isDDL) {
|
||||
UpdatePgObjectChangecsn(RelationGetRelid(rel), rel->rd_rel->relkind);
|
||||
}
|
||||
|
||||
return newPartOid;
|
||||
}
|
||||
|
|
@ -7113,7 +7119,7 @@ int lookupHBucketid(oidvector *buckets, int low, int2 bktId)
|
|||
* Description :
|
||||
* Notes :
|
||||
*/
|
||||
Oid heapTupleGetPartitionId(Relation rel, void *tuple)
|
||||
Oid heapTupleGetPartitionId(Relation rel, void *tuple, bool isDDL)
|
||||
{
|
||||
Oid partitionid = InvalidOid;
|
||||
|
||||
|
|
@ -7140,7 +7146,7 @@ Oid heapTupleGetPartitionId(Relation rel, void *tuple)
|
|||
(errcode(ERRCODE_NO_DATA_FOUND), errmsg("inserted partition key does not map to any table partition")));
|
||||
} break;
|
||||
case PART_AREA_INTERVAL: {
|
||||
return AddNewIntervalPartition(rel, tuple);
|
||||
return AddNewIntervalPartition(rel, tuple, isDDL);
|
||||
} break;
|
||||
case PART_AREA_LIST: {
|
||||
ereport(ERROR,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ static void InternalAggIsSupported(const char *aggName)
|
|||
"json_agg",
|
||||
"json_object_agg",
|
||||
"st_summarystatsagg",
|
||||
"st_union"
|
||||
"st_union",
|
||||
"wm_concat"
|
||||
};
|
||||
|
||||
uint len = lengthof(supportList);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ static_assert(sizeof(false) == sizeof(char), "illegal bool size");
|
|||
static struct HTAB* nameHash = NULL;
|
||||
static struct HTAB* oidHash = NULL;
|
||||
|
||||
/* for b_sql_plugin */
|
||||
/* for dolphin */
|
||||
struct HTAB* b_nameHash = NULL;
|
||||
struct HTAB* b_oidHash = NULL;
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ static const FuncGroup* NameHashTableAccess(HASHACTION action, const char* name,
|
|||
|
||||
Assert(name != NULL);
|
||||
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_nameHash != NULL && u_sess->attr.attr_sql.dolphin) {
|
||||
result = (HashEntryNameToFuncGroup *)hash_search(b_nameHash, &temp_name, action, &found);
|
||||
} else {
|
||||
result = (HashEntryNameToFuncGroup *)hash_search(nameHash, &temp_name, action, &found);
|
||||
|
|
@ -144,7 +144,7 @@ static const Builtin_func* OidHashTableAccess(HASHACTION action, Oid oid, const
|
|||
bool found = false;
|
||||
Assert(oid > 0);
|
||||
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.b_sql_plugin) {
|
||||
if (DB_IS_CMPT(B_FORMAT) && b_oidHash != NULL && u_sess->attr.attr_sql.dolphin) {
|
||||
result = (HashEntryOidToBuiltinFunc *)hash_search(b_oidHash, &oid, action, &found);
|
||||
} else {
|
||||
result = (HashEntryOidToBuiltinFunc *)hash_search(oidHash, &oid, action, &found);
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ Subscription *GetSubscription(Oid subid, bool missing_ok)
|
|||
|
||||
/* Get slotname */
|
||||
datum = SysCacheGetAttr(SUBSCRIPTIONOID, tup, Anum_pg_subscription_subslotname, &isnull);
|
||||
if (unlikely(isnull)) {
|
||||
if (!isnull) {
|
||||
sub->slotname = pstrdup(NameStr(*DatumGetName(datum)));
|
||||
} else {
|
||||
sub->slotname = NULL;
|
||||
|
|
@ -92,10 +92,10 @@ Subscription *GetSubscription(Oid subid, bool missing_ok)
|
|||
|
||||
datum = SysCacheGetAttr(SUBSCRIPTIONOID, tup, Anum_pg_subscription_subbinary, &isnull);
|
||||
if (unlikely(isnull)) {
|
||||
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE),
|
||||
errmsg("null binary for subscription %u", subid)));
|
||||
sub->binary = false;
|
||||
} else {
|
||||
sub->binary = DatumGetBool(datum);
|
||||
}
|
||||
sub->binary = DatumGetBool(datum);
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@ bool pg_md5_encrypt(const char* passwd, const char* salt, size_t salt_len, char*
|
|||
{
|
||||
size_t passwd_len = strlen(passwd);
|
||||
errno_t rc = EOK;
|
||||
/* the length of salt and password is <= SIZE_MAX */
|
||||
#ifndef WIN32
|
||||
if (unlikely(passwd_len >= SIZE_MAX - salt_len)) {
|
||||
return false;
|
||||
|
|
@ -322,6 +323,7 @@ bool pg_md5_encrypt(const char* passwd, const char* salt, size_t salt_len, char*
|
|||
char* crypt_buf = (char*)malloc(passwd_len + salt_len + 1);
|
||||
bool ret = false;
|
||||
|
||||
/* the buffer is not exist */
|
||||
if (crypt_buf == NULL)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -772,6 +772,15 @@ bool pg_sha256_encrypt_for_md5(const char* password, const char* salt, size_t sa
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* @Description: calculate the encrypted password for GsSm3.
|
||||
* @const char* password : the password need be encrypted.
|
||||
* @const char* salt_s : the content fo the slat.
|
||||
* @size_t salt_len : the length fo the slat.
|
||||
* @char* buf : the buffer to store the encrypted key with GsSm3.
|
||||
* @char* client_key_buf : the buffer to store the key of client.
|
||||
* @int iteration_count : to record the number of the iteration.
|
||||
*/
|
||||
bool GsSm3Encrypt(
|
||||
const char* password, const char* salt_s, size_t salt_len, char* buf, char* client_key_buf, int iteration_count)
|
||||
{
|
||||
|
|
@ -799,6 +808,7 @@ bool GsSm3Encrypt(
|
|||
}
|
||||
|
||||
password_len = strlen(password);
|
||||
/* Tranform string(64Bytes) to binary(32Bytes) */
|
||||
sha_hex_to_bytes32(salt, (char*)salt_s);
|
||||
/* calculate k */
|
||||
pkcs_ret = PKCS5_PBKDF2_HMAC((char*)password,
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@
|
|||
|
||||
THR_LOCAL bool skip_read_extern_fields = false;
|
||||
|
||||
#define IS_DATANODE_BUT_NOT_SINGLENODE (IS_PGXC_DATANODE && !IS_SINGLE_NODE)
|
||||
/*
|
||||
* Macros to simplify reading of different kinds of fields. Use these
|
||||
* wherever possible to reduce the chance for silly typos. Note that these
|
||||
|
|
@ -401,24 +402,27 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); /* skip :fldname */ \
|
||||
local_node->fldname = _readBitmapset()
|
||||
|
||||
#define READ_TYPEINFO_FIELD(fldname) \
|
||||
do { \
|
||||
if (local_node->fldname >= FirstBootstrapObjectId) { \
|
||||
IF_EXIST(exprtypename) \
|
||||
{ \
|
||||
char* exprtypename = NULL; \
|
||||
char* exprtypenamespace = NULL; \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypename = nullable_string(token, length); \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypenamespace = nullable_string(token, length); \
|
||||
local_node->fldname = get_typeoid(get_namespace_oid(exprtypenamespace, false), exprtypename); \
|
||||
pfree_ext(exprtypename); \
|
||||
pfree_ext(exprtypenamespace); \
|
||||
} \
|
||||
} \
|
||||
#define READ_TYPEINFO_FIELD(fldname) \
|
||||
do { \
|
||||
if (local_node->fldname >= FirstBootstrapObjectId) { \
|
||||
IF_EXIST(exprtypename) \
|
||||
{ \
|
||||
char* exprtypename = NULL; \
|
||||
char* exprtypenamespace = NULL; \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypename = nullable_string(token, length); \
|
||||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
exprtypenamespace = nullable_string(token, length); \
|
||||
/* No need to reset field on CN or singlenode, keep pg_strtok() for forward compatibility */ \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
||||
local_node->fldname = get_typeoid(get_namespace_oid(exprtypenamespace, false), exprtypename); \
|
||||
} \
|
||||
pfree_ext(exprtypename); \
|
||||
pfree_ext(exprtypenamespace); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define READ_TYPEINFO(typePtr) \
|
||||
|
|
@ -493,9 +497,30 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
funcnamespace = nullable_string(token, length); \
|
||||
if (IS_PGXC_DATANODE && !skip_read_extern_fields) { \
|
||||
local_node->fldname = \
|
||||
get_func_oid(funcname, get_namespace_oid(funcnamespace, false), (Expr*)local_node); \
|
||||
bool notfound = false; \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) { \
|
||||
Oid funcoid = InvalidOid; \
|
||||
do { \
|
||||
Oid nspid = get_namespace_oid(funcnamespace, true); \
|
||||
if (!OidIsValid(nspid)) { \
|
||||
notfound = true; \
|
||||
break; \
|
||||
} \
|
||||
funcoid = get_func_oid(funcname, nspid, (Expr*)local_node); \
|
||||
} while (0); \
|
||||
if (notfound || !OidIsValid(funcoid)) { \
|
||||
ereport(ERROR, \
|
||||
(errmodule(MOD_OPT), errcode(ERRCODE_UNDEFINED_OBJECT), \
|
||||
errmsg("Cannot identify function %s.%s while deserializing field.", \
|
||||
funcname, funcnamespace), \
|
||||
errdetail("Function with oid %u or its namespace may be renamed", \
|
||||
local_node->fldname), \
|
||||
errhint("Please rebuild column defalt expression, views etc. that are" \
|
||||
" related to this renamed object."), \
|
||||
errcause("Object renamed after recorded as nodetree."), \
|
||||
erraction("Rebuild relevant object."))); \
|
||||
} \
|
||||
local_node->fldname = funcoid; \
|
||||
} \
|
||||
pfree_ext(funcname); \
|
||||
pfree_ext(funcnamespace); \
|
||||
|
|
@ -525,7 +550,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
oprrightname = nullable_string(token, length); \
|
||||
if (IS_PGXC_DATANODE) { \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
||||
namespaceId = get_namespace_oid(opnamespace, false); \
|
||||
oprleft = get_typeoid(namespaceId, oprleftname); \
|
||||
oprright = oprleft; \
|
||||
|
|
@ -568,7 +593,7 @@ THR_LOCAL bool skip_read_extern_fields = false;
|
|||
token = pg_strtok(&length); \
|
||||
token = pg_strtok(&length); \
|
||||
oprrightname = nullable_string(token, length); \
|
||||
if (IS_PGXC_DATANODE) { \
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE) { \
|
||||
namespaceId = get_namespace_oid(opnamespace, false); \
|
||||
oprleft = get_typeoid(namespaceId, oprleftname); \
|
||||
oprright = oprleft; \
|
||||
|
|
@ -2126,14 +2151,21 @@ static FuncExpr* _readFuncExpr(void)
|
|||
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("NULL seqNamespace for nextval()")));
|
||||
}
|
||||
|
||||
if (!IS_PGXC_COORDINATOR && !skip_read_extern_fields) {
|
||||
Oid seqid = get_valid_relname_relid(seqNamespace, seqName);
|
||||
if (IS_DATANODE_BUT_NOT_SINGLENODE && !skip_read_extern_fields) {
|
||||
|
||||
Oid seqid = get_valid_relname_relid(seqNamespace, seqName, true);
|
||||
Const* firstArg = (Const*)linitial(local_node->args);
|
||||
if (OidIsValid(seqid)) {
|
||||
Const* firstArg = (Const*)linitial(local_node->args);
|
||||
if (firstArg != NULL) {
|
||||
firstArg->constvalue = ObjectIdGetDatum(seqid);
|
||||
}
|
||||
} else {
|
||||
ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("Cannot identify sequence %s.%s while deserializing field.", seqNamespace, seqName),
|
||||
errdetail("Sequence with oid %u or its namespace may be renamed",
|
||||
DatumGetObjectId(firstArg->constvalue)),
|
||||
errhint("Please rebuild column defalt expression, views etc. that are related to this sequence"),
|
||||
errcause("Object renamed after recorded as nodetree."), erraction("Rebuild relevant object.")));
|
||||
}
|
||||
}
|
||||
pfree_ext(seqName);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1454,7 +1454,14 @@ FuncCandidateList sort_candidate_func_list(FuncCandidateList oldCandidates)
|
|||
}
|
||||
candidates[smallestIndex] = NULL;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (candidates[i] != NULL) {
|
||||
lastCandidate->next = candidates[i];
|
||||
lastCandidate = lastCandidate->next;
|
||||
}
|
||||
}
|
||||
lastCandidate->next = NULL;
|
||||
pfree(candidates);
|
||||
return sortedCandidates;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ void GlobalBaseDefCache::RemoveElemFromBucket(GlobalBaseEntry *base)
|
|||
if (is_relation) {
|
||||
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
|
||||
uint64 rel_size = GetRelEstimateSize(entry);
|
||||
pg_atomic_fetch_sub_u64(&m_base_space, rel_size);
|
||||
pg_atomic_fetch_sub_u64(&m_base_space, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
|
||||
m_db_entry->MemoryEstimateSub(rel_size);
|
||||
} else {
|
||||
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
|
||||
|
|
@ -77,7 +77,7 @@ void GlobalBaseDefCache::AddHeadToBucket(Index hash_index, GlobalBaseEntry *base
|
|||
if (is_relation) {
|
||||
GlobalRelationEntry *entry = (GlobalRelationEntry *)base;
|
||||
uint64 rel_size = GetRelEstimateSize(entry);
|
||||
pg_atomic_fetch_add_u64(&m_base_space, rel_size);
|
||||
pg_atomic_fetch_add_u64(&m_base_space, AllocSetContextUsedSpace(((AllocSet)entry->rel_mem_manager)));
|
||||
m_db_entry->MemoryEstimateAdd(rel_size);
|
||||
} else {
|
||||
GlobalPartitionEntry *entry = (GlobalPartitionEntry *)base;
|
||||
|
|
@ -400,4 +400,4 @@ GlobalBaseDefCache::GlobalBaseDefCache(Oid db_oid, bool is_shared, GlobalSysDBCa
|
|||
m_base_space = 0;
|
||||
m_obj_locks = NULL;
|
||||
m_db_entry = entry;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -659,7 +659,27 @@ void GlobalSysDBCache::InitSysCacheRelIds()
|
|||
*/
|
||||
void GlobalSysDBCache::RefreshHotStandby()
|
||||
{
|
||||
if (!EnableGlobalSysCache()) {
|
||||
return;
|
||||
}
|
||||
hot_standby = (t_thrd.postmaster_cxt.HaShmData->current_mode != STANDBY_MODE || XLogStandbyInfoActive());
|
||||
if (hot_standby || !m_is_inited) {
|
||||
return;
|
||||
}
|
||||
/* clean all */
|
||||
for (int hash_index = 0; hash_index < m_nbuckets; hash_index ++) {
|
||||
PthreadRWlockRdlock(LOCAL_SYSDB_RESOWNER, &m_db_locks[hash_index]);
|
||||
for (Dlelem * elt = DLGetTail(m_bucket_list.GetBucket(hash_index)); elt != NULL;) {
|
||||
GlobalSysDBCacheEntry *entry = (GlobalSysDBCacheEntry *)DLE_VAL(elt);
|
||||
elt = DLGetPred(elt);
|
||||
entry->ResetDBCache<true>();
|
||||
}
|
||||
PthreadRWlockUnlock(LOCAL_SYSDB_RESOWNER, &m_db_locks[hash_index]);
|
||||
}
|
||||
if (m_global_shared_db_entry != NULL) {
|
||||
m_global_shared_db_entry->ResetDBCache<true>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GlobalSysDBCache::Init(MemoryContext parent)
|
||||
|
|
@ -1272,9 +1292,18 @@ int ResizeHashBucket(int origin_nbucket, DynamicHashBucketStrategy strategy)
|
|||
return cc_nbuckets;
|
||||
}
|
||||
|
||||
void NotifyGscRecoveryStarted()
|
||||
{
|
||||
if (!EnableGlobalSysCache()) {
|
||||
return;
|
||||
}
|
||||
g_instance.global_sysdbcache.recovery_finished = false;
|
||||
|
||||
}
|
||||
|
||||
void NotifyGscRecoveryFinished()
|
||||
{
|
||||
if (EnableGlobalSysCache()) {
|
||||
g_instance.global_sysdbcache.recovery_finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ void GlobalSysTabCache::InvalidTuples(int cache_id, uint32 hash_value, bool rese
|
|||
|
||||
/* maybe upgrade from version before v5r2c00, the cacheid is out of order
|
||||
* whatever, we cache nothing except relmap, so just ignore the catcache invalmsg */
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished) && m_global_systupcaches[cache_id] == NULL) {
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished && m_global_systupcaches[cache_id] == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ Partition LocalPartDefCache::SearchPartitionFromGlobalCopy(Oid part_oid)
|
|||
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
return NULL;
|
||||
}
|
||||
uint32 hash_value = oid_hash((void *)&(part_oid), sizeof(Oid));
|
||||
|
|
@ -165,7 +165,7 @@ static bool IsPartOidStoreInGlobal(Oid part_oid)
|
|||
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||
return false;
|
||||
}
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
return false;
|
||||
}
|
||||
if (g_instance.global_sysdbcache.StopInsertGSC()) {
|
||||
|
|
@ -456,4 +456,4 @@ Partition LocalPartDefCache::PartitionIdGetPartition(Oid part_oid, StorageType s
|
|||
}
|
||||
|
||||
return pd;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -433,7 +433,7 @@ LocalCatCTup *LocalSysTupCache::SearchTupleFromGlobal(Datum *arguments, uint32 h
|
|||
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||
m_global_systupcache->enable_rls ||
|
||||
!g_instance.global_sysdbcache.hot_standby ||
|
||||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||
unlikely(!IsPrimaryRecoveryFinished());
|
||||
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
|
||||
global_ct = m_global_systupcache->SearchTupleFromFile(hash_value, arguments, true);
|
||||
} else {
|
||||
|
|
@ -585,7 +585,7 @@ LocalCatCList *LocalSysTupCache::SearchListFromGlobal(int nkeys, Datum *argument
|
|||
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||
m_global_systupcache->enable_rls ||
|
||||
!g_instance.global_sysdbcache.hot_standby ||
|
||||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||
unlikely(!IsPrimaryRecoveryFinished());
|
||||
GlobalCatCList *global_cl;
|
||||
if (invalid_entries.ExistList() || bypass_gsc) {
|
||||
global_cl = m_global_systupcache->SearchListFromFile(hash_value, nkeys, arguments, true);
|
||||
|
|
@ -703,7 +703,7 @@ LocalCatCTup *LocalSysTupCache::SearchTupleFromGlobalForProcAllArgs(
|
|||
bool bypass_gsc = HistoricSnapshotActive() ||
|
||||
m_global_systupcache->enable_rls ||
|
||||
!g_instance.global_sysdbcache.hot_standby ||
|
||||
unlikely(!g_instance.global_sysdbcache.recovery_finished);
|
||||
unlikely(!IsPrimaryRecoveryFinished());
|
||||
if (invalid_entries.ExistTuple(hash_value) || bypass_gsc) {
|
||||
global_ct = m_global_systupcache->SearchTupleFromFileWithArgModes(hash_value, arguments, argModes, true);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ Relation LocalTabDefCache::SearchRelationFromGlobalCopy(Oid rel_oid)
|
|||
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
return NULL;
|
||||
}
|
||||
uint32 hash_value = oid_hash((void *)&(rel_oid), sizeof(Oid));
|
||||
|
|
@ -190,7 +190,7 @@ static bool IsRelOidStoreInGlobal(Oid rel_oid)
|
|||
if (!g_instance.global_sysdbcache.hot_standby) {
|
||||
return false;
|
||||
}
|
||||
if (unlikely(!g_instance.global_sysdbcache.recovery_finished)) {
|
||||
if (unlikely(!IsPrimaryRecoveryFinished())) {
|
||||
return false;
|
||||
}
|
||||
if (g_instance.global_sysdbcache.StopInsertGSC()) {
|
||||
|
|
@ -1137,4 +1137,4 @@ void LocalTabDefCache::ResetInitFlag()
|
|||
m_is_inited_phase3 = false;
|
||||
|
||||
m_db_id = InvalidOid;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1723,7 +1723,7 @@ char* get_relname_relid_extend(
|
|||
extern bool StreamTopConsumerAmI();
|
||||
|
||||
/* same as get_relname_relid except we check for cache invalidation here */
|
||||
Oid get_valid_relname_relid(const char* relnamespace, const char* relname)
|
||||
Oid get_valid_relname_relid(const char* relnamespace, const char* relname, bool nsp_missing_ok)
|
||||
{
|
||||
Oid nspid = InvalidOid;
|
||||
Oid oldnspid = InvalidOid;
|
||||
|
|
@ -1747,7 +1747,10 @@ Oid get_valid_relname_relid(const char* relnamespace, const char* relname)
|
|||
if (EnableLocalSysCache()) {
|
||||
thrd_inval_count = t_thrd.lsc_cxt.lsc->inval_cxt.SIMCounter;
|
||||
}
|
||||
nspid = get_namespace_oid(relnamespace, false);
|
||||
nspid = get_namespace_oid(relnamespace, nsp_missing_ok);
|
||||
if (!OidIsValid(nspid)) {
|
||||
return InvalidOid;
|
||||
}
|
||||
relid = get_relname_relid(relname, nspid);
|
||||
/*
|
||||
* In bootstrap processing mode, we don't bother with locking
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ bool open_join_children = true;
|
|||
bool will_shutdown = false;
|
||||
|
||||
/* hard-wired binary version number */
|
||||
const uint32 GRAND_VERSION_NUM = 92607;
|
||||
const uint32 GRAND_VERSION_NUM = 92606;
|
||||
|
||||
const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522;
|
||||
const uint32 UPSERT_WHERE_VERSION_NUM = 92514;
|
||||
|
|
@ -101,7 +101,7 @@ const uint32 PRIVS_DIRECTORY_VERSION_NUM = 92460;
|
|||
const uint32 COMMENT_RECORD_PARAM_VERSION_NUM = 92484;
|
||||
const uint32 SCAN_BATCH_MODE_VERSION_NUM = 92568;
|
||||
const uint32 PUBLICATION_VERSION_NUM = 92580;
|
||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92607;
|
||||
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92606;
|
||||
|
||||
/* Version number of the guc parameter backend_version added in V500R001C20 */
|
||||
const uint32 V5R1C20_BACKEND_VERSION_NUM = 92305;
|
||||
|
|
|
|||
|
|
@ -2712,8 +2712,8 @@ void PostgresInitializer::InitExtensionVariable()
|
|||
}
|
||||
|
||||
/* check whether the extension has been created */
|
||||
const char* b_sql_plugin = "b_sql_plugin";
|
||||
u_sess->attr.attr_sql.b_sql_plugin = CheckIfExtensionExists(b_sql_plugin);
|
||||
const char* dolphin = "dolphin";
|
||||
u_sess->attr.attr_sql.dolphin = CheckIfExtensionExists(dolphin);
|
||||
}
|
||||
|
||||
void PostgresInitializer::FinishInit()
|
||||
|
|
|
|||
|
|
@ -10340,7 +10340,16 @@ check_sql_expr(const char *stmt, int location, int leaderlen)
|
|||
|
||||
oldCxt = MemoryContextSwitchTo(u_sess->plsql_cxt.curr_compile_context->compile_tmp_cxt);
|
||||
u_sess->plsql_cxt.plpgsql_yylloc = plpgsql_yylloc;
|
||||
(void) raw_parser(stmt);
|
||||
RawParserHook parser_hook= raw_parser;
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
if (u_sess->attr.attr_sql.dolphin) {
|
||||
int id = GetCustomParserId();
|
||||
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
||||
parser_hook = (RawParserHook)g_instance.raw_parser_hook[id];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
(void)parser_hook(stmt, NULL);
|
||||
MemoryContextSwitchTo(oldCxt);
|
||||
|
||||
/* Restore former ereport callback */
|
||||
|
|
|
|||
|
|
@ -188,6 +188,21 @@ typedef struct _IndexList {
|
|||
*
|
||||
* This code is here just because of historical reasons.
|
||||
*/
|
||||
//这是一个主要的引导启动进程。它包含以下主要步骤:
|
||||
//初始化全局变量,设置进程ID(PostmasterPid)和启动时间(MyStartTime)。
|
||||
//使用进程ID和启动时间作为种子初始化随机数。
|
||||
//初始化错误和内存管理子系统。
|
||||
//初始化全局配置选项。
|
||||
//处理命令行参数。根据参数设置相应的配置选项。
|
||||
//验证并设置数据目录。
|
||||
//创建数据目录的锁文件。
|
||||
//设置处理模式为BootstrapProcessing。
|
||||
//初始化基本的后台进程。
|
||||
//初始化统计信息收集。
|
||||
//根据进程类型执行相应的操作。
|
||||
//如果进程类型是CheckerProcess,则执行CheckerModeMain()函数,并退出进程。
|
||||
//如果进程类型是BootstrapProcess,则设置信号处理函数,执行BootStrapXLOG()函数,然后执行BootstrapModeMain()函数,并退出进程。
|
||||
//如果进程类型未被识别,则触发PANIC错误,并退出进程。
|
||||
void BootStrapProcessMain(int argc, char* argv[])
|
||||
{
|
||||
char* progName = argv[0];
|
||||
|
|
@ -388,44 +403,45 @@ static void CheckerModeMain(void)
|
|||
* The bootstrap backend doesn't speak SQL, but instead expects
|
||||
* commands in a special bootstrap language.
|
||||
*/
|
||||
static void BootstrapModeMain(void)
|
||||
static void BootstrapModeMain(void)//BootstrapModeMain函数用于完成系统引导模式,即系统启动阶段执行的函数
|
||||
{
|
||||
int i;
|
||||
|
||||
Assert(!IsUnderPostmaster);
|
||||
Assert(!IsUnderPostmaster);// 断言,确认不是在后台进程中执行
|
||||
|
||||
SetProcessingMode(BootstrapProcessing);
|
||||
SetProcessingMode(BootstrapProcessing);// 设置处理模式为引导模式
|
||||
|
||||
/*
|
||||
* Do backend-like initialization for bootstrap mode
|
||||
*/
|
||||
InitProcess();
|
||||
|
||||
InitProcess();//为引导模式做类似后台进程的初始化
|
||||
// 设置参数PostInit字段为NULL
|
||||
t_thrd.proc_cxt.PostInit->SetDatabaseAndUser(NULL, InvalidOid, NULL);
|
||||
// 初始化引导模式
|
||||
t_thrd.proc_cxt.PostInit->InitBootstrap();
|
||||
|
||||
/* Initialize stuff for bootstrap-file processing */
|
||||
/* 初始化bootstrap文件处理的相关内容 */
|
||||
for (i = 0; i < MAXATTR; i++) {
|
||||
t_thrd.bootstrap_cxt.attrtypes[i] = NULL;
|
||||
Nulls[i] = false;
|
||||
t_thrd.bootstrap_cxt.attrtypes[i] = NULL;// 每个属性的类型初始化为NULL
|
||||
Nulls[i] = false; // 每个属性的是否为空初始化为false
|
||||
}
|
||||
|
||||
/*
|
||||
* Process bootstrap input.
|
||||
*/
|
||||
boot_yyparse();
|
||||
boot_yyparse();//处理bootstrap输入
|
||||
|
||||
/*
|
||||
* We should now know about all mapped relations, so it's okay to write
|
||||
* out the initial relation mapping files.
|
||||
*/
|
||||
RelationMapFinishBootstrap();
|
||||
RelationMapFinishBootstrap();// 调用boot_yyparse函数进行解析
|
||||
|
||||
/* Clean up and exit */
|
||||
cleanup();
|
||||
proc_exit(0);
|
||||
cleanup();// 调用cleanup函数进行清理操作
|
||||
proc_exit(0);// 调用proc_exit函数结束进程
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* misc functions
|
||||
* ----------------------------------------------------------------
|
||||
|
|
@ -433,6 +449,22 @@ static void BootstrapModeMain(void)
|
|||
/*
|
||||
* Set up signal handling for a bootstrap process
|
||||
*/
|
||||
/*
|
||||
这个函数是一个初始化信号处理器的函数。根据是否在主服务器进程中运行来设置信号处理方式。
|
||||
|
||||
如果在主服务器进程中运行(IsUnderPostmaster为真),则设置一些信号的处理方式为忽略或默认处理。具体地:
|
||||
- SIGHUP信号被设置为忽略
|
||||
- SIGINT信号(取消查询)被设置为忽略
|
||||
- SIGTERM信号被设置为调用die()函数
|
||||
- SIGQUIT信号被设置为调用quickdie()函数
|
||||
- SIGALRM、SIGPIPE、SIGUSR1和SIGUSR2信号被设置为忽略
|
||||
- SIGCHLD、SIGTTIN、SIGTTOU、SIGCONT和SIGWINCH信号被设置为默认处理
|
||||
- 解除阻塞的信号被解除阻塞
|
||||
|
||||
如果不在主服务器进程中运行,则设置一些信号的处理方式为调用die()函数,同时解除阻塞的SIGUSR2信号。
|
||||
|
||||
总之,该函数的作用是为了根据运行环境设置合适的信号处理方式。
|
||||
*/
|
||||
static void bootstrap_signals(void)
|
||||
{
|
||||
if (IsUnderPostmaster) {
|
||||
|
|
@ -481,6 +513,20 @@ static void bootstrap_signals(void)
|
|||
* boot_openrel
|
||||
* ----------------
|
||||
*/
|
||||
/*
|
||||
这个函数的作用是打开一个关系(relation)。函数的输入参数是一个指向关系名的字符串。
|
||||
首先,函数检查关系名的长度是否超过了NAMEDATALEN。如果超过了,就将字符串的最后一个字符设置为'\0',这样就能确保字符串的长度不会超过NAMEDATALEN。
|
||||
然后,函数检查全局变量t_thrd.bootstrap_cxt.Typ是否为NULL。如果是NULL,说明还没有加载pg_type数据,需要加载该数据。
|
||||
加载pg_type数据的过程是从pg_type表中获取所有的行,并将行的数量存储到变量i中。然后,根据行的数量动态分配空间,并将空间的指针赋值给变量app。
|
||||
然后,循环执行i次,每次分配一个typmap结构的空间,并将该空间的指针存储到指针数组app中。最后,将数组的最后一个元素设置为NULL。
|
||||
接下来,重新开始扫描pg_type表,将扫描的结果存储到tup中。
|
||||
然后,将当前typmap结构的am_oid成员设置为tup的OID属性值,将am_typ成员设置为tup的实际数据,并将指针app递增1。循环扫描表的每一行,直到扫描结束。
|
||||
最后,关闭pg_type表,并将全局变量t_thrd.bootstrap_cxt.boot_reldesc设置为新打开的关系。获取关系的属性数量,并为每个属性分配一个空间。
|
||||
将关系的属性数据复制到属性空间中,并输出一些调试信息。
|
||||
这个函数的作用是打开一个关系,并加载关系的属性信息。
|
||||
加载属性信息的过程中,需要先加载pg_type表中的数据,并将数据存储到全局变量t_thrd.bootstrap_cxt.Typ中。
|
||||
然后根据关系的名称,打开关系并获取属性数量,为每个属性分配空间,并复制属性数据到空间中。
|
||||
*/
|
||||
void boot_openrel(char* relname)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -553,25 +599,41 @@ void boot_openrel(char* relname)
|
|||
* closerel
|
||||
* ----------------
|
||||
*/
|
||||
给函数closerel添加注释:
|
||||
|
||||
/**
|
||||
* @brief 关闭指定的关系。
|
||||
*
|
||||
* @param name 要关闭的关系的名称。
|
||||
*/
|
||||
void closerel(char* name)
|
||||
{
|
||||
// 检查是否传入了正确的参数
|
||||
if (name != NULL) {
|
||||
// 检查是否存在已打开的关系
|
||||
if (t_thrd.bootstrap_cxt.boot_reldesc) {
|
||||
// 检查要关闭的关系名是否与当前已打开的关系名不同
|
||||
if (strcmp(RelationGetRelationName(t_thrd.bootstrap_cxt.boot_reldesc), name) != 0)
|
||||
// 如果不同,报错,提示预期的关系名和实际的关系名
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("close of %s when %s was expected",
|
||||
name,
|
||||
RelationGetRelationName(t_thrd.bootstrap_cxt.boot_reldesc))));
|
||||
} else
|
||||
} else {
|
||||
// 如果不存在已打开的关系,报错,提示关闭关系前未打开任何关系
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("close of %s before any relation was opened", name)));
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否存在已打开的关系
|
||||
if (t_thrd.bootstrap_cxt.boot_reldesc == NULL)
|
||||
// 如果不存在已打开的关系,报错,提示没有可关闭的关系
|
||||
ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("no open relation to close")));
|
||||
else {
|
||||
// 输出调试信息,关闭关系,将已打开的关系指针设置为NULL
|
||||
ereport(DEBUG4, (errmsg("close relation %s", RelationGetRelationName(t_thrd.bootstrap_cxt.boot_reldesc))));
|
||||
heap_close(t_thrd.bootstrap_cxt.boot_reldesc, NoLock);
|
||||
t_thrd.bootstrap_cxt.boot_reldesc = NULL;
|
||||
|
|
@ -606,6 +668,16 @@ static void fix_attr_notnull(const char* name, int attnum)
|
|||
* will be called n times
|
||||
* ----------------
|
||||
*/
|
||||
/*
|
||||
这个函数是用来定义数据库表中的一个属性(列)。函数的参数包括属性的名称(name)、数据类型(type)、以及属性的位置(attnum)。
|
||||
函数首先检查是否存在正在处理的关系(表),如果有,则发出警告并关闭该关系。
|
||||
接下来,函数分配一个新的Attribute结构体给t_thrd.bootstrap_cxt.attrtypes[attnum],并用0填充这个结构体。
|
||||
然后,函数将给定的属性名称和类型复制到Attribute结构体中,并设置了其他关于属性的一些信息,如编号(attnum + 1)、数据类型的OID值、数据类型的长度、是否将数据类型存储为基本类型等。
|
||||
接下来,函数会判断属性是否可以为空。如果属性是一个固定宽度的数据类型,或者前面的属性也是不可为空的变量(用C结构体声明访问),则将属性标记为"not null"。
|
||||
接着,函数检查特定的属性名称,并将这些属性标记为可为空或不可为空。
|
||||
这里列举了两个示例情况,第一个是将名为"partkey"、"intervaltablespace"、"intspnum"的属性标记为可为空,第二个是将名为"roluseft"、"rolmonitoradmin"、"roloperatoradmin"和"rolpolicyadmin"的属性标记为不可为空。
|
||||
总之,这个函数用于定义数据库表中的一个属性,包括属性的名称、数据类型和是否可为空等信息,并根据一些规则来判断是否将属性标记为"not null"。
|
||||
*/
|
||||
void DefineAttr(const char* name, char* type, int attnum)
|
||||
{
|
||||
Oid typeoid;
|
||||
|
|
@ -694,6 +766,15 @@ void DefineAttr(const char* name, char* type, int attnum)
|
|||
* Otherwise, an OID will be assigned (if necessary) by heap_insert.
|
||||
* ----------------
|
||||
*/
|
||||
/*这个函数用于向表中插入一条元组。函数的参数是一个对象ID(objectid),表示要插入的元组的ID。函数通过`t_thrd.bootstrap_cxt.boot_reldesc`访问引导过程中的关系(表)描述符。
|
||||
首先,函数打印调试信息,包括要插入的行的ID和列数。然后,函数检查关系(表)描述符是否为引导过程中的pg_proc表的描述符,如果是,则报错,因为内置函数不应该被添加到pg_proc表中。
|
||||
接下来,函数调用`CreateTupleDesc`函数创建一个描述插入元组的元组描述符(tupDesc)。创建元组描述符时传递了一些参数,包括属性数目、关系是否具有物理上标识的Oid、属性类型数组以及关系的类型。
|
||||
然后,函数调用`tableam_tops_form_tuple`函数创建一个HeapTuple结构体,即要插入的元组。创建HeapTuple时使用了`tupDesc`、`values`(待插入的属性值数组)以及`Nulls`(表示每个属性是否为NULL的标记)。
|
||||
如果传递了非0的对象ID(objectid),则使用`HeapTupleSetOid`函数设置HeapTuple的对象ID。
|
||||
接下来,函数通过调用`simple_heap_insert`函数将HeapTuple插入到关系中。
|
||||
然后,函数通过调用`tableam_tops_free_tuple`函数释放之前创建的HeapTuple。
|
||||
最后,函数在插入完成后打印调试信息,并通过循环将`Nulls`数组重置为false,以便下一次插入元组时使用。
|
||||
总之,这个函数用于插入一条元组到表中。函数创建一个插入元组的元组描述符,然后根据传递的属性值和标记创建一个HeapTuple,并将其插入到关系中。最后,函数释放已创建的HeapTuple,并重置标记数组以备下次插入使用。*/
|
||||
void InsertOneTuple(Oid objectid)
|
||||
{
|
||||
HeapTuple tuple;
|
||||
|
|
@ -847,6 +928,16 @@ static Oid gettype(char* type)
|
|||
* can be made to work during early bootstrap.
|
||||
* ----------------
|
||||
*/
|
||||
/*
|
||||
这个函数用于获取指定类型(typid)的输入/输出数据。函数通过指定的typid查找对应的类型信息,并将这些信息通过输出参数返回给调用者。
|
||||
首先,函数检查`t_thrd.bootstrap_cxt.Typ`是否为空。如果不为空,说明在引导过程中已经获取到了`pg_type`表的内容。接下来,函数在`t_thrd.bootstrap_cxt.Typ`中查找指定的typid对应的类型信息,并将找到的信息保存在`ap`结构体中。
|
||||
如果没有找到指定的typid对应的信息,则报错,提示类型OID未在Typ列表中找到。
|
||||
接着,函数通过将`ap`结构体中的成员值赋给输出参数,将类型信息返回给调用者。具体包括类型的长度(typlen)、是否传递值(typbyval)、对齐方式(typalign)、分隔符(typdelim)、类型输入函数参数(typioparam)、类型输入函数(typinput)、类型输出函数(typoutput)。
|
||||
如果`t_thrd.bootstrap_cxt.Typ`为空,说明还没有获取到`pg_type`表的内容。在这种情况下,函数将使用固定的`TypInfo`数组来获取类型信息。函数通过遍历`TypInfo`数组,查找指定typid对应的类型信息,并将找到的信息保存在`typeindex`变量中。
|
||||
如果找不到指定typid对应的类型信息,则报错,提示类型OID在TypInfo中未找到。
|
||||
接下来,函数通过将`TypInfo`数组中的成员值赋给输出参数,将类型信息返回给调用者。具体包括类型的长度(typlen)、是否传递值(typbyval)、对齐方式(typalign)、分隔符(typdelim)、类型输入函数参数(typioparam)、类型输入函数(typinput)、类型输出函数(typoutput)。
|
||||
总之,这个函数用于获取指定类型的输入/输出数据。函数根据是否已经获取到`pg_type`表的内容来决定是使用`pg_type`中的类型信息,还是使用固定的`TypInfo`数组中的类型信息。然后,函数将获取到的类型信息通过输出参数返回给调用者。
|
||||
*/
|
||||
void boot_get_type_io_data(Oid typid, int16* typlen, bool* typbyval, char* typalign, char* typdelim, Oid* typioparam,
|
||||
Oid* typinput, Oid* typoutput)
|
||||
{
|
||||
|
|
@ -967,6 +1058,15 @@ const char* MapArrayTypeName(const char* s)
|
|||
* indexes on those catalogs. Doing it in two phases is the simplest
|
||||
* way of making sure the indexes have the right contents at the end.
|
||||
*/
|
||||
/*这个函数用于在引导过程中注册索引。函数接收三个参数:heap(堆表的对象ID)、ind(索引的对象ID)和indexInfo(IndexInfo结构体的指针,包含了索引的详细信息)。
|
||||
函数。首先,函数创建一个IndexList结构体的实例newind,并将其初始化为NULL。
|
||||
接下来,函数检查是否已经创建了t_thrd.bootstrap_cxt.nogc上下文,如果没有,则创建一个名为"BootstrapNoGC"的上下文。这个上下文用于在引导过程中暂时保存索引的相关信息,防止其被垃圾回收。
|
||||
然后函数将当前的内存上下文切换到t_thrd.bootstrap_cxt.nogc上下文。
|
||||
接着,函数分配一个IndexList结构体的内存,并将heap、ind和indexInfo的值分别赋给新分配的结构体的相应成员变量。
|
||||
然后函数通过memcpy_s函数将indexInfo结构体的内容复制到newind->il_info中。同时,函数使用copyObject函数分别复制indexInfo->ii_Expressions和indexInfo->ii_Predicate,并将复制后的值分别赋给newind->il_info->ii_Expressions和newind->il_info->ii_Predicate。
|
||||
接下来,函数将newind添加到t_thrd.bootstrap_cxt.ILHead链表中,以便在稍后的操作中使用。
|
||||
最后,函数将内存上下文切换回先前的上下文。
|
||||
总之,这个函数用于在引导过程中注册索引。它创建一个表示索引的IndexList结构体对象,并将索引相关的信息保存在其中。然后,它将这个对象添加到上下文链表中以备后续使用。*/
|
||||
void index_register(Oid heap, Oid ind, IndexInfo* indexInfo)
|
||||
{
|
||||
IndexList* newind = NULL;
|
||||
|
|
@ -1011,6 +1111,14 @@ void index_register(Oid heap, Oid ind, IndexInfo* indexInfo)
|
|||
/*
|
||||
* build_indices -- fill in all the indexes registered earlier
|
||||
*/
|
||||
/*
|
||||
这个函数用于在引导过程中构建索引。它通过遍历t_thrd.bootstrap_cxt.ILHead链表中的每个索引来逐个构建索引。
|
||||
循环的迭代条件是t_thrd.bootstrap_cxt.ILHead不为空,也就是说还有待构建的索引。循环的每次迭代,我们会定义两个Relation对象:heap和ind,分别用于表示堆表和索引表。
|
||||
引导过程中不需要考虑获取锁的问题,所以我们使用heap_open和index_open函数打开堆表和索引表。这两个函数接收两个参数:表的对象ID和锁的模式(NoLock表示不获取锁)。返回的Relation对象分别赋给heap和ind变量。
|
||||
然后,我们调用index_build函数来构建索引。这个函数接收多个参数,包括堆表、分区信息、索引表、并行标志、索引详细信息等。这些参数的值分别来自t_thrd.bootstrap_cxt.ILHead链表的当前节点。函数会使用这些参数来构建索引。
|
||||
索引构建完成后,我们使用index_close和heap_close函数关闭索引表和堆表。这些函数同样需要传入锁的模式参数(NoLock)。
|
||||
总之,这个函数用于在引导过程中构建索引。通过遍历t_thrd.bootstrap_cxt.ILHead链表中的每个索引,我们依次打开堆表和索引表,并调用index_build函数进行索引构建。最后,我们关闭索引表和堆表。
|
||||
*/
|
||||
void build_indices(void)
|
||||
{
|
||||
for (; t_thrd.bootstrap_cxt.ILHead != NULL; t_thrd.bootstrap_cxt.ILHead = t_thrd.bootstrap_cxt.ILHead->il_next) {
|
||||
|
|
|
|||
|
|
@ -49,13 +49,14 @@ int BBOX_GetSysDateTime(void)
|
|||
int iCommandFD = -1;
|
||||
int iReadSize = 0;
|
||||
|
||||
// 打开一个管道,并执行指定的日期时间命令
|
||||
BBOX_NOINTR(iCommandFD = sys_popen(BBOX_DATE_TIME_CMD, "r"));
|
||||
if (iCommandFD < 0) {
|
||||
bbox_print(PRINT_ERR, "sys_popen is failed, errno = %d.\n", errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* read the result of sys_read command */
|
||||
// 读取sys_read命令的结果
|
||||
BBOX_NOINTR(iReadSize = sys_read(iCommandFD, g_acDateTime, BBOX_TINE_LEN));
|
||||
if (iReadSize <= 0) {
|
||||
(void)sys_pclose(iCommandFD);
|
||||
|
|
@ -66,7 +67,7 @@ int BBOX_GetSysDateTime(void)
|
|||
(void)sys_pclose(iCommandFD);
|
||||
|
||||
if (iReadSize > 0) {
|
||||
g_acDateTime[iReadSize - 1] = '\0'; /* remove '\n' */
|
||||
g_acDateTime[iReadSize - 1] = '\0'; /* 移除'\n'字符 */
|
||||
}
|
||||
|
||||
bbox_print(PRINT_LOG, "Get system time %s.\n", g_acDateTime);
|
||||
|
|
@ -179,6 +180,7 @@ s32 BBOX_GetBBoxOldiestName(const char* pszPath, const char* pszName, void* pArg
|
|||
struct kernel_stat stCurrState = {0};
|
||||
char szFileName[BBOX_NAME_PATH_LEN];
|
||||
|
||||
// 检查参数
|
||||
pstArgs = (struct BBOX_ListDirParam*)pArgs;
|
||||
if (pstArgs == NULL) {
|
||||
bbox_print(PRINT_ERR, "Invalid argument pstArgs\n");
|
||||
|
|
@ -188,35 +190,37 @@ s32 BBOX_GetBBoxOldiestName(const char* pszPath, const char* pszName, void* pArg
|
|||
pstOldiestState = (struct kernel_stat*)pstArgs->pArg1;
|
||||
pszOldName = (char*)pstArgs->pArg2;
|
||||
|
||||
/* ignore path "." and ".." */
|
||||
// 忽略路径"."和".."
|
||||
if ((0 == bbox_strcmp(pszName, ".")) || (0 == bbox_strcmp(pszName, ".."))) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/* ignore the file which not belong to bbox */
|
||||
// 忽略不属于bbox的文件
|
||||
if ((0 == bbox_strstr(pszName, BBOX_SNAP_FILE_ADD_NAME ".lz4")) &&
|
||||
(0 == bbox_strstr(pszName, BBOX_CORE_FILE_ADD_NAME ".lz4"))) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/* ignore the file which not created by this process. */
|
||||
// 忽略不是由该进程创建的文件
|
||||
if (bbox_strstr(pszName, progname) == 0) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
// 拼接文件路径
|
||||
if (bbox_snprintf(szFileName, sizeof(szFileName), "%s/%s", pszPath, pszName) <= 0) {
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
// 获取文件信息
|
||||
if (sys_stat(szFileName, &stCurrState) < 0) {
|
||||
bbox_print(PRINT_ERR, "Get stat of '%s' failed, errno = %d\n", szFileName, errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* compare and judge if it is the oldiest time */
|
||||
// 比较并判断是否为最早创建的文件
|
||||
if (stCurrState.st_mtime_ < pstOldiestState->st_mtime_) {
|
||||
/* record the oldiest file information */
|
||||
// 记录最早的文件信息
|
||||
*pstOldiestState = stCurrState;
|
||||
if (bbox_snprintf(pszOldName, BBOX_NAME_PATH_LEN, "%s/%s", pszPath, pszName) <= 0) {
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
|
||||
|
|
@ -349,42 +353,48 @@ void BBOX_RemoveTempBBoxFile(void)
|
|||
*/
|
||||
void BBOX_FinishDumpFile(void* args)
|
||||
{
|
||||
// 声明所需的变量
|
||||
char* pszNewName = NULL;
|
||||
char* pszOldName = NULL;
|
||||
struct kernel_timeval stProgramCoreDumpTime = {0};
|
||||
struct BBOX_ListDirParam* pstArgs = (struct BBOX_ListDirParam*)args;
|
||||
|
||||
// 检查参数是否为NULL
|
||||
if (args == NULL) {
|
||||
bbox_print(PRINT_ERR, "BBOX_FinishDumpFile args is null.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取程序核心转储完成的时间
|
||||
sys_gettimeofday(&stProgramCoreDumpTime, NULL);
|
||||
|
||||
// 将程序核心转储完成的时间赋值给全局变量
|
||||
g_iCoreDumpEndTime = stProgramCoreDumpTime.tv_sec;
|
||||
bbox_print(PRINT_TIP, "coredump End at %ld\n", stProgramCoreDumpTime.tv_sec);
|
||||
|
||||
// 打印程序核心转储所用的时间
|
||||
bbox_print(PRINT_TIP, "coredump used time: %ld sec\n", g_iCoreDumpEndTime - g_iCoreDumpBeginTime);
|
||||
|
||||
/* remove oldiest file */
|
||||
// 移除最旧的文件
|
||||
BBOX_RemoveOldBBoxFile();
|
||||
|
||||
// 获取新文件名和旧文件名
|
||||
pszNewName = (char*)pstArgs->pArg1;
|
||||
pszOldName = (char*)pstArgs->pArg2;
|
||||
|
||||
/* change file mode to 0600 */
|
||||
// 将旧文件的访问权限设置为0600
|
||||
if (sys_chmod(pszOldName, 0600)) {
|
||||
bbox_print(PRINT_ERR, "set %s mode to 0600 failed, errno = %d\n", pszOldName, errno);
|
||||
}
|
||||
|
||||
/* rename file */
|
||||
// 重命名文件
|
||||
if (pszNewName != NULL && pszOldName != NULL) {
|
||||
if (sys_rename(pszOldName, pszNewName) < 0) {
|
||||
bbox_print(PRINT_ERR, "rename file %s to %s failed, errno = %d.\n", pszOldName, pszNewName, errno);
|
||||
}
|
||||
}
|
||||
|
||||
/* remove temp bbox file. */
|
||||
// 移除临时核心转储文件
|
||||
BBOX_RemoveTempBBoxFile();
|
||||
}
|
||||
|
||||
|
|
@ -403,19 +413,22 @@ s32 BBOX_CreateCoredump(char* file_name)
|
|||
|
||||
bbox_initlog(0);
|
||||
|
||||
// 打印日志头
|
||||
bbox_print(PRINT_TIP, "\nBBOX LOG\n-------------------------------\n");
|
||||
|
||||
// 获取系统当前时间
|
||||
iRet = BBOX_GetSysDateTime();
|
||||
if (iRet != RET_OK) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
// 创建核心文件保存路径
|
||||
if (bbox_mkdir(g_szBboxCorePath) < 0) {
|
||||
bbox_print(PRINT_ERR, "bbox_mkdir is failed, errno = %d.\n", errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* if file_name is NULL, create it using default name. */
|
||||
// 若file_name为NULL,则使用默认名称创建核心文件
|
||||
if (file_name == NULL) {
|
||||
if (BBOX_GetDefaultCoreName(szFileName, BBOX_NAME_PATH_LEN, BBOX_CORE_FILE_ADD_NAME) == RET_OK) {
|
||||
file_name = szFileName;
|
||||
|
|
@ -425,8 +438,10 @@ s32 BBOX_CreateCoredump(char* file_name)
|
|||
}
|
||||
}
|
||||
|
||||
// 打印核心文件路径
|
||||
bbox_print(PRINT_TIP, "core file path is %s\n", file_name);
|
||||
|
||||
// 获取临时核心文件名
|
||||
if (BBOX_GetTmpCoreName(szTmpName, BBOX_NAME_PATH_LEN) == RET_OK) {
|
||||
file_tmp = szTmpName;
|
||||
} else {
|
||||
|
|
@ -434,6 +449,7 @@ s32 BBOX_CreateCoredump(char* file_name)
|
|||
return RET_ERR;
|
||||
}
|
||||
|
||||
// 设置参数并调用相关函数
|
||||
stArgs.pArg1 = file_name;
|
||||
stArgs.pArg2 = file_tmp;
|
||||
|
||||
|
|
|
|||
|
|
@ -52,59 +52,59 @@ char g_acBboxStrTabInfo[BBOX_SH_STR_TAB_SIZE]; /* record string symbol tab
|
|||
* return : iGetChar - current character of the file being read
|
||||
* RET_ERR - failed
|
||||
*/
|
||||
|
||||
static int BBOX_SkipDeviceAndNodeField(struct BBOX_READ_FILE_IO* pstReadIO)
|
||||
{
|
||||
int iCount = -1;
|
||||
int iGetChar = -1;
|
||||
|
||||
if (NULL == pstReadIO) {
|
||||
// 检查参数的有效性
|
||||
if (NULL == pstReadIO) {
|
||||
bbox_print(PRINT_ERR, "BBOX_SkipDeviceAndNodeField参数无效:pstReadIO为NULL。\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
bbox_print(PRINT_ERR, "BBOX_SkipDeviceAndNodeField parameters is invalid: pstReadIO is NULL.\n");
|
||||
// 从文件中获取一个字符
|
||||
iGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
if (RET_ERR == iGetChar) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败,iGetChar= %d。\n", iGetChar);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
iGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
if (RET_ERR == iGetChar) {
|
||||
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, iGetChar= %d.\n", iGetChar);
|
||||
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
for (iCount = 0; iCount < DEVICE_AND_NODE_FIELD_NUM; iCount++) {
|
||||
while (iGetChar == ' ') {
|
||||
iGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
if (RET_ERR == iGetChar) {
|
||||
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, iGetChar= %d.\n", iGetChar);
|
||||
|
||||
return RET_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
while (iGetChar != ' ' && iGetChar != '\n') {
|
||||
if (RET_ERR == iGetChar) {
|
||||
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, iGetChar= %d.\n", iGetChar);
|
||||
|
||||
return RET_ERR;
|
||||
}
|
||||
iGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
}
|
||||
|
||||
while (iGetChar == ' ') {
|
||||
iGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
if (RET_ERR == iGetChar) {
|
||||
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, iGetChar= %d.\n", iGetChar);
|
||||
|
||||
return RET_ERR;
|
||||
}
|
||||
// 进入循环,跳过设备和节点字段
|
||||
for (iCount = 0; iCount < DEVICE_AND_NODE_FIELD_NUM; iCount++) {
|
||||
// 跳过空格字符
|
||||
while (iGetChar == ' ') {
|
||||
// 继续从文件中获取下一个字符
|
||||
iGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
if (RET_ERR == iGetChar) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败,iGetChar= %d。\n", iGetChar);
|
||||
return RET_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
return iGetChar;
|
||||
// 跳过非空格和换行符的字符
|
||||
while (iGetChar != ' ' && iGetChar != '\n') {
|
||||
if (RET_ERR == iGetChar) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败,iGetChar= %d。\n", iGetChar);
|
||||
return RET_ERR;
|
||||
}
|
||||
// 继续从文件中获取下一个字符
|
||||
iGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
}
|
||||
|
||||
// 跳过空格字符
|
||||
while (iGetChar == ' ') {
|
||||
// 继续从文件中获取下一个字符
|
||||
iGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
if (RET_ERR == iGetChar) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败,iGetChar= %d。\n", iGetChar);
|
||||
return RET_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iGetChar; // 返回读取的下一个字符
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -155,79 +155,82 @@ static int BBOX_SetMappingDeviceFlag(
|
|||
return RET_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* set whether the mapping is labeled as PF_VDSO, means that, whether or not it's a VDSO mapping.
|
||||
* in : int *piGetChar - pointer to the character read
|
||||
* struct BBOX_READ_FILE_IO *pstReadIO - pointer to struct of file read
|
||||
* struct BBOX_VM_MAPS *pstVmMappingSegment - pointer to discription of mapping segment structure.
|
||||
* return RET_OK or RET_ERR
|
||||
*/
|
||||
static int BBOX_SetMappingVDSOFlag(
|
||||
int* piGetChar, struct BBOX_READ_FILE_IO* pstReadIO, struct BBOX_VM_MAPS* pstSegmentMapping)
|
||||
/*
|
||||
这段代码是一个名为BBOX_SetMappingVDSOFlag的静态函数。
|
||||
该函数用于设置映射的VDSO标志以及VVAR标志。
|
||||
参数:
|
||||
piGetChar: 指向整型变量的指针,用于获取从文件中读取的字符
|
||||
pstReadIO: 一个指向BBOX_READ_FILE_IO结构的指针,用于读取文件
|
||||
pstSegmentMapping: 一个指向BBOX_VM_MAPS结构的指针,表示虚拟内存映射段的信息
|
||||
返回值:
|
||||
成功:返回RET_OK
|
||||
失败:返回RET_ERR */
|
||||
static int BBOX_SetMappingVDSOFlag(int* piGetChar, struct BBOX_READ_FILE_IO* pstReadIO, struct BBOX_VM_MAPS* pstSegmentMapping)
|
||||
{
|
||||
int iIsMappingVdsoFlag = BBOX_FALSE;
|
||||
int iIsMappingVvarFlag = BBOX_TRUE;
|
||||
const char* pszVdso = VDSO_NAME_STRING;
|
||||
const char* pszVvar = VVAR_NAME_STRING;
|
||||
|
||||
if (NULL == piGetChar || NULL == pstReadIO || NULL == pstSegmentMapping) {
|
||||
|
||||
bbox_print(PRINT_ERR,
|
||||
"BBOX_FillMappingFlagsAndOffset parameters is invalid: piGetChar," \
|
||||
"pstReadIO or pstSegmentMapping is NULL.\n");
|
||||
int iIsMappingVdsoFlag = BBOX_FALSE; // 表示是否映射了VDSO的标志,初始为假
|
||||
int iIsMappingVvarFlag = BBOX_TRUE; // 表示是否映射了VVAR的标志,初始为真
|
||||
const char* pszVdso = VDSO_NAME_STRING; // VDSO名称字符串
|
||||
const char* pszVvar = VVAR_NAME_STRING; // VVAR名称字符串
|
||||
// 检查参数的有效性
|
||||
if (NULL == piGetChar || NULL == pstReadIO || NULL == pstSegmentMapping) {
|
||||
bbox_print(PRINT_ERR,
|
||||
"BBOX_SetMappingVDSOFlag参数无效:piGetChar,pstReadIO或pstSegmentMapping为NULL。\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
// 当VDSO名称字符串和从文件中获取的字符相等时,进行以下操作
|
||||
while (*pszVdso && *piGetChar == *pszVdso) {
|
||||
// 如果映射了VVAR并且从文件中获取的字符与VVAR名称字符串相等
|
||||
if (iIsMappingVvarFlag == BBOX_TRUE) {
|
||||
iIsMappingVvarFlag = (*piGetChar == *pszVvar) ? BBOX_TRUE : BBOX_FALSE;
|
||||
pszVvar++;
|
||||
}
|
||||
|
||||
// 继续从文件中获取下一个字符
|
||||
*piGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
if (RET_ERR == *piGetChar) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败,*piGetChar= %d。\n", *piGetChar);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
while (*pszVdso && *piGetChar == *pszVdso) {
|
||||
if (iIsMappingVvarFlag == BBOX_TRUE) {
|
||||
iIsMappingVvarFlag = (*piGetChar == *pszVvar) ? BBOX_TRUE : BBOX_FALSE;
|
||||
pszVvar++;
|
||||
}
|
||||
pszVdso++;
|
||||
}
|
||||
|
||||
// 如果VDSO名称字符串为空,且从文件中获取的字符为换行符、空格或空字符
|
||||
if (*pszVdso == '\0' && (*piGetChar == '\n' || *piGetChar == ' ' || *piGetChar == '\0')) {
|
||||
pstSegmentMapping->iFlags |= PF_VDSO; // 设置VDSO标志
|
||||
|
||||
bbox_print(PRINT_DBG,
|
||||
"获取VDSO的起始地址 = %zu,结束地址 = %zu。\n",
|
||||
pstSegmentMapping->uiStartAddress,
|
||||
pstSegmentMapping->uiEndAddress);
|
||||
}
|
||||
|
||||
// 如果映射了VVAR,并且从文件中获取的字符与VVAR名称字符串相等时,进行以下操作
|
||||
if (iIsMappingVvarFlag == BBOX_TRUE) {
|
||||
while (*pszVdso && *piGetChar == *pszVvar) {
|
||||
// 继续从文件中获取下一个字符
|
||||
*piGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
if (RET_ERR == *piGetChar) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, *piGetChar= %d.\n", *piGetChar);
|
||||
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile调用失败,*piGetChar= %d。\n", *piGetChar);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
pszVdso++;
|
||||
pszVvar++;
|
||||
}
|
||||
|
||||
iIsMappingVdsoFlag = (*pszVdso == '\0' && (*piGetChar == '\n' || *piGetChar == ' ' || *piGetChar == '\0'));
|
||||
if (BBOX_TRUE == iIsMappingVdsoFlag) {
|
||||
pstSegmentMapping->iFlags |= PF_VDSO; /* set VDSO flag. */
|
||||
// 如果VVAR名称字符串为空,且从文件中获取的字符为换行符、空格或空字符
|
||||
if (*pszVvar == '\0' && (*piGetChar == '\n' || *piGetChar == ' ' || *piGetChar == '\0')) {
|
||||
pstSegmentMapping->iFlags |= PF_VVAR; // 设置VVAR标志
|
||||
|
||||
bbox_print(PRINT_DBG,
|
||||
" Get VDSO StartAddr = %zu, EndAddr = %zu.\n",
|
||||
pstSegmentMapping->uiStartAddress,
|
||||
pstSegmentMapping->uiEndAddress);
|
||||
"获取VVAR的起始地址 = %zu,结束地址 = %zu。\n",
|
||||
pstSegmentMapping->uiStartAddress, pstSegmentMapping->uiEndAddress);
|
||||
}
|
||||
|
||||
if (iIsMappingVvarFlag == BBOX_TRUE) {
|
||||
while (*pszVdso && *piGetChar == *pszVvar) {
|
||||
*piGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
if (RET_ERR == *piGetChar) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile is failed, *piGetChar= %d.\n", *piGetChar);
|
||||
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
pszVvar++;
|
||||
}
|
||||
|
||||
if (*pszVvar == '\0' && (*piGetChar == '\n' || *piGetChar == ' ' || *piGetChar == '\0')) {
|
||||
pstSegmentMapping->iFlags |= PF_VVAR; /* set VVAR flag */
|
||||
|
||||
bbox_print(PRINT_DBG,
|
||||
" Get VVAR StartAddr = %zu, EndAddr = %zu.\n",
|
||||
pstSegmentMapping->uiStartAddress, pstSegmentMapping->uiEndAddress);
|
||||
}
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
/*
|
||||
* check if the file is a dynamic library file.
|
||||
* in : char* pszFilePath - path
|
||||
|
|
@ -344,6 +347,28 @@ static int BBOX_SettingFileFlags(
|
|||
* return : int iGetChar - current character of file reading
|
||||
* RET_ERR - read failed
|
||||
*/
|
||||
/*
|
||||
这个函数名为BBOX_FillMappingFlagsAndOffset。它的作用是填充虚拟内存映射段的标志位和偏移量。
|
||||
|
||||
参数:
|
||||
- pstReadIO: 指向BBOX_READ_FILE_IO结构的指针,用于读取文件
|
||||
- pstSegmentMapping: 指向BBOX_VM_MAPS结构的指针,表示虚拟内存映射段的信息
|
||||
|
||||
返回值:
|
||||
- 成功: 返回从文件中获取的字符
|
||||
- 失败: 返回RET_ERR
|
||||
|
||||
1. 检查参数的有效性,如果传入的指针为空,则打印错误消息并返回RET_ERR。
|
||||
2. 通过循环读取标志位,并在读取完地址之后将'-'设置为0。读取的字符通过位运算合并到pstSegmentMapping->iFlags中。
|
||||
3. 对pstSegmentMapping->iFlags进行处理,将其右移一位并与PF_MASK进行与运算。
|
||||
4. 通过BBOX_StringSwitchInt函数读取偏移量,并将其保存到pstSegmentMapping->uiOffset中。
|
||||
5. 跳过描述设备和节点的字段。
|
||||
6. 判断下一个字段是否以'['开头或者是结束,如果是,则将其标记为匿名设备。
|
||||
7. 如果是匿名设备,设置PF_ANONYMOUS标志,并调用BBOX_SetMappingVDSOFlag函数判断是否是VDSO段,如果是则标记为VDSO并返回获取的字符。
|
||||
8. 如果不是匿名设备,则调用BBOX_SetMappingDeviceFlag函数判断是否是描述某个设备的字段,如果是则设置设备标志。
|
||||
9. 判断是否存在映射文件,如果存在,则调用BBOX_SettingFileFlags函数设置文件标志。
|
||||
10. 返回获取的字符。
|
||||
*/
|
||||
static int BBOX_FillMappingFlagsAndOffset(struct BBOX_READ_FILE_IO* pstReadIO, struct BBOX_VM_MAPS* pstSegmentMapping)
|
||||
{
|
||||
int iRessult = 0;
|
||||
|
|
@ -510,6 +535,28 @@ static char BBOX_FillMappingAddress(struct BBOX_READ_FILE_IO* pstReadIO, struct
|
|||
* struct BBOX_WRITE_FDS *pstWriteFds : segment to be written into core file
|
||||
* return RET_OK if success else RET_ERR.
|
||||
*/
|
||||
/*
|
||||
这个函数名为BBOX_VmExecludeBlackList。它的作用是根据黑名单排除虚拟内存映射段。
|
||||
|
||||
参数:
|
||||
- pstVmMappingSegment: 指向BBOX_VM_MAPS结构的指针,表示虚拟内存映射段的信息
|
||||
|
||||
返回值:
|
||||
- 成功: 返回RET_OK
|
||||
|
||||
1. 定义一些变量并初始化。
|
||||
2. 调用_BBOX_FindAddrInBlackList函数在黑名单中查找起始地址和结束地址。
|
||||
3. 如果找到了匹配的黑名单节点,则获取黑名单节点的起始地址和结束地址。
|
||||
4. 获取下一个虚拟内存映射段的指针。
|
||||
5. 将下一个虚拟内存映射段的标志位设置为当前映射段的标志位。
|
||||
6. 如果起始地址小于黑名单的起始地址,则更新当前映射段的写入大小、结束地址、起始地址和删除标志。
|
||||
7. 否则,将当前映射段的删除标志设置为真。
|
||||
8. 如果黑名单的结束地址小于结束地址,则更新下一个虚拟内存映射段的写入大小、起始地址、结束地址和删除标志。
|
||||
9. 否则,将下一个虚拟内存映射段的删除标志设置为真。
|
||||
10. 如果没有找到匹配的黑名单节点,则什么都不做。
|
||||
11. 打印调试消息,并返回RET_OK。
|
||||
|
||||
*/
|
||||
static int BBOX_VmExecludeBlackList(struct BBOX_VM_MAPS *pstVmMappingSegment)
|
||||
{
|
||||
void *pStartAddress = (void *)(uintptr_t)pstVmMappingSegment->uiStartAddress;
|
||||
|
|
@ -2742,6 +2789,29 @@ static int BBOX_CloseCoreFile(struct BBOX_WRITE_FDS* pstFileWriteFd)
|
|||
* va_list ap - Multiparameter list
|
||||
* return RET_OK or RET_ERR
|
||||
*/
|
||||
/*
|
||||
该函数的功能是生成一个包含各种信息的core文件。它的参数包括回调函数指针、句柄、线程数量、进程ID数组以及可变参数列表。
|
||||
|
||||
该函数首先检查参数的有效性,如果参数无效,返回RET_ERR。
|
||||
|
||||
然后使用原子变量锁进入一个循环,等待直到可以将锁变量加1。在循环内部,打印一个调试信息,并让函数休眠1秒。
|
||||
|
||||
退出循环后,声明一个大小为线程数量的BBOX_THREAD_NOTE_INFO结构体数组,并从可变参数列表中获取堆栈帧。如果堆栈帧为NULL,则打印错误信息并返回RET_ERR。
|
||||
|
||||
接下来,初始化几个结构体和变量,包括BBOX_VM_VDSO、BBOX_ELF_NOTE_INFO和BBOX_WRITE_FDS。设置主进程ID和线程信息数。
|
||||
|
||||
然后调用BBOX_GetVmMapsNum函数获取/proc/self/maps文件的行数,表示段的数量。如果数量小于等于0,则打印错误信息并返回RET_ERR。
|
||||
|
||||
接下来,声明一个大小为段数量加上一个常量值的BBOX_VM_MAPS结构体数组,并初始化该数组。然后调用BBOX_FillAllInfoOfCoreFile函数来填充生成core文件所需的所有信息。如果返回值不是RET_OK,则打印错误信息并返回RET_ERR。
|
||||
|
||||
之后,调用回调函数通知线程模块数据获取已完成。获取core文件名并检查其有效性。如果无效,则打印错误信息并返回RET_ERR。
|
||||
|
||||
接下来,调用BBOX_OpenCoreFile函数创建core文件。如果返回值不是RET_OK,则打印错误信息并跳转到ERR标签。
|
||||
|
||||
在ERR标签处,减少原子变量锁的值,并检查是否需要调用BBOX_CloseCoreFile函数。如果需要,如果返回值不是RET_OK,则打印错误信息。
|
||||
|
||||
最后,返回BBOX_CloseCoreFile函数的结果,该结果是函数的返回值或RET_ERR,具体取决于函数的返回值。
|
||||
*/
|
||||
int BBOX_DoDumpElfCore(BBOX_GetAllThreadDone pDone, void* pDoneHandle, int iNumThreads, pid_t* ptPids, va_list ap)
|
||||
{
|
||||
int iSegmentNum = -1;
|
||||
|
|
|
|||
|
|
@ -44,23 +44,41 @@ static int g_iPosBlackList = 0;
|
|||
/* array store for black list */
|
||||
static BBOX_BLACKLIST_STRU g_stBlackList[BBOX_BLACK_LIST_COUNT_MAX];
|
||||
|
||||
/*
|
||||
* Determines whether the byte order of the local machine is large or small
|
||||
* return : ELFDATA2LSB - large
|
||||
* : ELFDATA2MSB - small
|
||||
*/
|
||||
/*
|
||||
function name: BBOX_DetermineMsb
|
||||
description: The function should judge the mode that PC uses to store data is Big-endian/Little-endian.
|
||||
arguments: void
|
||||
return value: An integer that indicates the mode is Big-endian/Little-endian,
|
||||
if it is ELFDATA2LSB, the mode is Little-endian,
|
||||
if it is ELFDATA2MSB, the mode is Big-endian.
|
||||
note锛歍he way that this function judge the mode that PC uses to store data is through a union variable unProbe,
|
||||
at first we give its first member variable sShortInt a value BBOX_MSB_LSB_INT of type short, then its second
|
||||
member variable cSplit[sizeof(short)] equaling to cSplit[2] would have the equal value of the first. Finally we
|
||||
just need to compare BBOX_LITTER_BITS and BBOX_HIGH_BITS, namely the low byte and high byte of
|
||||
BBOX_MSB_LSB_INT, with unProbe.cSplit[0] and unProbe.cSplit[1], if they are correspondingly equal, the mode is
|
||||
Little-endian, else is the Big-endian.
|
||||
date: 2022/8/2
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
// 用于确定系统的字节序的函数
|
||||
int BBOX_DetermineMsb(void)
|
||||
{
|
||||
// 定义一个联合体,用于存储一个short整数并将其拆分为单个字节
|
||||
union INT_PROBE {
|
||||
short sShortInt;
|
||||
char cSplit[sizeof(short)];
|
||||
short sShortInt; // 短整数
|
||||
char cSplit[sizeof(short)]; // 字符数组(字节数组),用于拆分整数
|
||||
} unProbe;
|
||||
|
||||
// 将联合体中的整数值设置为已知值
|
||||
unProbe.sShortInt = BBOX_MSB_LSB_INT;
|
||||
|
||||
// 检查short整数的第一个字节是否与MSB的预期值匹配
|
||||
// 并且检查第二个字节是否与LSB的预期值匹配
|
||||
if ((BBOX_LITTER_BITS == unProbe.cSplit[0]) && (BBOX_HIGH_BITS == unProbe.cSplit[1])) {
|
||||
// 如果字节序为LSB,则返回LSB的值
|
||||
return ELFDATA2LSB;
|
||||
} else {
|
||||
// 如果字节序为MSB,则返回MSB的值
|
||||
return ELFDATA2MSB;
|
||||
}
|
||||
}
|
||||
|
|
@ -100,25 +118,31 @@ int BBOX_StringToTime(const char* pSwitch, struct BBOX_ELF_TIMEVAL* pstElfTimeva
|
|||
* return : the character read in file - success
|
||||
* RET_ERR - failed
|
||||
*/
|
||||
// 从文件中获取一个字符的函数
|
||||
int BBOX_GetCharFromFile(struct BBOX_READ_FILE_IO* pstIO)
|
||||
{
|
||||
ssize_t iReadSize = -1;
|
||||
|
||||
// 检查pstIO是否为NULL
|
||||
if (NULL == pstIO) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile parameters is invalid: pstIO is NULL.\n");
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCharFromFile参数无效:pstIO为NULL。\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
unsigned char* pTempIO = pstIO->pData;
|
||||
|
||||
// 检查缓冲区是否为空
|
||||
if (pTempIO == pstIO->pEnd) {
|
||||
/* read character from file when the buffer is empty, and push it into buffer */
|
||||
/* 当缓冲区为空时,从文件中读取字符并将其放入缓冲区 */
|
||||
BBOX_NOINTR(iReadSize = sys_read(pstIO->iFd, pstIO->szBuff, sizeof(pstIO->szBuff)));
|
||||
|
||||
// 检查读取的大小
|
||||
if (iReadSize <= 0) {
|
||||
if (0 == iReadSize) {
|
||||
errno = 0;
|
||||
errno = 0; // 清除错误标记
|
||||
}
|
||||
|
||||
return RET_ERR;
|
||||
return RET_ERR; // 读取出错
|
||||
}
|
||||
|
||||
pTempIO = &(pstIO->szBuff[0]);
|
||||
|
|
@ -137,52 +161,57 @@ int BBOX_GetCharFromFile(struct BBOX_READ_FILE_IO* pstIO)
|
|||
* return : the result num - success
|
||||
* RET_ERR - failed
|
||||
*/
|
||||
// 字符串转换为整数的函数, 从文件中读取字符并将其转换为整数
|
||||
int BBOX_StringSwitchInt(struct BBOX_READ_FILE_IO* pstIO, size_t* pAddress)
|
||||
{
|
||||
int iMappingTextChar = 0;
|
||||
|
||||
// 检查pstIO和pAddress是否为NULL
|
||||
if (NULL == pstIO || NULL == pAddress) {
|
||||
bbox_print(
|
||||
PRINT_ERR, "BBOX_StringSwitchInt parameters is invalid: pstIO or pAddress is NULL.\n");
|
||||
PRINT_ERR, "BBOX_StringSwitchInt参数无效:pstIO或pAddress为NULL。\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
*pAddress = 0;
|
||||
iMappingTextChar = BBOX_GetCharFromFile(pstIO);
|
||||
while (
|
||||
(iMappingTextChar >= '0' && iMappingTextChar <= '9') || (iMappingTextChar >= 'a' && iMappingTextChar <= 'f')) {
|
||||
*pAddress = 0; // 初始化pAddress为0
|
||||
iMappingTextChar = BBOX_GetCharFromFile(pstIO); // 从文件中获取一个字符
|
||||
|
||||
/* left shift the variable, and add the num converted from character at the end. */
|
||||
*pAddress =
|
||||
(*pAddress << ONE_HEXA_DECIMAL_BITS) |
|
||||
// 循环直到遇到非数字字符和非小写字母字符
|
||||
while ((iMappingTextChar >= '0' && iMappingTextChar <= '9') || (iMappingTextChar >= 'a' && iMappingTextChar <= 'f')) {
|
||||
|
||||
/* 将变量左移,并在末尾添加由字符转换而来的数字 */
|
||||
*pAddress = (*pAddress << ONE_HEXA_DECIMAL_BITS) |
|
||||
(unsigned int)(iMappingTextChar < 'A' ? iMappingTextChar - '0'
|
||||
: ((unsigned int)iMappingTextChar & 0xF) + ASC2_CHAR_GREATER_NUM);
|
||||
iMappingTextChar = BBOX_GetCharFromFile(pstIO); /* read next character */
|
||||
: ((unsigned int)iMappingTextChar & 0xF) + ASC2_CHAR_GREATER_NUM);
|
||||
|
||||
iMappingTextChar = BBOX_GetCharFromFile(pstIO); // 读取下一个字符
|
||||
}
|
||||
|
||||
return iMappingTextChar;
|
||||
return iMappingTextChar; // 返回读取的字符
|
||||
}
|
||||
|
||||
/*
|
||||
* when read file /proc/self/maps, ignore unusefull information and skip to the end of line
|
||||
* after we have geting all necessary information.
|
||||
* return : count of character store into buffer - success
|
||||
* RET_ERR - failed
|
||||
* 当读取文件/proc/self/maps时,忽略无用信息并跳过到行尾,在获得所有必要信息之后。
|
||||
* 返回:存储在缓冲区中的字符数 - 成功
|
||||
* RET_ERR - 失败
|
||||
*/
|
||||
int BBOX_SkipToLineEnd(struct BBOX_READ_FILE_IO* pstReadIO)
|
||||
{
|
||||
int iGetChar = -1;
|
||||
|
||||
// 检查pstReadIO是否为NULL
|
||||
if (NULL == pstReadIO) {
|
||||
bbox_print(PRINT_ERR, "BBOX_SkipToLineEnd parameters is invalid: pstReadIO is NULL.\n");
|
||||
bbox_print(PRINT_ERR, "BBOX_SkipToLineEnd参数无效:pstReadIO为NULL。\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
do {
|
||||
/* reads characters until the newline character */
|
||||
/* 读取字符直到换行符 */
|
||||
iGetChar = BBOX_GetCharFromFile(pstReadIO);
|
||||
|
||||
// 检查读取字符是否失败
|
||||
if (RET_ERR == iGetChar) {
|
||||
bbox_print(PRINT_ERR, "BBOX_SkipToLineEnd is failed, iGetChar= %d.\n", iGetChar);
|
||||
bbox_print(PRINT_ERR, "BBOX_SkipToLineEnd失败,iGetChar = %d。\n", iGetChar);
|
||||
return RET_ERR;
|
||||
}
|
||||
} while (iGetChar != '\n');
|
||||
|
|
@ -191,18 +220,17 @@ int BBOX_SkipToLineEnd(struct BBOX_READ_FILE_IO* pstReadIO)
|
|||
}
|
||||
|
||||
/*
|
||||
* judge whether the range between *pStartAddress* and *pEndAddress* is in black list or not.
|
||||
* If found, return the blacklist item which cover it, else return NULL.
|
||||
* 判断地址范围是否在黑名单中,如果是,则返回覆盖它的黑名单项,否则返回NULL。
|
||||
*
|
||||
* NOTE: this function is a thread-unsafe function since it works as an iterator.
|
||||
* 注意:该函数是一个线程不安全的函数,因为它作为迭代器使用。
|
||||
*/
|
||||
BBOX_BLACKLIST_STRU *_BBOX_FindAddrInBlackList(const void *pStartAddress, const void *pEndAddress)
|
||||
BBOX_BLACKLIST_STRU *_BBOX_FindAddrInBlackList(const void* pStartAddress, const void* pEndAddress)
|
||||
{
|
||||
int i = 0;
|
||||
int iPerformance = 0;
|
||||
size_t uiPageSize = sys_sysconf(_SC_PAGESIZE);
|
||||
size_t uiPageSize = sys_sysconf(_SC_PAGESIZE);
|
||||
|
||||
/* if the cursor reachs the end of blacklist, start a new trip. */
|
||||
/* 如果游标达到黑名单的末尾,则开始新的遍历。 */
|
||||
if (g_iPosBlackList >= g_iNumBlackList) {
|
||||
g_iPosBlackList = 0;
|
||||
}
|
||||
|
|
@ -211,41 +239,41 @@ BBOX_BLACKLIST_STRU *_BBOX_FindAddrInBlackList(const void *pStartAddress, const
|
|||
iPerformance++;
|
||||
|
||||
/*
|
||||
* if the endAddress of segemnt is less than the startAddress of this item, it means there is
|
||||
* no cross with the rest blacklist items since blacklist items are in increasing order.
|
||||
* 如果段的结束地址小于此项的开始地址,
|
||||
* 这意味着不会与剩余的黑名单项相交,因为黑名单项是按递增顺序排列的。
|
||||
*/
|
||||
if (pEndAddress <= g_stBlackList[i].pBlackStartAddr) {
|
||||
bbox_print(PRINT_DBG, "\nFIND BL BY %d TIMES, POS = %d.\n\n", iPerformance, g_iPosBlackList);
|
||||
bbox_print(PRINT_DBG, "not find black list in segment.\n");
|
||||
bbox_print(PRINT_DBG, "\n通过%d次查找,POS = %d找到黑名单。\n\n", iPerformance, g_iPosBlackList);
|
||||
bbox_print(PRINT_DBG, "在段中未找到黑名单。\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pStartAddress <= g_stBlackList[i].pBlackStartAddr &&
|
||||
g_stBlackList[i].pBlackStartAddr < pEndAddress) {
|
||||
g_iPosBlackList = i;
|
||||
bbox_print(PRINT_DBG, "\nFIND BL BY %d TIMES, POS = %d.\n\n", iPerformance, g_iPosBlackList);
|
||||
bbox_print(PRINT_DBG, "find black list in segment.\n");
|
||||
bbox_print(PRINT_DBG, "\n通过%d次查找,POS = %d找到黑名单。\n\n", iPerformance, g_iPosBlackList);
|
||||
bbox_print(PRINT_DBG, "在段中找到黑名单。\n");
|
||||
return &(g_stBlackList[i]);
|
||||
}
|
||||
|
||||
if (pStartAddress < g_stBlackList[i].pBlackEndAddr &&
|
||||
g_stBlackList[i].pBlackEndAddr <= pEndAddress) {
|
||||
if (((uintptr_t)pEndAddress - (uintptr_t)(g_stBlackList[i].pBlackEndAddr)) < uiPageSize) {
|
||||
bbox_print(PRINT_DBG, "find black list in segment, but size < 4K, do not care return.\n");
|
||||
bbox_print(PRINT_DBG, "在段中找到黑名单,但大小小于4K,不用关心,返回NULL。\n");
|
||||
return NULL;
|
||||
} else {
|
||||
g_iPosBlackList = i;
|
||||
bbox_print(PRINT_DBG, "\nFIND BL BY %d TIMES, POS = %d.\n\n", iPerformance, g_iPosBlackList);
|
||||
bbox_print(PRINT_DBG, "find black list in segment.\n");
|
||||
bbox_print(PRINT_DBG, "\n通过%d次查找,POS = %d找到黑名单。\n\n", iPerformance, g_iPosBlackList);
|
||||
bbox_print(PRINT_DBG, "在段中找到黑名单。\n");
|
||||
return &(g_stBlackList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bbox_print(PRINT_DBG, "\nFIND BL BY %d TIMES, POS = %d.\n\n", iPerformance, g_iPosBlackList);
|
||||
bbox_print(PRINT_DBG, "not find black list in segment.\n");
|
||||
bbox_print(PRINT_DBG, "\n通过%d次查找,POS = %d未找到黑名单。\n\n", iPerformance, g_iPosBlackList);
|
||||
bbox_print(PRINT_DBG, "在段中未找到黑名单。\n");
|
||||
|
||||
/* no cross between this segment and blacklist items. */
|
||||
/* 此段与黑名单项之间无交叉。 */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -255,23 +283,25 @@ BBOX_BLACKLIST_STRU *_BBOX_FindAddrInBlackList(const void *pStartAddress, const
|
|||
* unsigned long long uiLen : memory size
|
||||
* return RET_OK if success else RET_ERR.
|
||||
*/
|
||||
/* 向黑名单列表添加地址 */
|
||||
int _BBOX_AddBlackListAddress(void* pAddress, unsigned long long uiLen)
|
||||
{
|
||||
unsigned int uiFound = 0;
|
||||
|
||||
// 如果地址为空或者长度小于最小限制,打印错误信息并返回错误码
|
||||
if (pAddress == NULL || uiLen < BBOX_BLACK_LIST_MIN_LEN) {
|
||||
bbox_print(PRINT_ERR, "parameter uiLen(%llu) is invaild.\n", uiLen);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* use atomic increment to control concurrency. */
|
||||
/* 使用原子增加操作来控制并发 */
|
||||
while (BBOX_AtomicIncReturn(&g_stLockBlackList) > 1) {
|
||||
BBOX_AtomicDec(&g_stLockBlackList);
|
||||
bbox_print(PRINT_DBG, "add blacklist addr is running, waiting.\n");
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
/* if too many blacklist items were added, return error while its upper limits reaches. */
|
||||
// 如果黑名单项目数量达到上限,打印错误信息并返回错误码
|
||||
if (g_iNumBlackList >= BBOX_BLACK_LIST_COUNT_MAX) {
|
||||
BBOX_AtomicDec(&g_stLockBlackList);
|
||||
bbox_print(PRINT_ERR, "blacklist addr total reach max, failed.\n");
|
||||
|
|
@ -279,11 +309,11 @@ int _BBOX_AddBlackListAddress(void* pAddress, unsigned long long uiLen)
|
|||
}
|
||||
|
||||
/*
|
||||
* suppose that address became bigger and bigger, move forward from blacklist's tail,
|
||||
* and find the proper postion to insert this address into the blacklist.
|
||||
* 假设地址越来越大,从黑名单末尾开始往前移动,
|
||||
* 找到适合将该地址插入到黑名单的位置
|
||||
*/
|
||||
for (int i = g_iNumBlackList - 1; i >= 0; i--) {
|
||||
/* if try to add the same address again, report error. */
|
||||
/* 如果试图再次添加相同的地址,报告错误 */
|
||||
if (g_stBlackList[i].pBlackStartAddr == pAddress) {
|
||||
BBOX_AtomicDec(&g_stLockBlackList);
|
||||
|
||||
|
|
@ -308,7 +338,7 @@ int _BBOX_AddBlackListAddress(void* pAddress, unsigned long long uiLen)
|
|||
}
|
||||
}
|
||||
|
||||
/* if no found, it means this address is smaller than all,put it in the head. */
|
||||
/* 如果没有找到,说明该地址比所有地址都小,将其置于首位 */
|
||||
if (uiFound == 0) {
|
||||
g_stBlackList[0].pBlackStartAddr = pAddress;
|
||||
g_stBlackList[0].uiLength = uiLen;
|
||||
|
|
@ -324,42 +354,43 @@ int _BBOX_AddBlackListAddress(void* pAddress, unsigned long long uiLen)
|
|||
}
|
||||
|
||||
/*
|
||||
* drop a blaclist item to dump it in core file.
|
||||
* void *pAddress : the head address of excluded memory
|
||||
* return RET_OK if success else RET_ERR.
|
||||
* 将黑名单中的项删除,并将其转储到核心文件中。
|
||||
* void *pAddress : 被排除内存的起始地址
|
||||
* return RET_OK 成功,否则返回 RET_ERR。
|
||||
*/
|
||||
int _BBOX_RmvBlackListAddress(void* pAddress)
|
||||
{
|
||||
unsigned int uiFound = 0;
|
||||
|
||||
// 如果地址为空,打印错误信息并返回错误码
|
||||
if (pAddress == NULL) {
|
||||
bbox_print(PRINT_ERR, "parameter pAddress is invaild.\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* use atomic increment to control concurrency. */
|
||||
/* 使用原子增加操作来控制并发 */
|
||||
while (BBOX_AtomicIncReturn(&g_stLockBlackList) > 1) {
|
||||
BBOX_AtomicDec(&g_stLockBlackList);
|
||||
bbox_print(PRINT_DBG, "remove blacklist addr is running, waiting.\n");
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
/* if blacklist is empty, return error. */
|
||||
// 如果黑名单为空,返回错误码
|
||||
if (g_iNumBlackList == 0) {
|
||||
BBOX_AtomicDec(&g_stLockBlackList);
|
||||
bbox_print(PRINT_ERR, "blacklist addr total is zero, failed.\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* find the specified address and drop it from blacklist. */
|
||||
// 找到指定的地址并从黑名单中删除
|
||||
for (int i = 0; i < g_iNumBlackList; i++) {
|
||||
if (pAddress == g_stBlackList[i].pBlackStartAddr) {
|
||||
uiFound = 1;
|
||||
}
|
||||
|
||||
/* if found, move subsequent items a step forward. */
|
||||
/* 如果找到,将后续项目向前移动一步 */
|
||||
if (uiFound == 1) {
|
||||
/* if it is the last, clear it and stop. */
|
||||
/* 如果是最后一个,清除并停止 */
|
||||
if (i == (g_iNumBlackList - 1)) {
|
||||
int rc = memset_s(&g_stBlackList[i], sizeof(g_stBlackList[0]), 0, sizeof(g_stBlackList[0]));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
|
|
@ -391,6 +422,8 @@ int _BBOX_RmvBlackListAddress(void* pAddress)
|
|||
* return : count of character store into buffer - success
|
||||
* RET_ERR - failed
|
||||
*/
|
||||
```c
|
||||
// 获取系统状态信息
|
||||
int BBOX_GetStatusInfo(char* pBuffer, unsigned int uiBufLen)
|
||||
{
|
||||
int iResult = 0;
|
||||
|
|
@ -398,15 +431,16 @@ int BBOX_GetStatusInfo(char* pBuffer, unsigned int uiBufLen)
|
|||
int iAllSize = 0;
|
||||
int iReadSize = 0;
|
||||
|
||||
// 检查参数是否有效
|
||||
if (NULL == pBuffer) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetStatusInfo parameters is invalid.\n");
|
||||
bbox_print(PRINT_ERR, "BBOX_GetStatusInfo参数无效。\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* information title */
|
||||
iResult = bbox_snprintf(pBuffer, uiBufLen, "\nSTATUS INFO\n--------------------------------------------\n");
|
||||
/* 信息标题 */
|
||||
iResult = bbox_snprintf(pBuffer, uiBufLen, "\n状态信息\n--------------------------------------------\n");
|
||||
if (iResult <= 0 || iResult > (int)uiBufLen) {
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf执行失败,errno = %d。\n", errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
|
|
@ -415,18 +449,18 @@ int BBOX_GetStatusInfo(char* pBuffer, unsigned int uiBufLen)
|
|||
uiBufLen -= iResult;
|
||||
iAllSize += iResult;
|
||||
|
||||
/* open /proc/self/status */
|
||||
/* 打开/proc/self/status */
|
||||
BBOX_NOINTR(iStatFD = sys_open(BBOX_SELF_STATUS_PATH, O_RDONLY, 0));
|
||||
if (iStatFD < 0) {
|
||||
bbox_print(PRINT_ERR, "sys_open is failed, errno = %d.\n", errno);
|
||||
bbox_print(PRINT_ERR, "sys_open执行失败,errno = %d。\n", errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* read /proc/self/status */
|
||||
/* 读取/proc/self/status */
|
||||
BBOX_NOINTR(iReadSize = sys_read(iStatFD, pBuffer, uiBufLen));
|
||||
if (iReadSize < 0) {
|
||||
(void)sys_close(iStatFD);
|
||||
bbox_print(PRINT_ERR, "sys_read is failed, errno = %d.\n", errno);
|
||||
bbox_print(PRINT_ERR, "sys_read执行失败,errno = %d。\n", errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
|
|
@ -437,11 +471,11 @@ int BBOX_GetStatusInfo(char* pBuffer, unsigned int uiBufLen)
|
|||
}
|
||||
|
||||
/*
|
||||
* get status information of cpu
|
||||
* in : char *pBuffer - buffer to store result
|
||||
* unsigned int uiBufLen - buffer size
|
||||
* return : count of character store into buffer - success
|
||||
* RET_ERR - failed
|
||||
* 获取CPU信息
|
||||
* 输入:char *pBuffer - 存储结果的缓冲区
|
||||
* unsigned int uiBufLen - 缓冲区大小
|
||||
* 返回值:存储到缓冲区的字符数 - 成功
|
||||
* RET_ERR - 失败
|
||||
*/
|
||||
int BBOX_GetCpuInfo(char* pBuffer, unsigned int uiBufLen)
|
||||
{
|
||||
|
|
@ -450,15 +484,16 @@ int BBOX_GetCpuInfo(char* pBuffer, unsigned int uiBufLen)
|
|||
int iAllSize = 0;
|
||||
int iReadSize = 0;
|
||||
|
||||
// 检查参数是否有效
|
||||
if (NULL == pBuffer) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCpuInfo parameters is invalid.\n");
|
||||
bbox_print(PRINT_ERR, "BBOX_GetCpuInfo参数无效。\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* information title */
|
||||
iResult = bbox_snprintf(pBuffer, uiBufLen, "\nCPU INFO\n--------------------------------------------\n");
|
||||
/* 信息标题 */
|
||||
iResult = bbox_snprintf(pBuffer, uiBufLen, "\nCPU信息\n--------------------------------------------\n");
|
||||
if (iResult <= 0 || iResult > (int)uiBufLen) {
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf执行失败,errno = %d。\n", errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
|
|
@ -467,18 +502,18 @@ int BBOX_GetCpuInfo(char* pBuffer, unsigned int uiBufLen)
|
|||
uiBufLen -= iResult;
|
||||
iAllSize += iResult;
|
||||
|
||||
/* open /proc/stat */
|
||||
/* 打开/proc/stat */
|
||||
BBOX_NOINTR(iStatFD = sys_open(BBOX_PROC_INTER_PATH, O_RDONLY, 0));
|
||||
if (iStatFD < 0) {
|
||||
bbox_print(PRINT_ERR, "sys_open is failed, errno = %d.\n", errno);
|
||||
bbox_print(PRINT_ERR, "sys_open执行失败,errno = %d。\n", errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* read /proc/stat */
|
||||
/* 读取/proc/stat */
|
||||
BBOX_NOINTR(iReadSize = sys_read(iStatFD, pBuffer, uiBufLen));
|
||||
if (iReadSize < 0) {
|
||||
(void)sys_close(iStatFD);
|
||||
bbox_print(PRINT_ERR, "sys_read is failed, errno = %d.\n", errno);
|
||||
bbox_print(PRINT_ERR, "sys_read执行失败,errno = %d。\n", errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
|
|
@ -489,11 +524,11 @@ int BBOX_GetCpuInfo(char* pBuffer, unsigned int uiBufLen)
|
|||
}
|
||||
|
||||
/*
|
||||
* get information of system internal storage
|
||||
* in : char *pBuffer - buffer to store result
|
||||
* unsigned int uiBufLen - buffer size
|
||||
* return : count of character store into buffer - success
|
||||
* RET_ERR - failed
|
||||
* 获取系统内存信息
|
||||
* 输入:char *pBuffer - 存储结果的缓冲区
|
||||
* unsigned int uiBufLen - 缓冲区大小
|
||||
* 返回值:存储到缓冲区的字符数 - 成功
|
||||
* RET_ERR - 失败
|
||||
*/
|
||||
int BBOX_GetMemInfo(char* pBuffer, unsigned int uiBufLen)
|
||||
{
|
||||
|
|
@ -502,15 +537,16 @@ int BBOX_GetMemInfo(char* pBuffer, unsigned int uiBufLen)
|
|||
int iAllSize = 0;
|
||||
int iReadSize = 0;
|
||||
|
||||
// 检查参数是否有效
|
||||
if (NULL == pBuffer) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetMemInfo parameters is invalid.\n");
|
||||
bbox_print(PRINT_ERR, "BBOX_GetMemInfo参数无效。\n");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* information title */
|
||||
iResult = bbox_snprintf(pBuffer, uiBufLen, "\nMEM INFO\n--------------------------------------------\n");
|
||||
/* 信息标题 */
|
||||
iResult = bbox_snprintf(pBuffer, uiBufLen, "\n内存信息\n--------------------------------------------\n");
|
||||
if (iResult <= 0 || iResult > (int)uiBufLen) {
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf执行失败,errno = %d。\n", errno);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
|
|
@ -519,18 +555,18 @@ int BBOX_GetMemInfo(char* pBuffer, unsigned int uiBufLen)
|
|||
uiBufLen -= iResult;
|
||||
iAllSize += iResult;
|
||||
|
||||
/* open /proc/meminfo */
|
||||
/* 打开/proc/meminfo */
|
||||
BBOX_NOINTR(iStatFD = sys_open(BBOX_PROC_MEMINFO_PATH, O_RDONLY, 0));
|
||||
if (iStatFD < 0) {
|
||||
bbox_print(PRINT_ERR, "sys_open is failed, iStatFD = %d.\n", iStatFD);
|
||||
bbox_print(PRINT_ERR, "sys_open执行失败,iStatFD = %d。\n", iStatFD);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* read /proc/meminfo */
|
||||
/* 读取/proc/meminfo */
|
||||
BBOX_NOINTR(iReadSize = sys_read(iStatFD, pBuffer, uiBufLen));
|
||||
if (iReadSize < 0) {
|
||||
(void)sys_close(iStatFD);
|
||||
bbox_print(PRINT_ERR, "sys_read is failed, iReadSize = %d.\n", iReadSize);
|
||||
bbox_print(PRINT_ERR, "sys_read执行失败,iReadSize = %d。\n", iReadSize);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
|
|
@ -540,6 +576,7 @@ int BBOX_GetMemInfo(char* pBuffer, unsigned int uiBufLen)
|
|||
return iAllSize;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get information of ps command
|
||||
* in : char *pBuffer - buffer to write result information
|
||||
|
|
@ -547,6 +584,18 @@ int BBOX_GetMemInfo(char* pBuffer, unsigned int uiBufLen)
|
|||
* return : success - count of characters written to the buffer
|
||||
* failed - RET_ERR
|
||||
*/
|
||||
/*
|
||||
这段代码是一个用于获取系统运行信息的函数。函数名为BBOX_GetPsInfo,
|
||||
接受两个参数:一个字符指针pBuffer,用于存储信息的缓冲区;一个无符号整数uiBufLen,表示缓冲区的长度。函数的返回值为成功写入缓冲区的字符数量,如果失败则返回一个错误码。
|
||||
函数首先对传入的指针进行了NULL检查,如果pBuffer为NULL,则打印错误消息并返回一个错误码。
|
||||
然后,使用bbox_snprintf函数将一些信息标题写入缓冲区,包括换行符和分隔线。如果bbox_snprintf返回值小于等于0,或者大于缓冲区长度,打印一个错误消息,并返回一个错误码。
|
||||
接下来,函数通过执行系统命令"ps"来获取进程信息。函数使用sys_popen函数打开一个管道,并将管道的输出连接到iCommandFD文件描述符。如果sys_popen返回的文件描述符小于0,说明打开管道失败,打印一个相关错误消息,并返回一个错误码。
|
||||
然后,函数使用sys_read函数从iCommandFD文件描述符中读取数据,并将数据写入缓冲区。如果sys_read返回的字节数小于0,说明读取失败,函数调用sys_pclose函数关闭打开的管道,并打印一个相关错误消息,并返回一个错误码。
|
||||
接着,函数将读取到的字节数累加到iAllSize变量中。如果iReadSize不为0,函数将缓冲区中的最后一个字符设置为'\0'。
|
||||
最后,函数返回iAllSize变量的值,表示写入缓冲区的总字符数量。
|
||||
此外,代码中还有一个函数_BBOX_GetAddonInfo,该函数调用了BBOX_GetPsInfo函数,并对获取的系统运行信息进行了进一步处理。该函数的实现逻辑与BBOX_GetPsInfo类似,但是还调用了其他几个函数来获取不同的系统信息,并将这些信息写入缓冲区。
|
||||
最后的#ifdef __cplusplus部分是对C++编译器进行的特殊处理,暂时可以忽略。
|
||||
*/
|
||||
int BBOX_GetPsInfo(char* pBuffer, unsigned int uiBufLen)
|
||||
{
|
||||
int iResult = 0;
|
||||
|
|
|
|||
|
|
@ -51,8 +51,28 @@ struct PIPE_IDS {
|
|||
static struct PIPE_IDS astPipeIds[BBOX_MAX_PIDS];
|
||||
|
||||
/*
|
||||
* compare string pszSrc and pszTarget
|
||||
*/
|
||||
function name: bbox_strncmp
|
||||
description: To compare two substrings, the pointers pszSrc and pszTarget store their host strings'addresses.
|
||||
arguments: Two pointers of type const char*, pointing to two strings needed to be compared.
|
||||
An integer indicates the number of characters at the former of two strings that
|
||||
will be compared.
|
||||
return value: Type s32, an interger.
|
||||
If it's zero, then the former substrings of string pszSrc and pszTarget are same,
|
||||
else it indicates the difference between the first two characters that these two
|
||||
strings can't match.
|
||||
note锛歍he two pointers shouldn't be null. The last argument shouldn't less than zero.
|
||||
date: 2022/8/2
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/*
|
||||
这段代码是一个用于比较字符串的函数bbox_strncmp。它接受三个参数:常量字符指针pszSrc,用于表示源字符串;常量字符指针pszTarget,用于表示目标字符串;整数count,表示要比较的字符数。
|
||||
首先,定义一个有符号字符变量cRes并初始化为0。
|
||||
然后,使用while循环进行字符串比较,条件为count大于0。每次循环执行以下操作:
|
||||
首先,将源字符串指针的值与目标字符串指针的值相减,并将结果赋给cRes。如果结果不等于0,或者源字符串指针的值为0(即字符串结束),则跳出循环。
|
||||
然后,将目标字符串指针递增1,源字符串指针也递增1。
|
||||
最后,将count减1。
|
||||
循环结束后,返回变量cRes,它表示最后一次比较的结果。如果cRes为0,则表示两个字符串相等;如果cRes小于0,则表示源字符串小于目标字符串;如果cRes大于0,则表示源字符串大于目标字符串。
|
||||
*/
|
||||
s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
|
||||
{
|
||||
signed char cRes = 0;
|
||||
|
|
@ -68,8 +88,20 @@ s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count)
|
|||
}
|
||||
|
||||
/*
|
||||
* compare string pszSrc and pszTarget
|
||||
*/
|
||||
function name: bbox_strcmp
|
||||
description: compare two strings, the pointer pszSrc and pszTarget store their addresses.
|
||||
arguments: Two pointers of type const char*, pointing to two strings needed to be compared.
|
||||
An integer indicates the number of characters at the former of two strings that
|
||||
will be compared.
|
||||
return value: Type s32, an interger.
|
||||
If it's zero, then the former substrings of string pszSrc and pszTarget are same,
|
||||
else if it's 1, then it indicates between first two characters that these two
|
||||
strings can't match, the character of first string that pszSrc points is greater,
|
||||
else if it's -1, the character of second string that pszTarget points is greater.
|
||||
note锛歍he two pointers shouldn't be null. The last argument shouldn't less than zero.
|
||||
date: 2022/8/2
|
||||
contact tel:same
|
||||
*/
|
||||
s32 bbox_strcmp(const char* pszSrc, const char* pszTarget)
|
||||
{
|
||||
unsigned char c1, c2;
|
||||
|
|
@ -90,8 +122,15 @@ s32 bbox_strcmp(const char* pszSrc, const char* pszTarget)
|
|||
}
|
||||
|
||||
/*
|
||||
* get the length of string pszString
|
||||
*/
|
||||
function name: bbox_strlen
|
||||
description: Calculate the length of string.
|
||||
arguments: An pointer that indicates the address of a string.
|
||||
return value: Type s32, an integer indicating the length of string.
|
||||
note: the length of string=(address of the last character not '\0'-address of the first character)/sizeof(char), and sizeof(char)
|
||||
equals to 1, so the length of string=(address of the last character not '\0'-address of the first character).
|
||||
date: 2022/8/2
|
||||
contact tel:same
|
||||
*/
|
||||
s32 bbox_strlen(const char* pszString)
|
||||
{
|
||||
const char* pszTemp = NULL;
|
||||
|
|
@ -105,8 +144,16 @@ s32 bbox_strlen(const char* pszString)
|
|||
}
|
||||
|
||||
/*
|
||||
* get the length of string pszString
|
||||
*/
|
||||
function name: bbox_strnlen
|
||||
description: Calculate the length of string, but having some restrictive conditions.
|
||||
arguments: An pointer that indicates the address of a string.
|
||||
And an integer that indicates the maxlenth.
|
||||
return value: Type s32, an integer indicating the length of string.
|
||||
note: If the length of string exceed the argument count, then return the length of string,
|
||||
else return the argument count.
|
||||
date: 2022/8/2
|
||||
contact tel:same
|
||||
*/
|
||||
s32 bbox_strnlen(const char* pszString, s32 count)
|
||||
{
|
||||
const char* pszTemp = NULL;
|
||||
|
|
@ -119,8 +166,25 @@ s32 bbox_strnlen(const char* pszString, s32 count)
|
|||
}
|
||||
|
||||
/*
|
||||
* convert a string to interger
|
||||
*/
|
||||
function name: bbox_atoi
|
||||
description: Convert a string that includes continuous digital characters to an integer,
|
||||
if the first character of the string is '-', then we will return a negative result.
|
||||
arguments: An pointer that indicates the address of a string.
|
||||
return value: Type s32, an integer indicating the result of string converted.
|
||||
note: I think the function isn't perfect, though it's not a core function. For example, what about
|
||||
the condition that the first character of the string is '+'?
|
||||
date: 2022/8/2
|
||||
contact tel:same
|
||||
*/
|
||||
/*
|
||||
这段代码是一个将字符串转换为整数的函数bbox_atoi。它接受一个常量字符指针pszString,表示要转换的字符串,并返回一个整数值。
|
||||
首先,定义两个整数变量n和iNeg,并初始化为0。其中,n用于存储转换后的整数值,iNeg用于表示是否为负数。
|
||||
然后,判断字符串的第一个字符是否为'-'。如果是,则将iNeg设置为1,表示转换结果为负数。
|
||||
如果iNeg为1,将字符串指针向后移动一位,跳过负号。
|
||||
接下来,使用while循环,判断当前字符是否为数字字符,即是否在字符范围'0'到'9'之间。
|
||||
在循环内部,首先将n乘以10,然后将当前字符减去'0',并累加到n中。
|
||||
循环结束后,返回n的值。如果iNeg为1,则表示结果为负数,返回负数的n;如果iNeg为0,则表示结果为正数,返回正数的n。
|
||||
*/
|
||||
s32 bbox_atoi(const char* pszString)
|
||||
{
|
||||
s32 n = 0;
|
||||
|
|
@ -140,10 +204,18 @@ s32 bbox_atoi(const char* pszString)
|
|||
|
||||
return iNeg ? -n : n;
|
||||
}
|
||||
|
||||
/*
|
||||
* compare memory
|
||||
*/
|
||||
function name: bbox_memcmp
|
||||
description: Compare former count bytes in ASCII of data stored in two areas that pointers cs and ct direct.
|
||||
arguments: Two pointers to areas of memory, and an integer indicating the max counts compared.
|
||||
return value: Type s32, an integer.
|
||||
If the value returned is 0, then the data stored in two areas destined are same,
|
||||
else if is 1, then between two first data in ASCII of byte different, cs's is greater,
|
||||
else if is -1, then ct's is greater.
|
||||
note: The two pointers should not be null, it's dangerous.
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
s32 bbox_memcmp(const void* cs, const void* ct, s32 count)
|
||||
{
|
||||
const unsigned char *su1 = NULL;
|
||||
|
|
@ -159,8 +231,18 @@ s32 bbox_memcmp(const void* cs, const void* ct, s32 count)
|
|||
}
|
||||
|
||||
/*
|
||||
* search string l2 in l1
|
||||
*/
|
||||
function name: bbox_strstr
|
||||
description: Judge if the string s2 directs is substring of string s1 directs.
|
||||
arguments: Two pointers of type const char*, pointing to two strings.
|
||||
return value: Type char*, a pointer. Actually it's a address, if s2 directs a
|
||||
null string, then return the address of the first character of s1,
|
||||
if the string s2 directs isn't substring of string s1 directs, return
|
||||
null, if the string s2 directs is substring of string s1 directs, then return
|
||||
the address of first character matched.
|
||||
note: The two pointers should not be null, it's dangerous.
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
char* bbox_strstr(const char* s1, const char* s2)
|
||||
{
|
||||
int l1, l2;
|
||||
|
|
@ -182,8 +264,17 @@ char* bbox_strstr(const char* s1, const char* s2)
|
|||
}
|
||||
|
||||
/*
|
||||
* make a directory
|
||||
*/
|
||||
function name: bbox_mkdir
|
||||
description: We distinguish parent directory and child directory through character '/',
|
||||
normally through a for loop, we can make sure all directories above the directory
|
||||
we want to creat exist, finally we will creat the flag directory after its parent.
|
||||
arguments: A pointers of type const char*, pointing to one strings, which indicates the filename and its full path.
|
||||
return value: An integer of type s32, if it's RET_ERR, then we fail to make a directory, else if it's RET_OK then we succeed.
|
||||
note: Take care the last non-null character of the string needed to be '/', and once if flag directory's
|
||||
ancestors aren't exist, the function return RET_ERR.
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
s32 bbox_mkdir(const char* pszDir)
|
||||
{
|
||||
char szDirName[BBOX_TMP_LEN_32 * 16];
|
||||
|
|
@ -228,8 +319,16 @@ s32 bbox_mkdir(const char* pszDir)
|
|||
}
|
||||
|
||||
/*
|
||||
* search free pipe id
|
||||
*/
|
||||
function name: bbox_GetFreePid
|
||||
description: Through a for loop, we search a free pipe in a structure array, to an array element if its
|
||||
member variable isUsed's value is 0, we return the array element's another member variable
|
||||
stPid's address.
|
||||
arguments: void
|
||||
return value: An pointer of type struct PIPE_ID* or NULL.
|
||||
note: none
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
struct PIPE_ID* bbox_GetFreePid(void)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -245,8 +344,14 @@ struct PIPE_ID* bbox_GetFreePid(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* Release the occupied pipeid
|
||||
*/
|
||||
function name: bbox_PutPid
|
||||
description: Release the occupied pipe.
|
||||
arguments: A pointer of type struct PIPE_ID*.
|
||||
return value: void
|
||||
note: If the argument pointer is null, then there is no need to free the storage, the function ends.
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
void bbox_PutPid(struct PIPE_ID* pstPid)
|
||||
{
|
||||
struct PIPE_IDS* pstPids = NULL;
|
||||
|
|
@ -261,8 +366,16 @@ void bbox_PutPid(struct PIPE_ID* pstPid)
|
|||
}
|
||||
|
||||
/*
|
||||
* find available pipe id by file handle
|
||||
*/
|
||||
function name: bbox_FindPid
|
||||
description: In all occupied pipes, the function search the flag pipe through compare all structure
|
||||
array elements's member variable stPid's member variable iFd with the function
|
||||
argument iFd, if they are equal, then return the addres of this array elements.
|
||||
arguments: An integer that indicates a file's file handle.
|
||||
return value: A pointer of type struct PIPE_ID* or NULL.
|
||||
note: none
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
struct PIPE_ID* bbox_FindPid(int iFd)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -281,8 +394,38 @@ struct PIPE_ID* bbox_FindPid(int iFd)
|
|||
}
|
||||
|
||||
/*
|
||||
* run popen
|
||||
*/
|
||||
function name: sys_popen
|
||||
description: The function gets a free pipe by function bbox_GetFreePid, if normally, then creat a pipe
|
||||
through sys_pipe, andcreat a child process through function sys_fork, execute a shell command
|
||||
to run a process.
|
||||
arguments: One pointer to a string that represents command line, another pointer of type const char*
|
||||
indicates that the file file handle directs is used in the this mode.
|
||||
return value: A pointer of type struct PIPE_ID* or NULL.
|
||||
note: The string that indicates pszMode should only be "r" or "w",
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
/*
|
||||
函数sys_popen的作用是打开一个管道,用于执行指定的命令。
|
||||
它接受两个参数:一个字符指针pszCmd,用于存储要执行的命令;一个常量字符指针pszMode,表示管道的读写模式。函数返回一个整数值,表示管道文件描述符。
|
||||
首先,函数检查pszCmd和pszMode指针是否为空,如果为空,则设置errno为EINVAL,并返回-1。
|
||||
然后,函数检查读写模式是否正确,即pszMode只能为'r'或'w',并且只能有一个字符。如果模式不正确,则设置errno为EINVAL,并返回-1。
|
||||
接下来,函数使用bbox_GetFreePid函数获取一个空闲的管道ID。如果获取失败,则返回-1。
|
||||
然后,函数使用sys_pipe函数创建一个管道,如果创建失败,则返回-1。
|
||||
接着,函数使用sys_fork函数创建子进程。如果创建子进程失败,则关闭管道的文件描述符,释放管道ID,并返回-1。如果创建成功,则在子进程中执行以下操作:
|
||||
|
||||
- 获取待执行的命令和参数数组pArgv。
|
||||
- 恢复信号函数。
|
||||
- 关闭其他文件描述符,除了管道的读写文件描述符。
|
||||
- 根据读写模式设置标准输入输出文件描述符。
|
||||
- 使用sys_execve函数执行命令。如果执行失败,则打印错误信息,并使用sys_exit函数退出进程。
|
||||
最后,如果当前进程是父进程,则根据读写模式选择要返回的文件描述符,并将管道ID和子进程ID保存起来。
|
||||
函数sys_pclose的作用是关闭由sys_popen打开的管道。它接受一个整数值iFd,表示要关闭的文件描述符。函数返回一个整数值,表示进程的最终状态。
|
||||
首先,函数使用bbox_FindPid函数根据文件描述符查找对应的管道ID。如果查找失败,则返回-1。
|
||||
然后,函数使用sys_close函数关闭文件描述符。
|
||||
接着,函数使用sys_waitpid函数等待子进程的退出,并获取进程的状态。如果等待失败,则继续等待,直到成功或出现其他错误。
|
||||
最后,函数释放管道ID,并根据等待的结果返回相应的值。
|
||||
*/
|
||||
s32 sys_popen(char* pszCmd, const char* pszMode)
|
||||
{
|
||||
struct PIPE_ID* volatile stCurPid = NULL;
|
||||
|
|
@ -387,8 +530,15 @@ s32 sys_popen(char* pszCmd, const char* pszMode)
|
|||
}
|
||||
|
||||
/*
|
||||
* close file handle
|
||||
*/
|
||||
function name: sys_pclose
|
||||
description: The function has an contrary action to function sys_popen, it close the pipe
|
||||
that sys_popen open.
|
||||
arguments: iFd, an integer that indicates a file handle.
|
||||
return value: An integer that indicates the final status of the process working before.
|
||||
note: none
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
int sys_pclose(s32 iFd)
|
||||
{
|
||||
struct PIPE_ID* pstCur = NULL;
|
||||
|
|
@ -411,8 +561,17 @@ int sys_pclose(s32 iFd)
|
|||
}
|
||||
|
||||
/*
|
||||
* list file in directory
|
||||
*/
|
||||
function name: bbox_listdir
|
||||
description: The function list all files below this path in directory.
|
||||
arguments: The first argument is a pointer to a string representing a file path, all files below
|
||||
this path will be listed in directory. The second argument is a pointer to a callback
|
||||
function. The last is a pointer of type void*, it indicates a command line.
|
||||
return value: An integer that indicates the result of function, if normal, it's RET_OK, else
|
||||
it's RET_ERR.
|
||||
note: The path that the first argument represents should be absolute path, take care.
|
||||
date: 2022/8/2
|
||||
contact tel: same
|
||||
*/
|
||||
s32 bbox_listdir(const char* pstPath, BBOX_LIST_DIR_CALLBACK callback, void* pArgs)
|
||||
{
|
||||
struct linux_dirent* pstEntry = NULL;
|
||||
|
|
|
|||
|
|
@ -57,23 +57,37 @@ void bbox_initlog(int iLogScreen)
|
|||
}
|
||||
|
||||
/*
|
||||
* convert int to string
|
||||
*/
|
||||
function name: bbox_itoc
|
||||
description: Convert an integer to a character.
|
||||
arguments: An integer needed to be converted.
|
||||
return value: An character that corresponds to the function's integer argument.
|
||||
note: The integer argument can be converted in radices more than decimalism.
|
||||
date: 2022/8/2
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
inline char bbox_itoc(u8 sNum)
|
||||
{
|
||||
return (char)((sNum < 10) ? (sNum + 48) : (sNum + 87));
|
||||
}
|
||||
|
||||
/*
|
||||
* convert int to string
|
||||
* in : pCallback - call back function
|
||||
* ptr - private data to call this function
|
||||
* piCount - offset pointer
|
||||
* iSize - buffer size
|
||||
* uNum - the variable to convert
|
||||
* sSys - type of variable
|
||||
* isNeg - is negative
|
||||
* return : need call back
|
||||
*/
|
||||
function name: bbox_put_dox
|
||||
description: Conversion of number systems.
|
||||
arguments: The first argument pCallback is a pointer to a callback function, we
|
||||
use it to reverse the final result. The second argument is a pointer of
|
||||
type void* used as a argument of function pCallback. The third argument
|
||||
piCount is a pointer of type int, an offset pointer, also be used as a argument
|
||||
of pCallback. The fourth argument is an integer of 32 bits, it indicates the buffer
|
||||
size pCallback uses.The fifth argument uNum is a decimal integer that will
|
||||
be converted to an integer in another radix. The sixth argument is used as
|
||||
base to conversion of number systems. The last argument indicates the integer
|
||||
after converted is a negative integer or not.
|
||||
return value: An integer, indicating if the function pCallback work successfully.
|
||||
note: The argument uNum should be a positive integer, after conversion of number systems
|
||||
the sign will be appended to string's tail.
|
||||
date: 2022/8/2
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
s32 bbox_put_dox(BBOX_vnprintCallBack pCallback, void* ptr, s32* piCount, u32 iSize, u64 uNum, s32 sSys, s32 isNeg)
|
||||
{
|
||||
s64 i = 0;
|
||||
|
|
@ -108,62 +122,76 @@ s32 bbox_put_dox(BBOX_vnprintCallBack pCallback, void* ptr, s32* piCount, u32 iS
|
|||
|
||||
return iRet;
|
||||
}
|
||||
|
||||
/*
|
||||
* simple signal-safe function vsnprintf
|
||||
* in : pCallback - call back function
|
||||
* ptr - private data to call this function
|
||||
* iSize - buffer size
|
||||
* pFmt - format type
|
||||
* ap - parameter list pointer¸ñʽ
|
||||
* return : length of string
|
||||
*/
|
||||
function name: bbox_vsnprintf
|
||||
description: The function is used to print string in corresponding array.
|
||||
arguments: The first argument is a pointer to a callback function, the next is a
|
||||
pointer to private data to call this function, also to buffer.
|
||||
The third is used to destine buffer size. The forth is used to destine
|
||||
the print format of deferent string, the last is a pointer to variable parameter list.
|
||||
return value: An integer, if iSize is big enough, then the return value is the length of
|
||||
string been written in destined memory successfully, not include '\0',
|
||||
if function makes errors, the return value is a negative integer.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const char* pFmt, va_list ap)
|
||||
{
|
||||
// 定义变量
|
||||
s32 iCount = 0; // 记录写入缓冲区的字符数
|
||||
char c; // 临时存储格式化字符串中的字符
|
||||
s32 iCheckFmt = 0; // 判断是否处于格式化标识符 '%' 的状态
|
||||
s32 iQualifier = 0; // 判断是否有 'l' 或 'z' 限定符
|
||||
s32 iSizeTConv = 0; // 判断是否有 'z' 限定符
|
||||
s32 iRet = 0; // 用于保存回调函数的返回值
|
||||
|
||||
s32 iCount = 0;
|
||||
char c;
|
||||
s32 iCheckFmt = 0;
|
||||
s32 iQualifier = 0;
|
||||
s32 iSizeTConv = 0;
|
||||
s32 iRet = 0;
|
||||
|
||||
// 检查缓冲区大小是否合法
|
||||
if (iSize <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* traversal handles formatting strings */
|
||||
// 遍历格式化字符串
|
||||
while (0 == iRet) {
|
||||
c = *(pFmt++);
|
||||
|
||||
// 判断是否遍历完格式化字符串
|
||||
if (!c) {
|
||||
break;
|
||||
}
|
||||
/* judge format type if % */
|
||||
|
||||
// 判断是否为格式化标识符 '%'
|
||||
if (c == '%' && 0 == iCheckFmt) {
|
||||
// 初始化限定符和转换说明符
|
||||
iQualifier = 0;
|
||||
iSizeTConv = 0;
|
||||
iCheckFmt = 1;
|
||||
continue;
|
||||
} else if (0 == iCheckFmt) {
|
||||
/* copy */
|
||||
// 复制非格式化标识符
|
||||
iRet = pCallback(c, ptr, &iCount, iSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check whether the parameter has l */
|
||||
// 判断是否有 'l' 限定符或 'z' 限定符
|
||||
if (c == 'l' && iQualifier == 0) {
|
||||
iQualifier = 1;
|
||||
iQualifier = 1; // 标记有 'l' 限定符
|
||||
continue;
|
||||
} else if (c == 'z') {
|
||||
iSizeTConv = 1;
|
||||
iSizeTConv = 1; // 标记有 'z' 限定符
|
||||
continue;
|
||||
}
|
||||
|
||||
// 根据格式化标识符的类型执行相应的操作
|
||||
switch (c) {
|
||||
case 'c': {
|
||||
// 处理字符类型
|
||||
char ch = (char)va_arg(ap, int);
|
||||
iRet = pCallback(ch, ptr, &iCount, iSize);
|
||||
iRet = pCallback(ch, ptr, &iCount, iSize); // 调用回调函数处理字符
|
||||
} break;
|
||||
case 'd': {
|
||||
// 处理有符号十进制整数类型
|
||||
signed long long n = 0;
|
||||
if (iSizeTConv) {
|
||||
#if (defined(__x86_64__)) || (defined(__aarch64__))
|
||||
|
|
@ -177,19 +205,22 @@ s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const c
|
|||
|
||||
s32 isNeg = (n < 0) ? 1 : 0;
|
||||
n = (isNeg) ? (-1 * n) : (n);
|
||||
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, isNeg);
|
||||
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, isNeg); // 调用回调函数处理数字
|
||||
} break;
|
||||
case 'l': {
|
||||
// 处理长整型类型
|
||||
signed long long n = (iQualifier) ? va_arg(ap, long long) : va_arg(ap, long);
|
||||
s32 isNeg = (n < 0) ? 1 : 0;
|
||||
n = (isNeg) ? (-1 * n) : (n);
|
||||
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, isNeg);
|
||||
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, isNeg); // 调用回调函数处理数字
|
||||
} break;
|
||||
case 'x': {
|
||||
// 处理十六进制整数类型
|
||||
unsigned long long n = (iQualifier) ? va_arg(ap, unsigned long int) : va_arg(ap, unsigned int);
|
||||
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 16, 0);
|
||||
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 16, 0); // 调用回调函数处理数字
|
||||
} break;
|
||||
case 'u': {
|
||||
// 处理无符号十进制整数类型
|
||||
unsigned long long n = 0;
|
||||
if (iSizeTConv) {
|
||||
#if (defined(__x86_64__)) || (defined(__aarch64__))
|
||||
|
|
@ -201,61 +232,75 @@ s32 bbox_vsnprintf(BBOX_vnprintCallBack pCallback, void* ptr, s32 iSize, const c
|
|||
n = (iQualifier) ? va_arg(ap, unsigned long long) : va_arg(ap, unsigned int);
|
||||
}
|
||||
|
||||
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, 0);
|
||||
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 10, 0); // 调用回调函数处理数字
|
||||
} break;
|
||||
case 'p': {
|
||||
// 处理指针类型
|
||||
unsigned long long n = va_arg(ap, unsigned long);
|
||||
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 16, 0);
|
||||
iRet = bbox_put_dox(pCallback, ptr, &iCount, iSize, (u64)n, 16, 0); // 调用回调函数处理数字
|
||||
} break;
|
||||
case 's': {
|
||||
// 处理字符串类型
|
||||
char* p = va_arg(ap, char*);
|
||||
|
||||
if (p == NULL) {
|
||||
p = "<NULL>";
|
||||
}
|
||||
while (*p && (!iRet)) {
|
||||
iRet = pCallback(*p, ptr, &iCount, iSize);
|
||||
iRet = pCallback(*p, ptr, &iCount, iSize); // 调用回调函数处理字符
|
||||
p++;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
iRet = pCallback(c, ptr, &iCount, iSize);
|
||||
iRet = pCallback(c, ptr, &iCount, iSize); // 调用回调函数处理字符
|
||||
break;
|
||||
}
|
||||
|
||||
// 重置限定符和转换说明符
|
||||
iQualifier = 0;
|
||||
iCheckFmt = 0;
|
||||
}
|
||||
|
||||
// 检查回调函数的返回值和终止符的写入情况
|
||||
if (iRet != RET_OK || pCallback(0, ptr, &iCount, iSize) != RET_OK) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
return iCount;
|
||||
return iCount; // 返回写入缓冲区的字符数
|
||||
}
|
||||
|
||||
/*
|
||||
* call back function of snprintf_s
|
||||
* in : c - string to calculate
|
||||
* pPtr - pointer to buffer
|
||||
* piCount - count of character
|
||||
* iSize - limit of length
|
||||
* return : length of string
|
||||
*/
|
||||
function name: bbox_SnprintCallback
|
||||
description: The function is used to print string in corresponding array, usually
|
||||
used as the first argument of function bbox_vsnprintf.
|
||||
arguments: The first argument is a character waited to be written into buffer that
|
||||
pPtr directs, the second argument directs a buffer area, the third is a
|
||||
pointer to an integera used to record the count to call this callback function,
|
||||
at the same time, it represents the count of characters written into buffer, it's
|
||||
a pointer so that we can conveniently modify data storedin it. The last
|
||||
argument destines the size of buffer, it represents the limit of length.
|
||||
return value: An integer, if written successfully, it's RET_OK, else it's RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/*
|
||||
bbox_SnprintCallback函数是一个回调函数,用于处理bbox_snprintf函数中的格式化字符串。该函数的作用是将字符c写入到pszBuff指向的缓冲区中,并更新pszBuff和piCount的值。
|
||||
*/
|
||||
s32 bbox_SnprintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
|
||||
{
|
||||
char** pszBuff = (char**)pPtr;
|
||||
|
||||
/* return if the buffer length is exceeded */
|
||||
/* 如果超过了缓冲区的长度限制,则返回错误 */
|
||||
if (*piCount >= iSize - 1) {
|
||||
/* set the last bit to 0 and return err, means that exit snprintf_s function. */
|
||||
/* 将最后一位设置为0,并返回错误(表示退出snprintf_s函数) */
|
||||
**pszBuff = 0;
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
**pszBuff = c;
|
||||
(*pszBuff)++;
|
||||
(*piCount)++;
|
||||
**pszBuff = c; // 将字符c写入到缓冲区中
|
||||
(*pszBuff)++; // 更新pszBuff的地址
|
||||
(*piCount)++; // 更新piCount的值
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
|
@ -267,6 +312,7 @@ s32 bbox_SnprintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
|
|||
* pFmt - string format
|
||||
* return : string length
|
||||
*/
|
||||
//bbox_snprintf函数是一个简化版的snprintf函数,用于格式化输出字符串到指定的缓冲区中。
|
||||
s32 bbox_snprintf(char* pszBuff, s32 iSize, const char* pFmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
|
@ -286,6 +332,10 @@ s32 bbox_snprintf(char* pszBuff, s32 iSize, const char* pFmt, ...)
|
|||
* iSize - length limit
|
||||
* return : string length
|
||||
*/
|
||||
/*
|
||||
bbox_PrintCallback函数是一个回调函数,用于处理bbox_printf函数和bbox_print函数中的格式化字符串。
|
||||
该函数的作用是将字符c写入到指定的文件描述符中,并更新g_pcCurWriteLogPos和g_iLastLogLen的值
|
||||
*/
|
||||
s32 bbox_PrintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
|
||||
{
|
||||
s32* fd = (s32*)pPtr;
|
||||
|
|
@ -294,14 +344,14 @@ s32 bbox_PrintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
|
|||
return RET_OK;
|
||||
}
|
||||
|
||||
/* write */
|
||||
/* 写入文件描述符 */
|
||||
if (fd != 0 && *fd >= 0) {
|
||||
sys_write(*fd, &c, 1);
|
||||
}
|
||||
|
||||
/* return if the buffer length is exceeded */
|
||||
/* 如果超过了缓冲区的长度限制,则返回错误 */
|
||||
if (g_iLastLogLen <= 1) {
|
||||
/* set the last bit to 0 and return err, means that exit snprintf_s function. */
|
||||
/* 将最后一位设置为0,并返回错误(表示退出snprintf_s函数) */
|
||||
*g_pcCurWriteLogPos = 0;
|
||||
if (g_iLogScreen) {
|
||||
return RET_OK;
|
||||
|
|
@ -310,9 +360,9 @@ s32 bbox_PrintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
|
|||
return RET_ERR;
|
||||
}
|
||||
|
||||
*g_pcCurWriteLogPos = c;
|
||||
(g_pcCurWriteLogPos)++;
|
||||
(g_iLastLogLen)--;
|
||||
*g_pcCurWriteLogPos = c; // 将字符c写入到缓冲区中
|
||||
(g_pcCurWriteLogPos)++; // 更新g_pcCurWriteLogPos的地址
|
||||
(g_iLastLogLen)--; // 更新g_iLastLogLen的值
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
|
@ -320,6 +370,7 @@ s32 bbox_PrintCallback(char c, void* pPtr, s32* piCount, s32 iSize)
|
|||
/*
|
||||
* simple signal-safe function printf
|
||||
*/
|
||||
//bbox_printf函数是一个简化版的printf函数,用于将格式化的字符串输出到标准输出。
|
||||
void bbox_printf(const char* pFmt, ...)
|
||||
{
|
||||
s32 fd = 1;
|
||||
|
|
@ -333,6 +384,7 @@ void bbox_printf(const char* pFmt, ...)
|
|||
/*
|
||||
* simple signal-safe function print
|
||||
*/
|
||||
//bbox_print函数是一个简化版的printf函数,可以根据打印级别和屏幕打印级别来输出格式化的字符串到标准输出。
|
||||
void bbox_print(EN_PRINT_TYPE enType, const char* pFmt, ...)
|
||||
{
|
||||
s32 fd = 1;
|
||||
|
|
@ -356,6 +408,7 @@ void bbox_print(EN_PRINT_TYPE enType, const char* pFmt, ...)
|
|||
/*
|
||||
* set print level
|
||||
*/
|
||||
//bbox_set_log_level函数用于设置日志级别,根据传入的enLevel参数来设置全局变量g_enLogLevel的值。
|
||||
s32 bbox_set_log_level(EN_PRINT_TYPE enLevel)
|
||||
{
|
||||
if (enLevel < PRINT_DBG || enLevel > PRINT_ERR) {
|
||||
|
|
@ -370,6 +423,7 @@ s32 bbox_set_log_level(EN_PRINT_TYPE enLevel)
|
|||
/*
|
||||
* set screen print level
|
||||
*/
|
||||
//bbox_set_screen_log_level函数用于设置屏幕打印级别,根据传入的enLevel参数来设置全局变量g_enScreenLogLeven的值。
|
||||
s32 bbox_set_screen_log_level(EN_PRINT_TYPE enLevel)
|
||||
{
|
||||
if (enLevel < PRINT_DBG || enLevel > PRINT_ERR) {
|
||||
|
|
|
|||
|
|
@ -64,8 +64,22 @@ u8 g_szAltStackMem[BBOX_ALT_STACKSIZE]; /* independent thread stack memory */
|
|||
BBOX_ATOMIC_STRU g_isBusy = BBOX_ATOMIC_INIT(0); /* whether deal with core file. */
|
||||
|
||||
/*
|
||||
* reserved count bytes on current stack, and set 0
|
||||
*/
|
||||
function name: BBOX_ReserveZeroStack
|
||||
description: The function creat a empty stack, and its size depend on argument count.
|
||||
arguments: An integer of type s32, namely int, it destines the storage of stack.
|
||||
return value: void
|
||||
note: The stack this function creats is actually a character array.
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
|
||||
/*
|
||||
void BBOX_ReserveZeroStack(s32 count)函数是一个预留并清零堆栈的函数。具体实现如下:
|
||||
|
||||
1. 创建一个大小为count的字符数组buff。
|
||||
2. 调用memset_s函数将buff的值全部设置为0。
|
||||
3. 调用sys_read函数将buff的值从文件描述符-1读取进来。实际上此处读取的操作是无效的,只是为了预留并使用堆栈空间。
|
||||
*/
|
||||
void BBOX_ReserveZeroStack(s32 count)
|
||||
{
|
||||
char buff[count];
|
||||
|
|
@ -80,6 +94,13 @@ void BBOX_ReserveZeroStack(s32 count)
|
|||
* clone the current process and runs the specified function
|
||||
* return 0 if seccess else err code
|
||||
*/
|
||||
/*
|
||||
s32 BBOX_CloneRun(u32 uFlags, s32 (*pFn)(void*), void* pArg, ...)函数是一个克隆当前进程并运行指定函数的函数。具体实现如下:
|
||||
|
||||
1. 首先判断pArg和pFn是否为NULL,如果为NULL则返回-1。
|
||||
2. 调用sys__clone函数克隆当前进程,并将指定的函数和参数传递给新创建的进程。
|
||||
3. 返回新创建进程的pid。
|
||||
*/
|
||||
s32 BBOX_CloneRun(u32 uFlags, s32 (*pFn)(void*), void* pArg, ...)
|
||||
{
|
||||
/* reserve 4K when calling and running a function to protect waitpid can exit correct. */
|
||||
|
|
@ -95,8 +116,14 @@ s32 BBOX_CloneRun(u32 uFlags, s32 (*pFn)(void*), void* pArg, ...)
|
|||
}
|
||||
|
||||
/*
|
||||
* get count of thread
|
||||
*/
|
||||
function name: BBOX_GetTaskNumber
|
||||
description: When get a path to specific process, this function will return count of threads below it.
|
||||
arguments: A pointer of type char*, including a path to specific process.
|
||||
return value: An integer that indicates the count of threads below specific process.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
s32 BBOX_GetTaskNumber(char* szTaskPath)
|
||||
{
|
||||
struct kernel_stat stProcSB = {0};
|
||||
|
|
@ -130,8 +157,37 @@ s32 BBOX_GetTaskNumber(char* szTaskPath)
|
|||
}
|
||||
|
||||
/*
|
||||
* get thread pid
|
||||
*/
|
||||
function name: BBOX_GetTaskId
|
||||
description: When get a path to specific process, this function will return count of threads below it.
|
||||
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
|
||||
we use it as a structure array to store requisite thread infomation, the next argument destines
|
||||
the max size of the array that the first argument destines. The last argument is a pointer of type
|
||||
char*, including a path to specific process.
|
||||
return value: An integer that indicates the count of threads stored in structure array.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/*
|
||||
这是一个用于获取指定路径下进程和线程ID的函数。
|
||||
|
||||
函数的参数包括指向TASK_ATTACH_INFO结构体的指针pstTaskInfo,整型变量iSize和指向字符数组的指针szTaskPath。
|
||||
|
||||
函数的主要步骤如下:
|
||||
|
||||
1. 首先检查指针pstTaskInfo和szTaskPath是否为NULL,如果是则输出错误信息并返回-1。
|
||||
2. 使用sys_open函数以只读和目录模式打开指定的路径szTaskPath,得到的文件描述符保存在变量iProc中。
|
||||
3. 如果iProc小于0,则输出错误信息并返回-1。
|
||||
4. 使用循环遍历/proc/[pid]/task目录下的所有文件,其中iThreadCount表示已经获取的进程和线程ID的数量。
|
||||
5. 使用sys_getdents函数读取目录项,读取的结果保存在szBuff中,返回的字节数保存在nBytes中。
|
||||
6. 如果nBytes小于0,则输出错误信息并跳转到errout标签。
|
||||
7. 如果nBytes等于0,则使用sys_lseek函数将文件指针设置到目录的开头位置,然后跳出循环。
|
||||
8. 遍历目录项,判断当前项是否为进程或线程的目录。
|
||||
9. 提取目录名中的数字作为pid,并将pid存储到pstTaskInfo数组对应的元素中。
|
||||
10. 将iThreadCount加1,表示已经获取的进程和线程ID的数量。
|
||||
11. 使用sys_close函数关闭iProc。
|
||||
12. 返回成功获取的进程和线程ID的数量iThreadCount,如果出错则返回-1。
|
||||
*/
|
||||
s32 BBOX_GetTaskId(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iSize, char* szTaskPath)
|
||||
{
|
||||
s32 iProc = -1;
|
||||
|
|
@ -214,13 +270,32 @@ errout:
|
|||
}
|
||||
|
||||
/*
|
||||
* a ptrace debug thread
|
||||
* in : TASK_ATTACH_INFO - thread information
|
||||
* iPidCount - count of thread information
|
||||
* iDoPtraceCheck - check if ptrace success
|
||||
* return : 0 - success
|
||||
* err code - failed
|
||||
*/
|
||||
function name: BBOX_PtraceAttachPid
|
||||
description: The function is used to check the process whose id stored in structure array pstTaskInfo work normally.
|
||||
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
|
||||
it is used as a structure array that has stored requisite thread infomation, the next argument destines
|
||||
the size of the array that the first argument destines, namely how many elements the array has.
|
||||
The last argument is an integer to decide if need to check if the trace to destined process
|
||||
work normally, if normal, corresponding element of array pstTaskInfo's member variable cIsAttached
|
||||
will change from 0 to 1.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/*
|
||||
s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s32 iDoPtraceCheck)函数是用于检查指定进程的跟踪状态是否正常的函数。
|
||||
|
||||
首先检查pstTaskInfo和iPidCount是否合法,如果不合法则返回指定的错误码。
|
||||
使用循环遍历pstTaskInfo数组中的每个任务。
|
||||
使用sys_ptrace函数将指定任务的跟踪状态设置为跟踪状态。
|
||||
使用sys_waitpid函数等待指定任务结束。
|
||||
如果等待失败并且错误码不是EINTR,则输出错误信息,然后使用sys_ptrace函数将跟踪状态取消。
|
||||
如果iDoPtraceCheck为真,则使用sys_ptrace函数检查跟踪状态是否有效。
|
||||
如果检查失败,输出错误信息并取消跟踪状态。
|
||||
将任务的cIsAttached成员变量设置为已跟踪状态。
|
||||
返回正常执行的结果码。
|
||||
*/
|
||||
s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s32 iDoPtraceCheck)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -272,13 +347,18 @@ s32 BBOX_PtraceAttachPid(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount, s3
|
|||
}
|
||||
|
||||
/*
|
||||
* cancel ptrace debug thread
|
||||
* in : TASK_ATTACH_INFO - thread information
|
||||
* iPidCount - count of thread information
|
||||
* iDoPtraceCheck - check if ptrace success
|
||||
* return : 0 - success
|
||||
* err code - failed
|
||||
*/
|
||||
function name: BBOX_DetachAllThread
|
||||
description: The function is used to cancel checking the process whose id stored in structure array pstTaskInfo
|
||||
work normally, "work normally" means in array pstTaskInfo corresponding element's member
|
||||
variable cIsAttached's value is 1.
|
||||
arguments: The first argument is a structure pointer named pstTaskInfo,its type is struct TASK_ATTACH_INFO*,
|
||||
it is used as a structure array that has stored requisite thread infomation, the next argument destines
|
||||
the size of the array that the first argument destines, namely how many elements the array has.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
void BBOX_DetachAllThread(struct TASK_ATTACH_INFO* pstTaskInfo, s32 iPidCount)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -323,26 +403,38 @@ void BBOX_CheckResumeThread(void* pArgs)
|
|||
}
|
||||
|
||||
/*
|
||||
* ptrace thread and run function.
|
||||
* in : pstArgs - information of callback function
|
||||
* iMaxThreadCount - max count of thread
|
||||
* pszProcSelfTask - /proc/[pid]/task of current tracked thread.
|
||||
* return 0 if success else err code.
|
||||
*/
|
||||
function name: BBOX_PtraceAndRun
|
||||
description: When get a path to specific process, this function will trace the threads below it, and get the
|
||||
information for example how many threads work normally then store it in pstArgs.
|
||||
arguments: The first argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
|
||||
what matters is its member variable callback function pointer, the next argument destines
|
||||
the max count of the thread. The last argument is a pointer of type char*, including a path
|
||||
to specific process.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/*
|
||||
这段代码是一个函数,接受一个指向结构体BBOX_ListParams的指针pstArgs、一个最大线程数量iMaxThreadCount和一个指向char类型的指针pszProcSelfTask作为参数。
|
||||
代码的作用是使用ptrace操作来追踪并运行线程。
|
||||
*/
|
||||
s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char* pszProcSelfTask)
|
||||
{
|
||||
struct TASK_ATTACH_INFO stTaskInfo[iMaxThreadCount];
|
||||
pid_t thread_pids[iMaxThreadCount];
|
||||
// 声明一些变量
|
||||
struct TASK_ATTACH_INFO stTaskInfo[iMaxThreadCount]; // 存储线程信息的数组
|
||||
pid_t thread_pids[iMaxThreadCount]; // 存储线程PID的数组
|
||||
|
||||
struct TASK_CHECK_RESUME_ARGS stTaskCheck; // 追踪线程所需参数
|
||||
s32 iThreadCount = 0; // 线程数量
|
||||
s32 iAttachCount = 0; // 被追踪的线程数量
|
||||
s32 iRet = 0; // 返回值变量
|
||||
s32 iDoPtraceCheck = 1; // 是否需要使用ptrace检查
|
||||
|
||||
struct TASK_CHECK_RESUME_ARGS stTaskCheck;
|
||||
s32 iThreadCount = 0;
|
||||
s32 iAttachCount = 0;
|
||||
s32 iRet = 0;
|
||||
s32 iDoPtraceCheck = 1;
|
||||
s32 i;
|
||||
|
||||
if (pstArgs == NULL || pszProcSelfTask == NULL || iMaxThreadCount <= 0) {
|
||||
|
||||
// 参数检查,如果参数无效则打印错误信息并返回错误码
|
||||
if (pstArgs == NULL || pszProcSelfTask == NULL || iMax 线程数量小于等于0) {
|
||||
bbox_print(PRINT_ERR,
|
||||
"Parameter is invald, pstArgs or pszProcSelfTask is NULL, iMaxThreadCount = %d \n",
|
||||
iMaxThreadCount);
|
||||
|
|
@ -350,6 +442,7 @@ s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char
|
|||
return RET_ERR;
|
||||
}
|
||||
|
||||
// 初始化stTaskInfo、thread_pids和stTaskCheck为0
|
||||
errno_t rc = memset_s(stTaskInfo, sizeof(stTaskInfo), 0, sizeof(stTaskInfo));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
rc = memset_s(thread_pids, sizeof(thread_pids), 0, sizeof(thread_pids));
|
||||
|
|
@ -357,6 +450,7 @@ s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char
|
|||
rc = memset_s(&stTaskCheck, sizeof(stTaskCheck), 0, sizeof(stTaskCheck));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
|
||||
// 获取线程数量
|
||||
iThreadCount = BBOX_GetTaskId(stTaskInfo, iMaxThreadCount, pszProcSelfTask);
|
||||
if (iThreadCount <= 0) {
|
||||
bbox_print(PRINT_ERR, "Get task id failed.\n");
|
||||
|
|
@ -364,19 +458,21 @@ s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char
|
|||
goto errout;
|
||||
}
|
||||
|
||||
// 根据pstArgs的enGetType判断是否需要使用ptrace检查
|
||||
if (GET_TYPE_DUMP != pstArgs->enGetType) {
|
||||
iDoPtraceCheck = 0;
|
||||
} else {
|
||||
iDoPtraceCheck = 1;
|
||||
}
|
||||
|
||||
// 使用BBOX_PtraceAttachPid函数对线程进行ptrace追踪
|
||||
iRet = BBOX_PtraceAttachPid(stTaskInfo, iThreadCount, iDoPtraceCheck);
|
||||
if (iRet != RET_OK) {
|
||||
bbox_print(PRINT_ERR, "Ptrace attache failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* copy information of thread that have been attaching. */
|
||||
// 将已经被追踪的线程的PID复制到thread_pids数组中
|
||||
for (i = 0; i < iThreadCount; i++) {
|
||||
if (!stTaskInfo[i].cIsAttached) {
|
||||
continue;
|
||||
|
|
@ -385,113 +481,148 @@ s32 BBOX_PtraceAndRun(struct BBOX_ListParams* pstArgs, s32 iMaxThreadCount, char
|
|||
iAttachCount++;
|
||||
}
|
||||
|
||||
// 设置stTaskCheck的相应参数
|
||||
stTaskCheck.pstTaskInfo = stTaskInfo;
|
||||
stTaskCheck.enType = pstArgs->enGetType;
|
||||
stTaskCheck.iThreadCount = iThreadCount;
|
||||
|
||||
/* run call back function. */
|
||||
// 调用回调函数进行处理
|
||||
bbox_print(PRINT_TIP, "Thread count :%d\n", iThreadCount);
|
||||
bbox_print(PRINT_TIP, "Ptraced thread count :%d\n", iAttachCount);
|
||||
bbox_print(PRINT_LOG, "Run callback: thread count = %d\n", iThreadCount);
|
||||
/* Callback to the thread information handler. */
|
||||
// 调用线程信息处理函数的回调函数
|
||||
pstArgs->iResult = pstArgs->pCallBack(BBOX_CheckResumeThread, &stTaskCheck, iAttachCount, thread_pids, pstArgs->ap);
|
||||
pstArgs->iError = errno;
|
||||
|
||||
// 解除所有线程的追踪
|
||||
BBOX_DetachAllThread(stTaskInfo, iThreadCount);
|
||||
|
||||
return RET_OK;
|
||||
|
||||
errout:
|
||||
// 出错情况下也需要解除所有线程的追踪
|
||||
BBOX_DetachAllThread(stTaskInfo, iThreadCount);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/*
|
||||
* print log information if export failed.
|
||||
*/
|
||||
function name: BBOX_PrintFailedLog
|
||||
description: Write log infomation into specific file, if errors arise, print the infomation about errors.
|
||||
arguments: The only argument is a pointer of type const char* to a filename string, if this file doesn't
|
||||
exist, we will creat a new file named it.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/*
|
||||
这段代码是一个函数,接受一个指向char类型的指针pFileName作为参数。代码的作用是将全局变量g_acBBoxLog中的内容输出到文件中。
|
||||
*/
|
||||
// 函数声明:将全局变量g_acBBoxLog中的内容输出到文件中
|
||||
void BBOX_PrintFailedLog(const char* pFileName)
|
||||
{
|
||||
ssize_t iRet = 0;
|
||||
s32 iWriteSize = 0;
|
||||
s32 iBboxLogFd = -1;
|
||||
ssize_t iRet = 0; // 返回值变量
|
||||
s32 iWriteSize = 0; // 写入的数据大小变量
|
||||
s32 iBboxLogFd = -1; // 文件描述符变量,初始化为-1
|
||||
|
||||
// 使用sys_open函数打开文件,以可读写和创建方式打开,文件的访问权限为0600
|
||||
iBboxLogFd = sys_open(pFileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
if (iBboxLogFd < 0) {
|
||||
|
||||
bbox_print(PRINT_ERR, "open failed, errno = %d\n", errno);
|
||||
bbox_print(PRINT_ERR, "open failed, errno = %d\n", errno); // 打印错误信息
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算要写入的数据大小
|
||||
iWriteSize = bbox_strnlen(g_acBBoxLog, BBOX_LOG_SIZE) + 1;
|
||||
iWriteSize = (iWriteSize > BBOX_LOG_SIZE) ? BBOX_LOG_SIZE : iWriteSize;
|
||||
|
||||
// 使用sys_write函数将g_acBBoxLog中的内容写入到文件中
|
||||
iRet = sys_write(iBboxLogFd, g_acBBoxLog, iWriteSize);
|
||||
if (iRet < 0) {
|
||||
bbox_print(PRINT_ERR, "write failed, errno = %d\n", errno);
|
||||
bbox_print(PRINT_ERR, "write failed, errno = %d\n", errno); // 打印错误信息
|
||||
|
||||
sys_close(iBboxLogFd);
|
||||
sys_close(iBboxLogFd); // 关闭文件描述符
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用sys_close函数关闭文件描述符
|
||||
sys_close(iBboxLogFd);
|
||||
}
|
||||
|
||||
/*
|
||||
* export thread information.
|
||||
*/
|
||||
function name: BBOX_ListThread
|
||||
description: Export thread information.
|
||||
arguments: The only argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
|
||||
what matters is its member variable callback function pointer and thread infomation.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
// 函数声明:获取进程的信息并进行一系列操作
|
||||
void BBOX_ListThread(struct BBOX_ListParams* pstArgs)
|
||||
{
|
||||
pid_t ppid = 0;
|
||||
s32 iMaker = -1;
|
||||
s32 iMaxThreadCount = 0;
|
||||
s32 iRet = 0;
|
||||
pid_t ppid = 0; // 父进程的进程ID
|
||||
s32 iMaker = -1; // socket的文件描述符,初始化为-1
|
||||
s32 iMaxThreadCount = 0; // 最大线程数,初始化为0
|
||||
s32 iRet = 0; // 返回值变量
|
||||
|
||||
struct kernel_stat stMarkerSB;
|
||||
char szProcSelfTask[BBOX_PROC_PATH_LEN];
|
||||
char pszMarkPath[BBOX_PROC_PATH_LEN];
|
||||
stack_t altstack;
|
||||
errno_t rc = EOK;
|
||||
struct kernel_stat stMarkerSB; // 文件状态结构体
|
||||
char szProcSelfTask[BBOX_PROC_PATH_LEN]; // 存放进程任务路径的数组
|
||||
char pszMarkPath[BBOX_PROC_PATH_LEN]; // 存放标记路径的数组
|
||||
stack_t altstack; // 备用信号栈结构体
|
||||
errno_t rc = EOK; // 错误号变量,初始化为EOK
|
||||
|
||||
// 如果pstArgs为空指针,则打印错误信息并返回
|
||||
if (pstArgs == NULL) {
|
||||
bbox_print(PRINT_ERR, "pstArgs is NULL.\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取父进程的进程ID
|
||||
ppid = sys_getppid();
|
||||
|
||||
// 创建一个socket,使用本地通信的地址族,数据报套接字类型,协议为0(自动选择协议)
|
||||
iMaker = sys_socket(PF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (iMaker < 0) {
|
||||
bbox_print(PRINT_ERR, "sys_socket error, errno = %d\n", errno);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
// 设置socket的关闭执行标记为FD_CLOEXEC,确保在exec族函数调用时关闭socket
|
||||
if (sys_fcntl(iMaker, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
bbox_print(PRINT_ERR, "sys_fcntl error, errno = %d\n", errno);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
// 使用bbox_snprintf函数将父进程的任务路径写入szProcSelfTask数组中
|
||||
if (bbox_snprintf(szProcSelfTask, BBOX_PROC_PATH_LEN, "/proc/%d/task", ppid) <= 0) {
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
// 使用bbox_snprintf函数将标记路径写入pszMarkPath数组中
|
||||
if (bbox_snprintf(pszMarkPath, BBOX_PROC_PATH_LEN, "/proc/%d/fd/%d", ppid, iMaker) <= 0) {
|
||||
bbox_print(PRINT_ERR, "bbox_snprintf is failed, errno = %d.\n", errno);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
// 打印提示信息,显示正在获取pid为ppid的进程的信息
|
||||
bbox_print(PRINT_TIP, "Get information for pid %d:\n", ppid);
|
||||
|
||||
// 使用memset_s函数将stMarkerSB结构体清零
|
||||
rc = memset_s(&stMarkerSB, sizeof(stMarkerSB), 0, sizeof(stMarkerSB));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
|
||||
// 使用sys_stat函数获取pszMarkPath对应文件的状态信息并保存到stMarkerSB结构体中
|
||||
if (sys_stat(pszMarkPath, &stMarkerSB) < 0) {
|
||||
bbox_print(PRINT_ERR, "sys_stat error, errno = %d, path = %s\n", errno, pszMarkPath);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* switch stack pointer */
|
||||
// 切换栈指针为备用信号栈
|
||||
rc = memset_s(&altstack, sizeof(altstack), 0, sizeof(altstack));
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
altstack.ss_sp = pstArgs->pAltStackMem;
|
||||
|
|
@ -499,57 +630,79 @@ void BBOX_ListThread(struct BBOX_ListParams* pstArgs)
|
|||
altstack.ss_size = BBOX_ALT_STACKSIZE;
|
||||
sys_sigaltstack(&altstack, (const stack_t*)NULL);
|
||||
|
||||
/* get max count of task. */
|
||||
// 获取进程的最大线程数
|
||||
iMaxThreadCount = BBOX_GetTaskNumber(szProcSelfTask);
|
||||
if (iMaxThreadCount <= 0) {
|
||||
bbox_print(PRINT_ERR, "Get task number failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* ptrace and run thread. */
|
||||
// 对线程执行ptrace并运行
|
||||
iRet = BBOX_PtraceAndRun(pstArgs, iMaxThreadCount, szProcSelfTask);
|
||||
if (iRet != RET_OK) {
|
||||
bbox_print(PRINT_ERR, "ptrace task and run failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
// 打印提示信息,获取信息成功
|
||||
bbox_print(PRINT_TIP, "Get information success.\n");
|
||||
|
||||
// 关闭socket
|
||||
sys_close(iMaker);
|
||||
|
||||
// 如果pstArgs的结果不等于RET_OK,则调用BBOX_PrintFailedLog函数打印失败日志
|
||||
if (RET_OK != pstArgs->iResult) {
|
||||
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
|
||||
}
|
||||
|
||||
// 如果pstArgs的回调函数不为空,则调用回调函数
|
||||
if (pstArgs->pDoneCallback != NULL) {
|
||||
pstArgs->pDoneCallback(pstArgs->pDoneArgs);
|
||||
}
|
||||
|
||||
// 退出线程,返回值为0
|
||||
sys_exit(0);
|
||||
|
||||
// 错误处理
|
||||
errout:
|
||||
if (iMaker > 0) {
|
||||
sys_close(iMaker);
|
||||
}
|
||||
|
||||
// 打印错误信息
|
||||
bbox_print(PRINT_ERR, "Get information failed.\n");
|
||||
|
||||
// 设置pstArgs的结果为-1并保存错误号
|
||||
pstArgs->iResult = -1;
|
||||
pstArgs->iError = errno;
|
||||
|
||||
// 调用BBOX_PrintFailedLog函数打印失败日志
|
||||
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
|
||||
|
||||
// 如果pstArgs的回调函数不为空,则调用回调函数
|
||||
if (pstArgs->pDoneCallback != NULL) {
|
||||
pstArgs->pDoneCallback(pstArgs->pDoneArgs);
|
||||
}
|
||||
|
||||
// 退出线程,返回值为1
|
||||
sys_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* get return value of child process
|
||||
* in : iClonePid - PID of child process
|
||||
* pstArgs - parameter
|
||||
* iCloneErrno - err code
|
||||
* return 0 if success else failed.
|
||||
function name: BBOX_GetClonePidResult
|
||||
description: The function get the status of child process at first, then according to it assign pstArgs's
|
||||
member variables iError and iResult appropriate values.
|
||||
arguments: The first argument is a integer named iClonePid, it represents the pid of child process.
|
||||
The second argument is a structure pointer named pstArgs, its type is struct BBOX_ListParams*,
|
||||
what matters is its member variable callback function pointer and thread infomation.
|
||||
The third argument is a integer indicating error code.
|
||||
return value: An integer, if function work normally, the value is RET_OK, else is RET_ERR.
|
||||
note: none
|
||||
date: 2022/8/3
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/*
|
||||
* 获取克隆进程的结果并处理
|
||||
*/
|
||||
s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32 iCloneErrno)
|
||||
{
|
||||
|
|
@ -558,7 +711,7 @@ s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32
|
|||
|
||||
if (iClonePid < 0) {
|
||||
|
||||
bbox_print(PRINT_ERR, "Clone failed, can't create child process, errno = %d.\n", iCloneErrno);
|
||||
bbox_print(PRINT_ERR, "克隆进程失败,无法创建子进程,errno = %d。\n", iCloneErrno);
|
||||
|
||||
BBOX_PrintFailedLog((char*)(((struct BBOX_ListDirParam*)(pstArgs->pDoneArgs))->pArg2));
|
||||
if (pstArgs->pDoneCallback != NULL) {
|
||||
|
|
@ -568,12 +721,12 @@ s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32
|
|||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* wait child process exit. */
|
||||
/* 等待子进程退出 */
|
||||
while ((iRet = sys_waitpid(iClonePid, &iStatus, __WALL)) < 0 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bbox_print(PRINT_LOG, "clone pid %d ret is %x, status = %x\n", iClonePid, iRet, WIFEXITED(iStatus));
|
||||
bbox_print(PRINT_LOG, "克隆进程的pid %d 返回值为 %x,状态为 %x\n", iClonePid, iRet, WIFEXITED(iStatus));
|
||||
|
||||
if (iRet < 0) {
|
||||
pstArgs->iError = errno;
|
||||
|
|
@ -598,21 +751,22 @@ s32 BBOX_GetClonePidResult(pid_t iClonePid, struct BBOX_ListParams* pstArgs, s32
|
|||
} else if (!WIFEXITED(iStatus)) {
|
||||
pstArgs->iError = EFAULT;
|
||||
pstArgs->iResult = -1;
|
||||
bbox_print(PRINT_ERR, "WIFEXITED status failed");
|
||||
bbox_print(PRINT_ERR, "WIFEXITED 状态判断失败");
|
||||
} else {
|
||||
pstArgs->iError = iCloneErrno;
|
||||
pstArgs->iResult = -1;
|
||||
bbox_print(PRINT_ERR, "WIFEXITED error, errno = %d\n", iCloneErrno);
|
||||
bbox_print(PRINT_ERR, "WIFEXITED 错误,errno = %d\n", iCloneErrno);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* get all threads and run specify function
|
||||
*/
|
||||
s32 BBOX_GetAllThreads(
|
||||
GET_THREAD_TYPE enType, BBOX_GetAllThreadDone pDone, void* pDoneArgs, BBOX_GetAllThreadsCallBack pCallback, ...)
|
||||
/*
|
||||
* 获取所有线程并运行指定函数
|
||||
*/
|
||||
s32 BBOX_GetAllThreads(GET_THREAD_TYPE enType, BBOX_GetAllThreadDone pDone, void* pDoneArgs, BBOX_GetAllThreadsCallBack pCallback, ...)
|
||||
{
|
||||
struct BBOX_ListParams stArgs;
|
||||
struct kernel_sigset_t stSigBlocked;
|
||||
|
|
@ -627,14 +781,14 @@ s32 BBOX_GetAllThreads(
|
|||
if (BBOX_AtomicIncReturn(&g_isBusy) > 1) {
|
||||
BBOX_AtomicDec(&g_isBusy);
|
||||
|
||||
bbox_print(PRINT_ERR, "Dump task is running.\n");
|
||||
bbox_print(PRINT_ERR, "Dump任务正在运行中。\n");
|
||||
|
||||
errno = EALREADY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (enType >= GET_TYPE_BUTT || pCallback == NULL) {
|
||||
bbox_print(PRINT_ERR, "Parameter is invalid, enType = %d, and maybe pCallback is NULL", enType);
|
||||
bbox_print(PRINT_ERR, "参数无效,enType = %d,可能 pCallback 为空", enType);
|
||||
BBOX_AtomicDec(&g_isBusy);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -648,19 +802,19 @@ s32 BBOX_GetAllThreads(
|
|||
|
||||
va_start(stArgs.ap, pCallback);
|
||||
|
||||
/* clear new stack */
|
||||
/* 清空新栈 */
|
||||
rc = memset_s(g_szAltStackMem, BBOX_ALT_STACKSIZE, 0, BBOX_ALT_STACKSIZE);
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
/* reserve 32K */
|
||||
/* 保留 32K */
|
||||
BBOX_ReserveZeroStack(1024 * 32);
|
||||
|
||||
/* check and set dump flag. */
|
||||
/* 检查并设置dump标志 */
|
||||
iDumpable = sys_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
|
||||
if (!iDumpable) {
|
||||
sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* set start parameter of dump thread. */
|
||||
/* 设置dump线程的启动参数 */
|
||||
stArgs.iResult = -1;
|
||||
stArgs.iError = 0;
|
||||
stArgs.pAltStackMem = g_szAltStackMem;
|
||||
|
|
@ -669,36 +823,35 @@ s32 BBOX_GetAllThreads(
|
|||
stArgs.pDoneArgs = pDoneArgs;
|
||||
stArgs.enGetType = enType;
|
||||
|
||||
/* suspend all signals */
|
||||
/* 暂停所有信号 */
|
||||
sys_sigfillset(&stSigBlocked);
|
||||
for (iSigNo = 0; iSigNo < (s32)(sizeof(iSyncSignals) / sizeof(*iSyncSignals)); iSigNo++) {
|
||||
sys_sigdelset(&stSigBlocked, iSyncSignals[iSigNo]);
|
||||
}
|
||||
|
||||
/* block all signals */
|
||||
/* 阻塞所有信号 */
|
||||
if (sys_sigprocmask(SIG_BLOCK, &stSigBlocked, &stSigOld)) {
|
||||
stArgs.iError = errno;
|
||||
stArgs.iResult = -1;
|
||||
bbox_print(PRINT_ERR, "sys_sigprocmask error, errno = %d\n", errno);
|
||||
bbox_print(PRINT_ERR, "sys_sigprocmask 错误,errno = %d\n", errno);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* create child process and run function to export thread information. */
|
||||
/* 创建子进程并运行导出线程信息的函数 */
|
||||
if (GET_TYPE_DUMP == enType) {
|
||||
|
||||
ClonePid = BBOX_CloneRun(CLONE_VM | CLONE_FS | CLONE_FILES, (s32(*)(void*))BBOX_ListThread, &stArgs);
|
||||
} else {
|
||||
/* copy VMA if type is snapshoot. */
|
||||
/* 如果类型是快照,则复制VMA */
|
||||
ClonePid = BBOX_CloneRun(CLONE_FS | CLONE_FILES, (s32(*)(void*))BBOX_ListThread, &stArgs);
|
||||
}
|
||||
|
||||
iCloneErrno = errno;
|
||||
|
||||
/* restoring signal */
|
||||
/* 恢复信号 */
|
||||
sys_sigprocmask(SIG_SETMASK, &stSigOld, &stSigOld);
|
||||
|
||||
if (BBOX_GetClonePidResult(ClonePid, &stArgs, iCloneErrno) != RET_OK) {
|
||||
bbox_print(PRINT_ERR, "BBOX_GetClonePidResult error\n");
|
||||
bbox_print(PRINT_ERR, "BBOX_GetClonePidResult 错误\n");
|
||||
}
|
||||
|
||||
errout:
|
||||
|
|
|
|||
|
|
@ -57,35 +57,83 @@ BlacklistItem g_blacklist_items[] = {
|
|||
{DATA_WRITER_QUEUE, "DATA_WRITER_QUEUE", false}
|
||||
};
|
||||
|
||||
static void coredump_handler(int sig, siginfo_t *si, void *uc)
|
||||
{
|
||||
/*
|
||||
function name: coredump_handler
|
||||
description: When a program is abnormal, but the exception appears in the core of process and wasn't caught,
|
||||
The function will generate a file to store the information about memory of process, status of register
|
||||
and running stack.
|
||||
arguments: The first argument is an integer indicating signal code that usually used in program of processing
|
||||
signal as variable.
|
||||
The second argument is a structure pointer of type siginfo_t*, the memory that this pointer
|
||||
directs stores comprehensive information about signal, for example, which process sends
|
||||
and which user sends.
|
||||
The third argument is a pointer of type void*, other kinds of pointers can directly used here.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/**
|
||||
* 此函数是用于核心转储信号的信号处理器。
|
||||
* 在接收到核心转储信号时,将调用此函数。
|
||||
*
|
||||
* 参数:
|
||||
* - sig:信号编号
|
||||
* - si:指向一个结构的指针,包含有关信号的附加信息
|
||||
* - uc:指向一个结构的指针,包含信号被触发时的机器上下文
|
||||
*/
|
||||
static void coredump_handler(int sig, siginfo_t *si, void *uc) {
|
||||
// 此变量存储第一个遇到致命错误的线程的线程ID。
|
||||
static volatile int64 first_tid = INVALID_TID;
|
||||
|
||||
// 获取当前线程的线程ID。
|
||||
int64 cur_tid = (int64)pthread_self();
|
||||
|
||||
// 检查是否为任何线程首次遇到的致命错误。
|
||||
if (first_tid == INVALID_TID &&
|
||||
__sync_bool_compare_and_swap(&first_tid, INVALID_TID, cur_tid)) {
|
||||
/* Only first fatal error will set db state and generate fatal error log */
|
||||
/* 只有首个致命错误会设置数据库状态并生成致命错误日志 */
|
||||
// 将数据库状态文件设置为 COREDUMP_STATE,表示发生了核心转储。
|
||||
(void)SetDBStateFileState(COREDUMP_STATE, false);
|
||||
|
||||
// 如果启用了 FFIC 日志,则生成一个错误消息。
|
||||
if (g_instance.attr.attr_common.enable_ffic_log) {
|
||||
(void)gen_err_msg(sig, si, (ucontext_t *)uc);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Subsequent fatal error will go to here. If it comes from different thread,
|
||||
* wait until first error handler end, and if it is a reentry, terminate process.
|
||||
* 后续的致命错误将进入此处。如果来自不同的线程,
|
||||
* 则等待第一个错误处理器结束,如果是重新进入,则终止进程。
|
||||
*/
|
||||
|
||||
// 如果这不是第一个致命错误并且来自不同的线程,
|
||||
// 则等待第一个错误处理器结束,如果是重新进入,则终止进程。
|
||||
if (first_tid != cur_tid) {
|
||||
(void)pause();
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复信号的默认处理器。
|
||||
(void)pqsignal(sig, SIG_DFL);
|
||||
|
||||
// 再次触发该信号,以调用默认的信号处理器。
|
||||
(void)raise(sig);
|
||||
}
|
||||
|
||||
/*
|
||||
* bbox_handler - handle signal conditions for bbox
|
||||
*/
|
||||
function name: bbox_handler
|
||||
description: Handle signal conditions for bbox.
|
||||
arguments: The first argument is an integer indicating signal code that usually used in program of processing
|
||||
signal as variable.
|
||||
The second argument is a structure pointer of type siginfo_t*, the memory that this pointer
|
||||
directs stores comprehensive information about signal, for example, which process sends
|
||||
and which user sends.
|
||||
The third argument is a pointer of type void*, other kinds of pointers can directly used here.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
static void bbox_handler(int sig, siginfo_t *si, void *uc)
|
||||
{
|
||||
static volatile int64 first_tid = INVALID_TID;
|
||||
|
|
@ -125,53 +173,88 @@ static void bbox_handler(int sig, siginfo_t *si, void *uc)
|
|||
}
|
||||
|
||||
/*
|
||||
* get_bbox_coredump_pattern_path - get the core dump path from the file "/proc/sys/kernel/core_pattern"
|
||||
function name: get_bbox_coredump_pattern_path
|
||||
description: Get the core dump file's path from the file "/proc/sys/kernel/core_pattern".
|
||||
arguments: The first argument is a pointer to string, we use it to store core dump file's path acquired
|
||||
from the file "/proc/sys/kernel/core_pattern", the next argument is the number of characters
|
||||
reading from the file "/proc/sys/kernel/core_pattern", all len-1 characters or less if appear '\n'.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/**
|
||||
* 此函数用于获取核心转储模式的路径。
|
||||
*
|
||||
* 参数:
|
||||
* - path:用于存储核心转储模式路径的缓冲区
|
||||
* - len:缓冲区的大小
|
||||
*/
|
||||
static void get_bbox_coredump_pattern_path(char* path, Size len)
|
||||
{
|
||||
static void get_bbox_coredump_pattern_path(char* path, Size len) {
|
||||
FILE* fp = NULL;
|
||||
char* p = NULL;
|
||||
struct stat stat_buf;
|
||||
|
||||
if ((fp = fopen("/proc/sys/kernel/core_pattern", "r")) == NULL) {
|
||||
write_stderr("cannot open file: /proc/sys/kernel/core_pattern.\n");
|
||||
// 打开文件失败,写入错误提示信息,并返回。
|
||||
write_stderr("无法打开文件:/proc/sys/kernel/core_pattern。\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fgets(path, len, fp) == NULL) {
|
||||
// 获取核心模式路径失败,关闭文件,写入错误提示信息,并返回。
|
||||
fclose(fp);
|
||||
write_stderr("failed to get the core pattern path.\n ");
|
||||
write_stderr("无法获取核心模式路径。\n");
|
||||
return;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if ((p = strrchr(path, '/')) == NULL) { /* a relative-path file */
|
||||
if ((p = strrchr(path, '/')) == NULL) { /* 相对路径文件 */
|
||||
*path = '\0';
|
||||
} else { /* an absolute-path file */
|
||||
} else { /* 绝对路径文件 */
|
||||
*(++p) = '\0';
|
||||
// 检查路径是否有效并且具有写权限。
|
||||
if (stat(path, &stat_buf) != 0 || !S_ISDIR(stat_buf.st_mode) || access(path, W_OK) != 0) {
|
||||
write_stderr("The core dump path is an invalid directory\n");
|
||||
// 核心转储路径是无效的目录,写入错误提示信息,并清空路径。
|
||||
write_stderr("核心转储路径是无效的目录。\n");
|
||||
*path = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* compute directory into which bbox dump core files are saved. */
|
||||
static void build_bbox_corepath(char *bbox_core_path, Size path_size, char *config_path)
|
||||
{
|
||||
/*
|
||||
function name: build_bbox_corepath
|
||||
description: Get the core dump file's path.
|
||||
arguments: The first argument is a pointer to string, we use it to store core dump file's path,
|
||||
the next argument is the size of the path's name, the last argument is a pointer
|
||||
to string that indicates maybe store a path to configure the core dump file.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/**
|
||||
* 此函数用于构建 bbox 核心转储路径。
|
||||
*
|
||||
* 参数:
|
||||
* - bbox_core_path:用于存储 bbox 核心转储路径的缓冲区
|
||||
* - path_size:缓冲区的大小
|
||||
* - config_path:指定的配置路径,如果为 NULL,则使用默认路径
|
||||
*/
|
||||
static void build_bbox_corepath(char *bbox_core_path, Size path_size, char *config_path) {
|
||||
struct stat stat_buf;
|
||||
|
||||
/*
|
||||
* the guc parameter bbox_dump_path is set to NULL as default.
|
||||
* bbox_dump_path has to be a valid directory, if it is altered by users.
|
||||
* 默认情况下,guc 参数 bbox_dump_path 设置为 NULL。
|
||||
* 如果用户修改了 bbox_dump_path,它必须是一个有效的目录。
|
||||
*/
|
||||
if (config_path != NULL && config_path[0] != '\0') {
|
||||
if (stat(config_path, &stat_buf) != 0 || !S_ISDIR(stat_buf.st_mode) || access(config_path, W_OK) != 0) {
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("bbox_dump_path %s is an invalid directory!\n", config_path)));
|
||||
errmsg("bbox_dump_path %s 是一个无效的目录!\n", config_path)));
|
||||
|
||||
/* if bbox_dump_path is invalid, the path of core dump will be set as default. */
|
||||
/* 如果 bbox_dump_path 是无效的,将使用默认的核心转储路径。 */
|
||||
get_bbox_coredump_pattern_path(bbox_core_path, path_size);
|
||||
} else {
|
||||
errno_t rc = strcpy_s(bbox_core_path, path_size, config_path);
|
||||
|
|
@ -179,29 +262,27 @@ static void build_bbox_corepath(char *bbox_core_path, Size path_size, char *conf
|
|||
}
|
||||
} else {
|
||||
/*
|
||||
* default path of the core dump will be obtained
|
||||
* by reading the file "/proc/sys/kernel/core_pattern"
|
||||
* 默认情况下,核心转储路径将从文件 "/proc/sys/kernel/core_pattern" 中获取。
|
||||
*/
|
||||
get_bbox_coredump_pattern_path(bbox_core_path, path_size);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check_bbox_corepath - check coredump path for bbox
|
||||
* check_bbox_corepath - 检查 bbox 的核心转储路径
|
||||
*/
|
||||
bool check_bbox_corepath(char** newval, void** extra, GucSource source)
|
||||
{
|
||||
bool check_bbox_corepath(char** newval, void** extra, GucSource source) {
|
||||
if (t_thrd.proc_cxt.MyProcPid != PostmasterPid)
|
||||
return true;
|
||||
|
||||
char core_dump_path[BBOX_PATH_SIZE] = {0};
|
||||
|
||||
/* determine which path is used for bbox core dump file */
|
||||
/* 确定用于 bbox 核心转储文件的路径 */
|
||||
build_bbox_corepath(core_dump_path, sizeof(core_dump_path), (newval != NULL) ? *newval : NULL);
|
||||
|
||||
if (core_dump_path[0] != '\0' && BBOX_SetCoredumpPath(core_dump_path) == RET_OK) {
|
||||
ereport(LOG,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("bbox_dump_path is set to %s", core_dump_path)));
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("bbox_dump_path 设置为 %s", core_dump_path)));
|
||||
}
|
||||
|
||||
char* result = (char*)MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DFX), BBOX_PATH_SIZE);
|
||||
|
|
@ -232,6 +313,15 @@ void assign_bbox_corepath(const char* newval, void* extra)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: show_bbox_dump_path
|
||||
description: Get the dump file's path.
|
||||
arguments: void
|
||||
return value: A pointer of type const char*, directing the path to dump or NULL.
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
const char* show_bbox_dump_path(void)
|
||||
{
|
||||
const char* path = g_bbox_dump_path;
|
||||
|
|
@ -239,40 +329,68 @@ const char* show_bbox_dump_path(void)
|
|||
return (path != NULL) ? path : "";
|
||||
}
|
||||
|
||||
/*
|
||||
function name: split_string_into_blacklist
|
||||
description: Get all strings been divided into character ',' in source string.
|
||||
arguments: A pointer of type const char*, directing the source string.
|
||||
return value: A pointer of type static List*.
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
/**
|
||||
* 将一个字符串拆分为黑名单列表。
|
||||
*
|
||||
* 参数:
|
||||
* - source:要拆分的源字符串
|
||||
*
|
||||
* 返回值:
|
||||
* - 拆分后的黑名单列表
|
||||
*/
|
||||
static List* split_string_into_blacklist(const char* source)
|
||||
{
|
||||
List *result = NIL;
|
||||
char *str = pstrdup(source);
|
||||
char *first_ch = str;
|
||||
int len = strlen(str) + 1;
|
||||
List *result = NIL; // 初始化列表为空
|
||||
char *str = pstrdup(source); // 复制源字符串
|
||||
char *first_ch = str; // 指向第一个字符的指针
|
||||
int len = strlen(str) + 1; // 字符串长度加1,包括结尾的空字符
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (str[i] == ',' || str[i] == '\0') {
|
||||
/* replace ',' with '\0'. */
|
||||
/* 将 ',' 替换为 '\0' */
|
||||
str[i] = '\0';
|
||||
|
||||
/* copy this into result. */
|
||||
/* 将该字符串添加到结果列表中 */
|
||||
result = lappend(result, pstrdup(first_ch));
|
||||
|
||||
/* move to the head of next string. */
|
||||
/* 移动到下一个字符串的开头 */
|
||||
first_ch = str + i + 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
pfree(str);
|
||||
pfree(str); // 释放复制的字符串内存
|
||||
|
||||
return result;
|
||||
return result; // 返回拆分后的黑名单列表
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查 bbox 黑名单配置项。
|
||||
*
|
||||
* 参数:
|
||||
* - newval:新设置的值
|
||||
* - extra:附加信息
|
||||
* - source:配置项的来源
|
||||
*
|
||||
* 返回值:
|
||||
* - 如果检查通过,返回 true;否则返回 false
|
||||
*/
|
||||
bool check_bbox_blacklist(char** newval, void** extra, GucSource source)
|
||||
{
|
||||
if (t_thrd.proc_cxt.MyProcPid != PostmasterPid)
|
||||
return true;
|
||||
|
||||
List *result = split_string_into_blacklist(*newval);
|
||||
List *result = split_string_into_blacklist(*newval); // 将配置项的值拆分为黑名单列表
|
||||
ListCell *lc = NULL;
|
||||
uint64 mask = 0;
|
||||
uint64 mask = 0; // 用于保存黑名单掩码
|
||||
size_t i;
|
||||
|
||||
foreach(lc, result) {
|
||||
|
|
@ -287,45 +405,62 @@ bool check_bbox_blacklist(char** newval, void** extra, GucSource source)
|
|||
}
|
||||
if (i == sizeof(g_blacklist_items) / sizeof(BlacklistItem)) {
|
||||
ereport(WARNING,
|
||||
(errmsg("blacklist item %s does not exist, so it is ignored.", (char*)lfirst(lc))));
|
||||
(errmsg("黑名单项 %s 不存在,已忽略。", (char*)lfirst(lc))));
|
||||
}
|
||||
}
|
||||
list_free_deep(result);
|
||||
list_free_deep(result); // 释放拆分后的黑名单列表内存
|
||||
|
||||
*extra = MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DFX), sizeof(uint64));
|
||||
if (*extra == NULL)
|
||||
return false;
|
||||
|
||||
*((uint64*)*extra) = (mask == 0) ? DEFAULT_BLACKLIST_MASK : mask;
|
||||
*((uint64*)*extra) = (mask == 0) ? DEFAULT_BLACKLIST_MASK : mask; // 设置附加信息为黑名单掩码
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 bbox 黑名单。
|
||||
*
|
||||
* 参数:
|
||||
* - newval:新设置的值
|
||||
* - extra:附加信息
|
||||
*/
|
||||
void assign_bbox_blacklist(const char* newval, void* extra)
|
||||
{
|
||||
if (t_thrd.proc_cxt.MyProcPid == PostmasterPid) {
|
||||
g_instance.attr.attr_common.bbox_blacklist_mask = *((uint64*)extra);
|
||||
g_instance.attr.attr_common.bbox_blacklist_mask = *((uint64*)extra); // 设置 bbox 黑名单掩码
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示当前的 bbox 黑名单。
|
||||
*
|
||||
* 返回值:
|
||||
* - 当前的 bbox 黑名单字符串
|
||||
*/
|
||||
const char* show_bbox_blacklist()
|
||||
{
|
||||
StringInfoData str;
|
||||
|
||||
initStringInfo(&str);
|
||||
initStringInfo(&str); // 初始化字符串信息
|
||||
for (size_t i = 0; i < sizeof(g_blacklist_items) / sizeof(BlacklistItem); i++) {
|
||||
if ((BLACKLIST_ITEM_MASK(g_blacklist_items[i].blacklist_ID) & BBOX_BLACKLIST) != 0) {
|
||||
appendStringInfo(&str, "%s,", g_blacklist_items[i].blacklist_name);
|
||||
}
|
||||
}
|
||||
if (str.len >= 0) {
|
||||
str.data[--str.len] = '\0';
|
||||
str.data[--str.len] = '\0'; // 将最后一个逗号替换为结束符
|
||||
}
|
||||
|
||||
return str.data;
|
||||
return str.data; // 返回黑名单字符串
|
||||
}
|
||||
|
||||
/*
|
||||
* assign_bbox_coredump - set coredump for bbox or not
|
||||
/**
|
||||
* 设置是否进行 bbox 核心转储。
|
||||
*
|
||||
* 参数:
|
||||
* - newval:新设置的值
|
||||
* - extra:附加信息
|
||||
*/
|
||||
void assign_bbox_coredump(const bool newval, void* extra)
|
||||
{
|
||||
|
|
@ -333,7 +468,7 @@ void assign_bbox_coredump(const bool newval, void* extra)
|
|||
return;
|
||||
|
||||
if (newval && !FencedUDFMasterMode) {
|
||||
(void)install_signal(SIGABRT, bbox_handler);
|
||||
(void)install_signal(SIGABRT, bbox_handler); // 安装信号处理程序
|
||||
(void)install_signal(SIGBUS, bbox_handler);
|
||||
(void)install_signal(SIGILL, bbox_handler);
|
||||
(void)install_signal(SIGSEGV, bbox_handler);
|
||||
|
|
@ -345,33 +480,33 @@ void assign_bbox_coredump(const bool newval, void* extra)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* do initilaization for dumping core file
|
||||
/**
|
||||
* 初始化 bbox 核心转储。
|
||||
*/
|
||||
void bbox_initialize()
|
||||
{
|
||||
char core_dump_path[BBOX_PATH_SIZE] = {0};
|
||||
char core_dump_path[BBOX_PATH_SIZE] = {0}; // 存储核心转储路径的缓冲区
|
||||
|
||||
/* determine path which is used for bbox core dump file */
|
||||
/* 确定用于 bbox 核心转储文件的路径 */
|
||||
build_bbox_corepath(core_dump_path, sizeof(core_dump_path),
|
||||
u_sess->attr.attr_common.bbox_dump_path);
|
||||
|
||||
if (u_sess->attr.attr_common.enable_bbox_dump && *core_dump_path != '\0' &&
|
||||
CheckFilenameValid(core_dump_path) == RET_OK &&
|
||||
BBOX_SetCoredumpPath(core_dump_path) == 0) {
|
||||
write_stderr("bbox_dump_path is set to %s\n", core_dump_path);
|
||||
write_stderr("bbox_dump_path 设置为 %s\n", core_dump_path); // 打印核心转储路径
|
||||
}
|
||||
|
||||
/*
|
||||
* no matter bbox_dump_count is default (8) or set by users, call function BBOX_SetCoreFileCount.
|
||||
* Note: bbox_dump_count cannot be smaller than 1.
|
||||
* 无论 bbox_dump_count 是默认值 (8) 还是用户设置的值,都调用函数 BBOX_SetCoreFileCount。
|
||||
* 注意:bbox_dump_count 不能小于 1。
|
||||
*/
|
||||
if (u_sess->attr.attr_common.bbox_dump_count != 0 &&
|
||||
BBOX_SetCoreFileCount(u_sess->attr.attr_common.bbox_dump_count) != 0) {
|
||||
write_stderr("failed to set coredump count.\n");
|
||||
write_stderr("设置核心转储文件计数失败。\n"); // 打印设置核心转储文件计数失败信息
|
||||
}
|
||||
|
||||
assign_bbox_coredump(u_sess->attr.attr_common.enable_bbox_dump, NULL);
|
||||
assign_bbox_coredump(u_sess->attr.attr_common.enable_bbox_dump, NULL); // 设置是否进行 bbox 核心转储
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -390,8 +525,8 @@ void bbox_blacklist_add(BlacklistIndex item, void* addr, uint64 size)
|
|||
}
|
||||
|
||||
/*
|
||||
* remove an blacklist item.
|
||||
* void *pAddress : the head address of excluded memory
|
||||
* 移除一个黑名单项。
|
||||
* void *pAddress : 要排除的内存的起始地址
|
||||
*/
|
||||
void bbox_blacklist_remove(BlacklistIndex item, void* addr)
|
||||
{
|
||||
|
|
@ -402,10 +537,10 @@ void bbox_blacklist_remove(BlacklistIndex item, void* addr)
|
|||
}
|
||||
|
||||
/*
|
||||
* @Description: check the value from environment variablethe to prevent command injection.
|
||||
* @in input_env_value : the input value need be checked.
|
||||
*
|
||||
*/
|
||||
描述: 检查文件名是否符合规范,如果包含危险字符,则文件名无效。
|
||||
参数: 文件名的字符串指针。
|
||||
返回值: 整型,函数正常工作时返回 RET_OK,否则返回 RET_ERR。
|
||||
*/
|
||||
int CheckFilenameValid(const char* inputEnvValue)
|
||||
{
|
||||
const int maxLen = 1024;
|
||||
|
|
@ -424,4 +559,3 @@ int CheckFilenameValid(const char* inputEnvValue)
|
|||
}
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,15 @@
|
|||
|
||||
static bool CommCheckFilterMatch(const char *filter, int len, const char *ip, int port);
|
||||
|
||||
/*
|
||||
function name: SetCPUAffinity
|
||||
description: The function set the affinity of CPU or CPUs destined by argument cpu_id.
|
||||
arguments: An integer representing the id of one CPU or more.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/5
|
||||
contact: 18720816902
|
||||
*/
|
||||
void SetCPUAffinity(int cpu_id)
|
||||
{
|
||||
cpu_set_t mask;
|
||||
|
|
@ -270,6 +279,15 @@ IPAddrType CommLibNetGetIPType(unsigned int ip)
|
|||
#define CMD_STR_MAX 512
|
||||
#define CMD_OUTPUT_BUFFER_SIZE 1024
|
||||
|
||||
/*
|
||||
function name: CommCheckLtranProcess
|
||||
description: The function check if the process currently working has loaded transactions.
|
||||
arguments: void
|
||||
return value: 0 or 1, if 1, then at least one loaded transcation exists, if 0, no one.
|
||||
note: none
|
||||
date: 2022/8/5
|
||||
contact: 18720816902
|
||||
*/
|
||||
int CommCheckLtranProcess()
|
||||
{
|
||||
AutoContextSwitch commContext(g_instance.comm_cxt.comm_global_mem_cxt);
|
||||
|
|
@ -387,6 +405,21 @@ static T GetCommProxySubParameter(const char* str_attr, const char* key)
|
|||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: ParseCommProxyNumaBind
|
||||
description: Get the ids of CPU to bind process with specific CPU.
|
||||
arguments: The first argument is a pointer of type const char* to a string that indicating
|
||||
the id of CPUs below NUMA, not necessarily all CPUs.
|
||||
The second argument is an integer telling us we will get CPUs' id from which position
|
||||
of array str_attr.
|
||||
The third argument tells us the number of NUMA system framework.
|
||||
The fourth argument is a pointer to an integer array used to store CPUs' id gotten
|
||||
from string str_attr, we can use these ids to bind specific CPU.
|
||||
return value: void
|
||||
note: none
|
||||
date: 2022/8/5
|
||||
contact: 18720816902
|
||||
*/
|
||||
static void ParseCommProxyNumaBind(
|
||||
const char* str_attr, const int pos, const int numa_num, int* numa_bind)
|
||||
{
|
||||
|
|
@ -487,6 +520,22 @@ bool ParseCommProxyAttr(CommProxyConfig* config)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: CommCheckFilterMatch
|
||||
description: This function compare the ip and port allowed with ip and port gotten from
|
||||
Filter, if they are correspondingly same, it will return true value.
|
||||
arguments: The first argument is a pointer of type const char* to a string that indicating
|
||||
the id and port of the request been sent to Filter, the id and port have been
|
||||
separated by character ':'.
|
||||
The second argument is an integer telling us we the length of the string first
|
||||
argument directs.
|
||||
The third argument tells us the ip allowed.
|
||||
The fourth argument tells us the port allowed.
|
||||
return value: static bool
|
||||
note: none
|
||||
date: 2022/8/4
|
||||
contact: 18720816902
|
||||
*/
|
||||
static bool CommCheckFilterMatch(const char *filter, int len, const char *ip, int port)
|
||||
{
|
||||
char *str_ip = NULL;
|
||||
|
|
|
|||
|
|
@ -175,6 +175,24 @@ void UpdateTxRxStats(int msg_level)
|
|||
last_rx_nbytes = current_rx_nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: parse_monitor_sock_queue
|
||||
description: Compare the string recv_buffer with "sockqueue fd:fd", the "fd"
|
||||
after character ':' is an integer indicating file descriptor. If recv_buffer
|
||||
accords with the format, the function will takes next action to see if
|
||||
fd is 0, which represents stdin, so the function ends with returned value 0.
|
||||
If fd isn't 0, compare the third argument type with ParseMonitorTypeSet,
|
||||
if equal, then get a structure variable including socket descriptor
|
||||
destined by the fd gotten from the first argument, if it's NULL, we can
|
||||
write "fd:[%d], type:[normal fd], no sock queue" into send_buffer.
|
||||
arguments: The first argument is a pointer to a string indicating request infomation.
|
||||
The second argument is a pointer to a string to store sent infomation.
|
||||
The third argument tells the kind of socket request.
|
||||
return value: 0 or 1.
|
||||
note: none
|
||||
date: 2022/8/5
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int parse_monitor_sock_queue(char* recv_buffer, char* send_buffer, ParseMonitorType type)
|
||||
{
|
||||
int length;
|
||||
|
|
@ -205,6 +223,25 @@ int parse_monitor_sock_queue(char* recv_buffer, char* send_buffer, ParseMonitorT
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: parse_monitor_fd
|
||||
description: Compare the string recv_buffer with "query fd:fd", the "fd"
|
||||
after character ':' is an integer indicating file descriptor. If recv_buffer
|
||||
accords with the format, the function will takes next action to see if
|
||||
fd is 0, which represents stdin, so the function ends with returned value 0.
|
||||
If fd isn't 0, compare the third argument type with ParseMonitorTypeSet,
|
||||
if equal, then get a structure variable including socket descriptor
|
||||
destined by the fd gotten from the first argument, if it's NULL, we can
|
||||
write "fd:[%d], type:[normal fd]"(%d--fd) into send_buffer, else write
|
||||
"fd:[%d], type:[%d]"(%d--fd,%d--sock_desc->m_fd_type).
|
||||
arguments: The first argument is a pointer to a string indicating request infomation.
|
||||
The second argument is a pointer to a string to store sent infomation.
|
||||
The third argument tells the kind of socket request.
|
||||
return value: 0 or 1.
|
||||
note: none
|
||||
date: 2022/8/5
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int parse_monitor_fd(char* recv_buffer, char* send_buffer, ParseMonitorType type)
|
||||
{
|
||||
int length;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,24 @@ static void comm_wait_broadcast_end(SocketRequest** req_arr, int num);
|
|||
* export function definition
|
||||
************************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
function name: comm_proxy_socket
|
||||
description: This function creates a socket file descriptor whose protocol family is
|
||||
domain, protocol type is type, and protocol number is protocol. If the
|
||||
function call is successful, it will return a file descriptor that identifies
|
||||
the socket. If it fails, it will return - 1.
|
||||
arguments: The first argument specifies the protocol family, it's used as domain to
|
||||
set up network communication.
|
||||
The second argument is used to set the type of socket communication.
|
||||
The third argument is used to specify a specific type of a protocol, which
|
||||
is a type in the second argument types' type.
|
||||
return value: If the function call is successful, it will return a file descriptor that
|
||||
identifies the socket. If it fails, it will return - 1.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_socket(int domain, int type, int protocol)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -154,6 +172,16 @@ ssize_t comm_proxy_addr_recv(int sockfd, void *buf, size_t len, int flags)
|
|||
return comm_proxy_recv(sockfd, buf, len, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_close
|
||||
description: The function is used to release the resources allocated
|
||||
to the socket by the system.
|
||||
arguments: The argument is the socket file descriptor to be closed.
|
||||
return value: If the call is successful, return 0; otherwise, return - 1 and set errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_close(int fd)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -205,6 +233,18 @@ int comm_proxy_close(int fd)
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_shutdown
|
||||
description: The function is used to release the resources allocated
|
||||
to the socket by the system.
|
||||
arguments: The first argument is a descriptor used to identify a socket.
|
||||
The second argument is used to describe which operations
|
||||
are prohibited, which determines the behavior of the function.
|
||||
return value: If the call is successful, return 0; otherwise, return - 1 and set errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_shutdown(int fd, int how)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -259,6 +299,21 @@ int comm_proxy_shutdown(int fd, int how)
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_accept
|
||||
description: This function extracts the first connection from the waiting connection queue of S, creates
|
||||
a new socket interface similar to s and returns a handle.
|
||||
arguments: The first argument is a socket descriptor, which listens for connection after comm_proxy_listen().
|
||||
The second argument is a optional pointer pointing to a buffer where the address of the
|
||||
connection entity known to the communication layer is received. The actual format of the
|
||||
addr argument is determined by the address family generated when the socket is created.
|
||||
The third argument is a optional pointer, used together with addr, pointing to the integer
|
||||
number with the length of addr address.
|
||||
return value: The return value is a new socket descriptor, which represents a new connection with the client.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -343,6 +398,17 @@ int comm_proxy_accept4(int sockfd, struct sockaddr* addr, socklen_t* addrlen, in
|
|||
return comm_proxy_accept(sockfd, addr, addrlen);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_connect
|
||||
description: This function is used to establish a connection with a specified socket.
|
||||
arguments: The first argument is used to identify an unconnected socket.
|
||||
The second argument is a pointer to the sockaddr structure to socket will be connected.
|
||||
The third argument is byte length of sockaddr structure.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -394,6 +460,17 @@ int comm_proxy_connect(int sockfd, const struct sockaddr *addr, socklen_t addrle
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_bind
|
||||
description: This function binds a local address with a set of interfaces.
|
||||
arguments: The first argument indicates the socket descriptor that has been established.
|
||||
The second argument is a pointer to the sockaddr structure to socket.
|
||||
The third argument is byte length of sockaddr structure.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_bind(int sockfd, const struct sockaddr* ServerAddr, socklen_t addrlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -421,6 +498,16 @@ int comm_proxy_bind(int sockfd, const struct sockaddr* ServerAddr, socklen_t add
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_listen
|
||||
description: This function creates a socket interface and listens for the requested connection.
|
||||
arguments: The first argument is a descriptor used to identify a bundled but unconnected socket.
|
||||
The second argument indicates the maximum length of waiting for connection queue
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_listen(int sockfd, int backlog)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -447,6 +534,19 @@ int comm_proxy_listen(int sockfd, int backlog)
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_setsockopt
|
||||
description: The function is used to set option values for sockets of any type and any state.
|
||||
arguments: The first argument is a descriptor that identifies a socket interface.
|
||||
The second argument indicates the level defined by the option.
|
||||
The third argument specifies the option to be set.
|
||||
The fourth argument is a pointer to the buffer where the new value of the option to be set is stored.
|
||||
The fifth argument indicates optval buffer length.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_setsockopt(int sockfd, int level, int optname, const void* optval, socklen_t optlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -476,6 +576,19 @@ int comm_proxy_setsockopt(int sockfd, int level, int optname, const void* optval
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_getsockopt
|
||||
description: The function is used to obtain the current value of the option of any type and any state socket, and store the result in optval.
|
||||
arguments: The first argument is a descriptor that identifies a socket interface.
|
||||
The second argument indicates the level defined by the option.
|
||||
The third argument specifies the socket options to be obtained.
|
||||
The fourth argument is a pointer to the buffer where the obtained option value is stored.
|
||||
The fifth argument is a pointer to the length value of optval buffer.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_getsockopt(int sockfd, int level, int optname, void* optval, socklen_t* optlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -504,6 +617,18 @@ int comm_proxy_getsockopt(int sockfd, int level, int optname, void* optval, sock
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_getsockname
|
||||
description: The function is used to get the name of a socket. It is used for a bundled or
|
||||
connected socket, and the local address will be returned.
|
||||
arguments: The first argument is a descriptor that identifies a socket interface.
|
||||
The second argument indicates the address of the receiving socket.
|
||||
The third argument specifies the length of the name buffer.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -530,6 +655,17 @@ int comm_proxy_getsockname(int sockfd, struct sockaddr* addr, socklen_t* addrlen
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_getpeername
|
||||
description: The function is used to obtain the foreign protocol address associated with a socket.
|
||||
arguments: The first argument is a descriptor that identifies a socket interface.
|
||||
The second argument indicates the name structure of the receiver address.
|
||||
The third argument specifies the length of the name structure.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -556,6 +692,19 @@ int comm_proxy_getpeername(int sockfd, struct sockaddr* addr, socklen_t* addrlen
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_fcntl
|
||||
description: The function can change the nature of the opened file, it provides control over descriptors.
|
||||
The argument sockfd is a descriptor operated by the argument cmd. For the value of cmd,
|
||||
fcntl can accept the third argument arg, which is a variable argument.
|
||||
arguments: The first argument is a descriptor that identifies a socket interface.
|
||||
The second argument represents the instruction to be operated.
|
||||
The third argument is a variable argument
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_fcntl(int sockfd, int cmd, ...)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -622,6 +771,17 @@ int comm_proxy_fcntl(int sockfd, int cmd, ...)
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_poll
|
||||
description: The function is used to hang the current file pointer to the waiting queue.
|
||||
arguments: The first argument is an array of struct pollfd structure type, used to store the socket descriptor whose state needs to be detected.
|
||||
The second argument is used to mark the total number of structural elements in the array fdarray;
|
||||
The third argument is the blocking time of the comm_proxy_poll function call.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_poll(struct pollfd* fdarray, unsigned long nfds, int timeout)
|
||||
{
|
||||
CommWaitPollParam param;
|
||||
|
|
@ -658,6 +818,15 @@ int comm_proxy_poll(struct pollfd* fdarray, unsigned long nfds, int timeout)
|
|||
return param.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_epoll_create
|
||||
description: The function is used to create a handle to epoll.
|
||||
arguments: The only argument size is used to tell the kernel how many listeners there are.
|
||||
return value: Returns a file descriptor that points to the newly created epoll instance
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_epoll_create(int size)
|
||||
{
|
||||
/*
|
||||
|
|
@ -687,6 +856,21 @@ int comm_proxy_epoll_create1(int flag)
|
|||
return comm_proxy_epoll_create(1);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_epoll_ctl
|
||||
description: This system call performs control operations on the epoll instance referenced
|
||||
by the file descriptor epfd. It requires the operation op to execute the target
|
||||
file descriptor fd. It's used as epoll's event registration function, it adds,
|
||||
modifies, or deletes events of interest to the epoll object.
|
||||
arguments: The first argument is a specific file descriptor for epoll generated by epoll_ create.
|
||||
The second argument indicates the actions to be taken, such as registering events.
|
||||
The third argument is associated file descriptor.
|
||||
The fourth argument is a pointer of type struct epoll_event, used to tell the kernel what events and actions to listen for.
|
||||
return value: The return value is 0 if succeed, - 1 is returned for failure and error reason is stored in errno.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)
|
||||
{
|
||||
SocketRequest req;
|
||||
|
|
@ -926,6 +1110,23 @@ int comm_proxy_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event)
|
|||
return result.s_ret;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: comm_proxy_epoll_wait
|
||||
description: Wait for IO events on the specified epoll file descriptor.
|
||||
arguments: The first argument is a specific file descriptor for epoll generated by epoll_ create.
|
||||
The second argument is a pointer to type epoll_ event structure, but it is now used
|
||||
as a container to get the collection of events from the kernel.
|
||||
The third argument is used to tell how large the container is (number of event
|
||||
array members), that is, the number of events that can be processed each time.
|
||||
The fourth argument is the timeout value for waiting for IO events.
|
||||
return value: When successful, comm_proxy_epoll_wait() returns the number of file descriptors
|
||||
ready for the requested IO. Returns zero if no file descriptor is ready within the
|
||||
requested timeout milliseconds. When an error occurs, comm_proxy_epoll_wait()
|
||||
returns - 1 and sets errno correctly.
|
||||
note: none
|
||||
date: 2022/8/8
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int comm_proxy_epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout)
|
||||
{
|
||||
CommWaitEpollWaitParam param;
|
||||
|
|
|
|||
|
|
@ -41,64 +41,64 @@
|
|||
#include "libcomm_common.h"
|
||||
|
||||
int binary_semaphore::init() {
|
||||
atomic_set(&b_flag, 0);
|
||||
atomic_set(&waiting_count, 0);
|
||||
atomic_set(&b_destroy, 0);
|
||||
atomic_set(&destroy_wait, 0);
|
||||
int err = pthread_cond_init(&cond, NULL);
|
||||
atomic_set(&b_flag, 0); // 初始化 b_flag 为 0
|
||||
atomic_set(&waiting_count, 0); // 初始化 waiting_count 为 0
|
||||
atomic_set(&b_destroy, 0); // 初始化 b_destroy 为 0
|
||||
atomic_set(&destroy_wait, 0); // 初始化 destroy_wait 为 0
|
||||
int err = pthread_cond_init(&cond, NULL); // 初始化 cond,若失败则返回错误码
|
||||
if (err != 0)
|
||||
return err;
|
||||
err = pthread_mutex_init(&mutex, NULL);
|
||||
err = pthread_mutex_init(&mutex, NULL); // 初始化 mutex,若失败则销毁 cond,并返回错误码
|
||||
if (err != 0) {
|
||||
LIBCOMM_PTHREAD_COND_DESTORY(&cond);
|
||||
return err;
|
||||
}
|
||||
return err;
|
||||
return err; // 返回错误码
|
||||
}
|
||||
|
||||
int binary_semaphore::destroy(bool do_destroy) {
|
||||
const int ret = 0;
|
||||
atomic_set(&b_destroy, 1);
|
||||
while (destroy_wait != 0) {
|
||||
post();
|
||||
usleep(100);
|
||||
}
|
||||
if (do_destroy) {
|
||||
LIBCOMM_PTHREAD_COND_DESTORY(&cond);
|
||||
LIBCOMM_PTHREAD_MUTEX_DESTORY(&mutex);
|
||||
}
|
||||
return ret;
|
||||
const int ret = 0;
|
||||
atomic_set(&b_destroy, 1); // 将 b_destroy 置为 1 表示要销毁
|
||||
while (destroy_wait != 0) { // 若存在等待销毁的线程,则发送信号,并休眠 100 微秒
|
||||
post();
|
||||
usleep(100);
|
||||
}
|
||||
if (do_destroy) { // 若指定要进行销毁,则销毁 cond 和 mutex
|
||||
LIBCOMM_PTHREAD_COND_DESTORY(&cond);
|
||||
LIBCOMM_PTHREAD_MUTEX_DESTORY(&mutex);
|
||||
}
|
||||
return ret; // 返回 0
|
||||
}
|
||||
|
||||
void binary_semaphore::reset() {
|
||||
atomic_set(&b_flag, 0);
|
||||
while (destroy_wait != 0) {
|
||||
atomic_set(&b_flag, 0); // 将 b_flag 重置为 0
|
||||
while (destroy_wait != 0) { // 若存在等待销毁的线程,则发送信号,并休眠 100 微秒
|
||||
post();
|
||||
usleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
void binary_semaphore::post() {
|
||||
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex);
|
||||
void binary_semaphore::post() {
|
||||
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex); // 上锁 mutex
|
||||
/* thread will poll up when someone has posted before */
|
||||
atomic_set(&b_flag, 1);
|
||||
if (waiting_count > 0) {
|
||||
atomic_set(&b_flag, 1); // 将 b_flag 置为 1 表示已有线程发送信号
|
||||
if (waiting_count > 0) { // 若存在等待的线程,则发送一个信号给等待线程
|
||||
LIBCOMM_PTHREAD_COND_SIGNAL(&cond);
|
||||
}
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex);
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex); // 解锁 mutex
|
||||
}
|
||||
|
||||
void binary_semaphore::post_all() {
|
||||
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex);
|
||||
atomic_set(&b_flag, 1);
|
||||
if (waiting_count > 0) {
|
||||
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex); // 上锁 mutex
|
||||
atomic_set(&b_flag, 1); // 将 b_flag 置为 1 表示已有线程发送信号
|
||||
if (waiting_count > 0) { // 若存在等待的线程,则发送广播给所有等待线程
|
||||
LIBCOMM_PTHREAD_COND_BROADCAST(&cond);
|
||||
}
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex);
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex); // 解锁 mutex
|
||||
}
|
||||
|
||||
int binary_semaphore::wait() {
|
||||
if (b_flag) {
|
||||
if (b_flag) { // 若 b_flag 为 1,则表示已有线程发送信号,不需要等待
|
||||
/* reset b_flag is no one is waitting */
|
||||
if (waiting_count == 0)
|
||||
atomic_set(&b_flag, 0);
|
||||
|
|
@ -106,29 +106,29 @@ int binary_semaphore::wait() {
|
|||
}
|
||||
|
||||
int ret = 0;
|
||||
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex);
|
||||
while (!b_flag) {
|
||||
atomic_add(&waiting_count, 1);
|
||||
ret = pthread_cond_wait(&cond, &mutex);
|
||||
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex); // 上锁 mutex
|
||||
while (!b_flag) { // 若 b_flag 为 0,则表示没有线程发送信号,需要等待
|
||||
atomic_add(&waiting_count, 1);
|
||||
ret = pthread_cond_wait(&cond, &mutex); // 等待信号,并当有信号到来时解锁 mutex 并接收信号
|
||||
atomic_sub(&waiting_count, 1);
|
||||
}
|
||||
|
||||
if (b_destroy)
|
||||
if (b_destroy) // 若 b_destroy 为 1,则表示要销毁,返回错误码
|
||||
ret = -1;
|
||||
/* reset b_flag is no one is waitting */
|
||||
if (waiting_count == 0)
|
||||
atomic_set(&b_flag, 0);
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex);
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex); // 解锁 mutex
|
||||
|
||||
return ret;
|
||||
return ret; // 返回错误码
|
||||
}
|
||||
|
||||
void binary_semaphore::destroy_wait_add() {
|
||||
atomic_add(&destroy_wait, 1);
|
||||
atomic_add(&destroy_wait, 1); // 销毁等待数 +1
|
||||
}
|
||||
|
||||
void binary_semaphore::destroy_wait_sub() {
|
||||
atomic_sub(&destroy_wait, 1);
|
||||
atomic_sub(&destroy_wait, 1); // 销毁等待数 -1
|
||||
}
|
||||
|
||||
/** The parameter timeout should be in second, if it is minus or zero, the function
|
||||
|
|
@ -137,138 +137,139 @@ void binary_semaphore::destroy_wait_sub() {
|
|||
int binary_semaphore::timed_wait(int timeout) {
|
||||
int ret = -1;
|
||||
|
||||
if (timeout <= 0) {
|
||||
if (timeout <= 0) { // 若超时时间小于等于 0,则与 _wait() 函数一样
|
||||
ret = wait();
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (b_flag) {
|
||||
if (b_flag) { // b_flag 为 1,表示已有线程发送信号,不需要等待
|
||||
/* reset b_flag is no one is waitting */
|
||||
if (waiting_count == 0)
|
||||
atomic_set(&b_flag, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex);
|
||||
if (b_flag) {
|
||||
LIBCOMM_PTHREAD_MUTEX_LOCK(&mutex); // 上锁 mutex
|
||||
if (b_flag) { // b_flag 为 1,表示已有线程发送信号,不需要等待
|
||||
atomic_set(&b_flag, 0);
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex);
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += timeout;
|
||||
clock_gettime(CLOCK_REALTIME, &ts); // 获取当前时间
|
||||
ts.tv_sec += timeout; // 计算超时的时间点
|
||||
ts.tv_nsec = 0;
|
||||
atomic_add(&waiting_count, 1);
|
||||
atomic_add(&waiting_count, 1); // 增加等待线程数
|
||||
|
||||
ret = pthread_cond_timedwait(&cond, &mutex, &ts);
|
||||
ret = pthread_cond_timedwait(&cond, &mutex, &ts); // 等待信号,若超过超时时间仍未接收到信号,则返回 ETIMEDOUT
|
||||
|
||||
atomic_sub(&waiting_count, 1);
|
||||
if (b_flag) {
|
||||
atomic_sub(&waiting_count, 1); // 减少等待线程数
|
||||
if (b_flag) { // b_flag 为 1,表示已有线程发送信号,不需要等待
|
||||
/* reset b_flag is no one is waitting */
|
||||
if (waiting_count == 0)
|
||||
atomic_set(&b_flag, 0);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (b_destroy)
|
||||
if (b_destroy) // 若 b_destroy 为 1,则表示要销毁,返回错误码
|
||||
ret = -1;
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex);
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&mutex); // 解锁 mutex
|
||||
|
||||
return ret;
|
||||
return ret; // 返回错误码
|
||||
}
|
||||
|
||||
int hash_entry::_init() {
|
||||
return sem.init();
|
||||
return sem.init(); // 调用 binary_semaphore 对象 sem 的 init() 函数
|
||||
}
|
||||
|
||||
void hash_entry::_destroy() {
|
||||
sem.destroy(true);
|
||||
sem.destroy(true); // 调用 binary_semaphore 对象 sem 的 destroy() 函数
|
||||
}
|
||||
|
||||
void hash_entry::_signal() {
|
||||
sem.post();
|
||||
sem.post(); // 调用 binary_semaphore 对象 sem 的 post() 函数
|
||||
}
|
||||
|
||||
void hash_entry::_signal_all() {
|
||||
sem.post_all();
|
||||
sem.post_all(); // 调用 binary_semaphore 对象 sem 的 post_all() 函数
|
||||
}
|
||||
|
||||
void hash_entry::_wait() {
|
||||
sem.wait();
|
||||
sem.wait(); // 调用 binary_semaphore 对象 sem 的 wait() 函数
|
||||
}
|
||||
|
||||
void hash_entry::_hold_destroy() {
|
||||
sem.destroy_wait_add();
|
||||
sem.destroy_wait_add(); // 调用 binary_semaphore 对象 sem 的 destroy_wait_add() 函数
|
||||
}
|
||||
|
||||
void hash_entry::_release_destroy() {
|
||||
sem.destroy_wait_sub();
|
||||
sem.destroy_wait_sub(); // 调用 binary_semaphore 对象 sem 的 destroy_wait_sub() 函数
|
||||
}
|
||||
|
||||
int hash_entry::_timewait(int timeout) {
|
||||
return sem.timed_wait(timeout);
|
||||
return sem.timed_wait(timeout); // 调用 binary_semaphore 对象 sem 的 timed_wait() 函数
|
||||
}
|
||||
|
||||
void node_sock::reset_all() {
|
||||
ctrl_tcp_sock = -1;
|
||||
ctrl_tcp_port = -1;
|
||||
ctrl_tcp_sock_id = 0;
|
||||
libcomm_reply_sock = -1;
|
||||
libcomm_reply_sock_id = -1;
|
||||
ctrl_tcp_sock = -1; // 重置 ctrl_tcp_sock 为 -1 表示未连接
|
||||
ctrl_tcp_port = -1; // 重置 ctrl_tcp_port 为 -1
|
||||
ctrl_tcp_sock_id = 0; // 重置 ctrl_tcp_sock_id 为 0
|
||||
libcomm_reply_sock = -1; // 重置 libcomm_reply_sock 为 -1 表示未连接
|
||||
libcomm_reply_sock_id = -1; // 重置 libcomm_reply_sock_id 为 -1
|
||||
errno_t ss_rc = 0;
|
||||
ss_rc = memset_s(remote_host, HOST_ADDRSTRLEN, 0x0, HOST_ADDRSTRLEN);
|
||||
ss_rc = memset_s(remote_host, HOST_ADDRSTRLEN, 0x0, HOST_ADDRSTRLEN); // 清空 remote_host 数组
|
||||
securec_check(ss_rc, "\0", "\0");
|
||||
ss_rc = memset_s(remote_nodename, NAMEDATALEN, 0x0, NAMEDATALEN);
|
||||
ss_rc = memset_s(remote_nodename, NAMEDATALEN, 0x0, NAMEDATALEN); // 清空 remote_nodename 数组
|
||||
securec_check(ss_rc, "\0", "\0");
|
||||
ss_rc = memset_s(&to_ss, sizeof(struct sockaddr_storage), 0x0, sizeof(struct sockaddr_storage));
|
||||
ss_rc = memset_s(&to_ss, sizeof(struct sockaddr_storage), 0x0, sizeof(struct sockaddr_storage)); // 清空 to_ss 结构体
|
||||
securec_check(ss_rc, "\0", "\0");
|
||||
}
|
||||
|
||||
void node_sock::init() {
|
||||
reset_all();
|
||||
LIBCOMM_PTHREAD_MUTEX_INIT(&_slock, 0);
|
||||
LIBCOMM_PTHREAD_MUTEX_INIT(&_tlock, 0);
|
||||
reset_all(); // 初始化相关成员变量
|
||||
LIBCOMM_PTHREAD_MUTEX_INIT(&_slock, 0); // 初始化锁 _slock
|
||||
LIBCOMM_PTHREAD_MUTEX_INIT(&_tlock, 0); // 初始化锁 _tlock
|
||||
}
|
||||
|
||||
void node_sock::clear() {
|
||||
reset_all();
|
||||
reset_all(); // 清空相关成员变量
|
||||
}
|
||||
|
||||
void node_sock::destroy() {
|
||||
clear();
|
||||
LIBCOMM_PTHREAD_MUTEX_DESTORY(&_slock);
|
||||
LIBCOMM_PTHREAD_MUTEX_DESTORY(&_tlock);
|
||||
clear(); // 清空相关成员变量
|
||||
LIBCOMM_PTHREAD_MUTEX_DESTORY(&_slock); // 销毁锁 _slock
|
||||
LIBCOMM_PTHREAD_MUTEX_DESTORY(&_tlock); // 销毁锁 _tlock
|
||||
}
|
||||
|
||||
void node_sock::lock() {
|
||||
LIBCOMM_PTHREAD_MUTEX_LOCK(&_tlock);
|
||||
LIBCOMM_PTHREAD_MUTEX_LOCK(&_tlock); // 上锁 _tlock
|
||||
}
|
||||
|
||||
void node_sock::unlock() {
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&_tlock);
|
||||
LIBCOMM_PTHREAD_MUTEX_UNLOCK(&_tlock); // 解锁 _tlock
|
||||
}
|
||||
|
||||
void node_sock::close_socket(int flag) {
|
||||
lock();
|
||||
close_socket_nl(flag);
|
||||
lock();
|
||||
close_socket_nl(flag); // 关闭 socket
|
||||
unlock();
|
||||
}
|
||||
|
||||
void node_sock::close_socket_nl(int flag) { // close without lock
|
||||
void node_sock::close_socket_nl(int flag) { // 关闭 socket,但不进行上锁
|
||||
switch (flag) {
|
||||
case CTRL_TCP_SOCK:
|
||||
if (ctrl_tcp_sock >= 0) {
|
||||
close(ctrl_tcp_sock);
|
||||
close(ctrl_tcp_sock); // 关闭 ctrl_tcp_sock
|
||||
ctrl_tcp_sock = -1;
|
||||
ctrl_tcp_sock_id = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void node_sock::set(int val, int flag) {
|
||||
lock();
|
||||
|
|
@ -276,49 +277,48 @@ void node_sock::set(int val, int flag) {
|
|||
unlock();
|
||||
}
|
||||
|
||||
void node_sock::set_nl(int val, int flag) { // set without lock
|
||||
switch (flag) {
|
||||
case CTRL_TCP_SOCK:
|
||||
ctrl_tcp_sock = val;
|
||||
break;
|
||||
case CTRL_TCP_PORT:
|
||||
ctrl_tcp_port = val;
|
||||
break;
|
||||
case CTRL_TCP_SOCK_ID:
|
||||
ctrl_tcp_sock_id = val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
void node_sock::set_nl(int val, int flag) {
|
||||
switch (flag) { // 根据flag的不同选择对应的操作
|
||||
case CTRL_TCP_SOCK: // 如果flag是CTRL_TCP_SOCK
|
||||
ctrl_tcp_sock = val; // 将val赋值给ctrl_tcp_sock
|
||||
break; // 结束该case
|
||||
case CTRL_TCP_PORT: // 如果flag是CTRL_TCP_PORT
|
||||
ctrl_tcp_port = val; // 将val赋值给ctrl_tcp_port
|
||||
break; // 结束该case
|
||||
case CTRL_TCP_SOCK_ID: // 如果flag是CTRL_TCP_SOCK_ID
|
||||
ctrl_tcp_sock_id = val; // 将val赋值给ctrl_tcp_sock_id
|
||||
break; // 结束该case
|
||||
default: // 如果flag不是上述三种情况
|
||||
break; // 不执行任何操作
|
||||
}
|
||||
}
|
||||
|
||||
int node_sock::get(int flag, int* id) {
|
||||
int val = -1;
|
||||
lock();
|
||||
val = get_nl(flag, id);
|
||||
unlock();
|
||||
return val;
|
||||
int val = -1; // 初始化val为-1
|
||||
lock(); // 加锁
|
||||
val = get_nl(flag, id); // 调用get_nl函数获取val的值
|
||||
unlock(); // 解锁
|
||||
return val; // 返回val的值
|
||||
}
|
||||
|
||||
int node_sock::get_nl(int flag, int* id) const { // get without lock
|
||||
int val = -1;
|
||||
switch (flag) {
|
||||
case CTRL_TCP_SOCK:
|
||||
val = ctrl_tcp_sock;
|
||||
if (id != NULL)
|
||||
*id = ctrl_tcp_sock_id;
|
||||
break;
|
||||
case CTRL_TCP_PORT:
|
||||
val = ctrl_tcp_port;
|
||||
break;
|
||||
case CTRL_TCP_SOCK_ID:
|
||||
val = ctrl_tcp_sock_id;
|
||||
if (id != NULL)
|
||||
*id = ctrl_tcp_sock_id;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
int node_sock::get_nl(int flag, int* id) const {
|
||||
int val = -1; // 初始化val为-1
|
||||
switch (flag) { // 根据flag的不同选择对应的操作
|
||||
case CTRL_TCP_SOCK: // 如果flag是CTRL_TCP_SOCK
|
||||
val = ctrl_tcp_sock; // 将ctrl_tcp_sock的值赋给val
|
||||
if (id != NULL) // 如果id不为空指针
|
||||
*id = ctrl_tcp_sock_id; // 将ctrl_tcp_sock_id的值赋给id所指向的变量
|
||||
break; // 结束该case
|
||||
case CTRL_TCP_PORT: // 如果flag是CTRL_TCP_PORT
|
||||
val = ctrl_tcp_port; // 将ctrl_tcp_port的值赋给val
|
||||
break; // 结束该case
|
||||
case CTRL_TCP_SOCK_ID: // 如果flag是CTRL_TCP_SOCK_ID
|
||||
val = ctrl_tcp_sock_id; // 将ctrl_tcp_sock_id的值赋给val
|
||||
if (id != NULL) // 如果id不为空指针
|
||||
*id = ctrl_tcp_sock_id; // 将ctrl_tcp_sock_id的值赋给id所指向的变量
|
||||
break; // 结束该case
|
||||
default: // 如果flag不是上述三种情况
|
||||
break; // 不执行任何操作
|
||||
}
|
||||
return val;
|
||||
return val; // 返回val的值
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,27 @@ void mc_tcp_set_keepalive(int fd)
|
|||
mc_tcp_setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, (char*)&count, sizeof(count));
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_get_peer_name
|
||||
description: This function is used to obtain the host IP and port number of the host bound to the specific socket.
|
||||
arguments: The first argument is a descriptor to a specified socket.
|
||||
The second argument is used to store the host IP address bound to the socket determined by the first parameter, in dotted decimal.
|
||||
The third parameter is used to store the port number bound to a specific socket, in the order of host bytes.
|
||||
return value: Return 0 if the function runs successfully.
|
||||
When the call to the getpeername() function fails:
|
||||
1、Return EBADF if the socket argument is not a valid file descriptor.
|
||||
2、Return EINVAL if the socket has been shut down.
|
||||
3、Return ENOTCONN if the socket is not connected or otherwise has not had the peer pre-specified.
|
||||
4、Return ENOTSOCK if the socket argument does not refer to a socket.
|
||||
5、Return EOPNOTSUPP if the operation is not supported for the socket protocol.
|
||||
6、Return ENOBUFS if insufficient resources were available in the system to complete the call.
|
||||
Return -2 when the host IP address belongs to IPv4 type, it fails to convert it to dotted decimal.
|
||||
Return -3 when the host IP address belongs to IPv6 type, it fails to convert it to dotted decimal.
|
||||
Return -4 when the error type is not any of the above.
|
||||
note: Allocate a certain amount of memory space for the host and port pointers respectively in advance.
|
||||
date: 2022/8/9
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_get_peer_name(int fd, char* host, int* port)
|
||||
{
|
||||
struct sockaddr peeraddr = {0};
|
||||
|
|
@ -121,6 +142,17 @@ int mc_tcp_set_cloexec(int fd)
|
|||
return set_socketopt(fd, 1, FD_CLOEXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_accept
|
||||
description: This function will block the process by default until a client connection is established and returns a new available socket.
|
||||
arguments: The first argument is a socket descriptor to a specific socket.
|
||||
The second argument is a result parameter, which is used to accept a return value that specifies the address of the client.
|
||||
The third argument is also a result argument, which is used to accept the size of the sockaddr structure. It indicates the number of bytes occupied by the sockaddr structure.
|
||||
return value: Return a value less than 0 if an error occurred when call the function accept4(), else return the new fd of socket.
|
||||
note: none
|
||||
date: 2022/8/9
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_accept(int fd, struct sockaddr* sa, socklen_t* salenptr)
|
||||
{
|
||||
int new_fd;
|
||||
|
|
@ -147,6 +179,17 @@ again:
|
|||
return (new_fd);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_bind
|
||||
description: This function binds the specified socket to a specific IP address and port.
|
||||
arguments: The first argument indicates the socket descriptor that has been established.
|
||||
The second argument is a pointer to the sockaddr structure to socket.
|
||||
The third argument is byte length of sockaddr structure.
|
||||
return value: Return errno, the return value is 0 if succeed, else one of other error types is returned for failure.
|
||||
note: none
|
||||
date: 2022/8/9
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_bind(int fd, const struct sockaddr* sa, socklen_t salen)
|
||||
{
|
||||
int error = -1;
|
||||
|
|
@ -191,6 +234,20 @@ static void mc_tcp_do_listen(int fd, int backlog)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_read_block
|
||||
description: This function receives data from the other end of TCP in a blocking manner, the receiving
|
||||
process will not end until the data of size byte length is successfully received or a real error occurs in the receiving process
|
||||
arguments: The first argument indicates the specific socket that has been established.
|
||||
The second argument is a pointer to memory area, we use it to store received data.
|
||||
The third argument is byte length of the memory area pointed to by the data pointer.
|
||||
The fourth argument specifies additional operations in addition to the read operation.
|
||||
return value: If there is no error, it returns the byte length of the successfully read data. If an error
|
||||
occurs, return - 1.
|
||||
note: When the data is read successfully, the byte length of the data is greater than 0.
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_read_block(int fd, void* data, int size, int flags)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
@ -261,6 +318,20 @@ int mc_tcp_read_block(int fd, void* data, int size, int flags)
|
|||
return (size_t)nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_read_nonblock
|
||||
description: This function receives data from the other end of TCP in a non blocking manner,
|
||||
the data receiving process is only performed once.
|
||||
arguments: The first argument indicates the specific socket that has been established.
|
||||
The second argument is a pointer to memory area, we use it to store received data.
|
||||
The third argument is byte length of the memory area pointed to by the data pointer.
|
||||
The fourth argument specifies additional operations in addition to the read operation.
|
||||
return value: If the error type is one of the errors represented by EAGAIN, EWOULDBLOCK and EINTR, it returns 0;
|
||||
other error types return - 1; if there is no error, it returns the byte length of the successfully read data.
|
||||
note: When the data is read successfully, the byte length of the data is greater than 0.
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_read_nonblock(int fd, void* data, int size, int flags)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
@ -306,6 +377,17 @@ int mc_tcp_read_nonblock(int fd, void* data, int size, int flags)
|
|||
return (size_t)nbytes;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_check_socket
|
||||
description: This function binds the specified socket to a specific IP address and port.
|
||||
arguments: The only argument indicates the specific socket that has been established.
|
||||
return value: Return -1 if when the recv function wait for the protocol to receive data,
|
||||
the other end of TCP closes the connection or a real error occurred while
|
||||
reading data. In other cases, 0 is returned.
|
||||
note: none
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_check_socket(int sock)
|
||||
{
|
||||
char temp_buf[IOV_DATA_SIZE] = {0};
|
||||
|
|
@ -368,6 +450,19 @@ int mc_tcp_check_socket(int sock)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_write_block
|
||||
description: This function writes data to the specified socket in blocking mode, the sending process
|
||||
will not end until all the data are successfully sent or a real error occurs during the sending process
|
||||
arguments: The first argument indicates the specific socket that has been established.
|
||||
The second argument is a pointer to memory area, we use it to store data to be sent.
|
||||
The third argument is byte length of data to be sent.
|
||||
return value: If there is no error, it returns the byte length of the successfully sent data. If an error
|
||||
occurs, return - 1.
|
||||
note: none
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_write_block(int fd, const void* data, int size)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
@ -426,6 +521,21 @@ int mc_tcp_write_block(int fd, const void* data, int size)
|
|||
return (size_t)nSend;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_write_noblock
|
||||
description: This function writes data to the specified socket in non blocking mode,
|
||||
the data transmission process is only performed once.
|
||||
arguments: The first argument indicates the specific socket that has been established.
|
||||
The second argument is a pointer to memory area, we use it to store data to be sent.
|
||||
The third argument is byte length of data to be sent.
|
||||
return value: If the sending fails but the failure reason is one of the error types represented by EAGAIN、
|
||||
EWOULDBLOCK、EINTR 和ENOBUFS, then 0 is returned; if the error type is other, then - 1
|
||||
is returned; If the transmission is successful, the byte length of the successfully transmitted
|
||||
data is returned
|
||||
note: none
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_write_noblock(int fd, const void* data, int size)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
@ -519,6 +629,17 @@ int mc_tcp_addr_init(const char* host, int port, struct sockaddr_storage* ss, in
|
|||
return (error == 1) ? 0 : error;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_connect_nonblock
|
||||
description: This function is used to create a socket and establish a connection with the port of the specified host
|
||||
in non blocking mode.
|
||||
arguments: The first parameter specifies a specific host, and the second parameter specifies a specific port of the host.
|
||||
return value: If the connection is successfully established, the file descriptor of the socket connected to the port of the
|
||||
specified host is returned; otherwise, - 1 is returned.
|
||||
note: none
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_connect_nonblock(const char* host, int port)
|
||||
{
|
||||
int sockfd, n;
|
||||
|
|
@ -566,6 +687,18 @@ int mc_tcp_connect_nonblock(const char* host, int port)
|
|||
return sockfd;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_connect
|
||||
description: This function first obtains the ports of other hosts with the same domain name stored through
|
||||
the ports of specific hosts, and creates a socket to establish a connection with an appropriate
|
||||
one of these ports.
|
||||
arguments: The first parameter specifies a specific host, and the second parameter specifies a specific port of the host.
|
||||
return value: The key is to successfully establish a connection with a port in the linked list. If the connection is successful, the
|
||||
socket file descriptor connected to it will be returned. Otherwise, it will return - 1.
|
||||
note: We finally get the infomation of the ports of other hosts through a linked list.
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_connect(const char* host, int port)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
@ -656,6 +789,18 @@ retry:
|
|||
return (sockfd);
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_tcp_listen
|
||||
description: This function first obtains the ports of other hosts with the same domain name stored through
|
||||
the ports of specific hosts, and creates a socket to bind with an appropriate one of these ports.
|
||||
arguments: The first parameter specifies a specific host, and the second parameter specifies a specific port of the host.
|
||||
The third is used to store size of protocol address.
|
||||
return value: The key lies in the successful binding with a port in the linked list. If the binding is successful, the socket file
|
||||
descriptor connected to it will be returned. Otherwise, it will return - 1.
|
||||
note: We finally get the infomation of the ports of other hosts through a linked list.
|
||||
date: 2022/8/10
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_tcp_listen(const char* host, int port, socklen_t* addrlenp)
|
||||
{
|
||||
#ifdef LIBCOMM_FAULT_INJECTION_ENABLE
|
||||
|
|
|
|||
|
|
@ -232,6 +232,21 @@ static int gs_tcp_write_noblock(int node_idx, int sock, const char* msg, int msg
|
|||
|
||||
return send_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: libcomm_tcp_send
|
||||
description: This function is used to send the message including message head and message body, to
|
||||
a specific socket.
|
||||
arguments: send_ info is a pointer of LibcommRecvInfo* type, pointing to the memory storing the data
|
||||
waiting to be sent.
|
||||
return value: Data will be sent twice in total. Before sending data, if it is found that the socket to receive
|
||||
data is not matched with the specified socket, then - 1 will be returned; If the sending of
|
||||
message head or message body fails, return - 1; If the function runs successfully, the byte
|
||||
length of the message body sent successfully is returned.
|
||||
note: none
|
||||
date: 2022/8/11
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
static int libcomm_tcp_send(LibcommSendInfo* send_info)
|
||||
{
|
||||
int sock = send_info->socket;
|
||||
|
|
@ -322,6 +337,19 @@ static int libcomm_tcp_send(LibcommSendInfo* send_info)
|
|||
return send_bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: libcomm_tcp_recv_noidx
|
||||
description: This function is used to store the message transmitted from the sender, specifically to obtain
|
||||
the message from a specific socket.
|
||||
arguments: recv_ info is a pointer of LibcommRecvInfo* type, pointing to the memory to store the data
|
||||
received.
|
||||
return value: If it fails to allocate memory for iov_ Item, return RECV_MEM_ERROR;
|
||||
If it fails to obtain data, no matter it is a message header or a message body, from the specified socket in blocking mode, return RECV_NET_ERROR;
|
||||
If the function runs successfully, the byte length of the read message body is returned.
|
||||
note: none
|
||||
date: 2022/8/11
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
static int libcomm_tcp_recv_noidx(LibcommRecvInfo* recv_info)
|
||||
{
|
||||
int sock = recv_info->socket;
|
||||
|
|
@ -371,6 +399,23 @@ static int libcomm_tcp_recv_noidx(LibcommRecvInfo* recv_info)
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: libcomm_tcp_recv
|
||||
description: This function is used to store the message transmitted from the sender, specifically to obtain
|
||||
the message from a specific socket.
|
||||
arguments: recv_ info is a pointer of LibcommRecvInfo* type, pointing to the memory to store the data
|
||||
received.
|
||||
return value: If the receiver has not been determined, call libcomm_tcp_recv_noidx() and take the return value
|
||||
of (libcomm_tcp_recv_noidx (recv_info)); Return RECV_NET_ERROR if there is an error in the
|
||||
process of reading the message heade or message body; If there is no data readable in the
|
||||
receiving buffer of the specified socket at this time or the number of bytes of the data that
|
||||
has been read is not enough, it returns RECV_NEED_RETRY; If iov_item is NULL, it returns
|
||||
RECV_MEM_ERROR if it fails to allocate space for it; If the function runs successfully, then
|
||||
the byte length of the read message head and message body is returned.
|
||||
note: none
|
||||
date: 2022/8/11
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int libcomm_tcp_recv(LibcommRecvInfo* recv_info)
|
||||
{
|
||||
MsgHead* msg_head = NULL;
|
||||
|
|
|
|||
|
|
@ -137,6 +137,16 @@ static int LibCommClientSSLDHVerifyCb(const SSL* s, const SSL_CTX* ctx,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: ssl_cipher_list2string
|
||||
description: This function converts the two-dimensional character array storing the key into a one-dimensional character array.
|
||||
arguments: The first argument represents the two-dimensional character array to be converted.
|
||||
The second argument indicates the number of one-dimensional arrays contained in this two-dimensional array.
|
||||
return value: Returns a pointer to the one-dimensional character array that has been successfully converted. If the conversion fails, NULL is returned.
|
||||
note: none
|
||||
date: 2022/8/12
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
static char* ssl_cipher_list2string(const char* ciphers[], const int num) {
|
||||
int i;
|
||||
int catlen = 0;
|
||||
|
|
@ -227,7 +237,20 @@ char* LibCommErrMessage(void) {
|
|||
return errBuf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
function name: LibCommClientSSLPasswd
|
||||
description: As a client, this function is used to detect whether there is a file with a valid key in the specified
|
||||
directory and whether there is permission to operate it. If so, the password will be decrypted by
|
||||
using the file.
|
||||
arguments: The first parameter is a pointer of type (SSL *).
|
||||
The second parameter is used to obtain the absolute path of the certificate file.
|
||||
The third parameter represents the user name.
|
||||
The fourth parameter is a pointer of type (libcommconn *), whose member variable contains the ciphertext to be decrypted.
|
||||
return value: If the path is empty or does not have operation permission to the directory where the certificate file is located, a non-1 value is returned; otherwise, 0 is returned.
|
||||
note: none
|
||||
date: 2022/8/12
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int LibCommClientSSLPasswd(SSL* pstContext, const char * path, const char * userName, LibCommConn * conn) {
|
||||
char* CertFilesDir = NULL;
|
||||
char CertFilesPath[MAXPATH] = {0};
|
||||
|
|
@ -251,8 +274,8 @@ int LibCommClientSSLPasswd(SSL* pstContext, const char * path, const char * user
|
|||
|
||||
/*check whether the cipher and rand files begins with userName exist.
|
||||
if exist, decrypt it.
|
||||
if not,decrypt the default cipher and rand files begins with client%.
|
||||
Because,for every client user mayown certification and private key*/
|
||||
if not,decrypt the default cipher and rand files begins with client.
|
||||
Because,for every client user may own certification and private key*/
|
||||
if (NULL == userName) {
|
||||
retval = LibCommClientCheckPermissionCipherFile(CertFilesDir, conn, NULL);
|
||||
if (retval != 1)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,16 @@ inline int mc_lqueue_item_size(struct mc_lqueue_item* q_item)
|
|||
return q_item->element.data->iov_len;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_lqueue_add
|
||||
description: Add an element to a specific queue.
|
||||
arguments: The first parameter is a pointer of type (mc_lqueue *), whose member variable list points to the target queue.
|
||||
The second parameter points to the element to be added to the queue.
|
||||
return value: Returns 1 if the element is successfully added to the queue, otherwise returns - 1.
|
||||
note: none
|
||||
date: 2022/8/13
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
int mc_lqueue_add(struct mc_lqueue* q, struct mc_lqueue_item* q_item)
|
||||
{
|
||||
if (q == NULL || q_item == NULL) {
|
||||
|
|
@ -60,6 +70,17 @@ int mc_lqueue_add(struct mc_lqueue* q, struct mc_lqueue_item* q_item)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_lqueue_remove
|
||||
description: Remove the head element in a specific queue.
|
||||
arguments: The first parameter is a pointer of type (mc_lqueue *), whose member variable list points to the target queue.
|
||||
The second parameter points to the queue head element used to store the removal from the queue.
|
||||
return value: Return NULL if an error occurs during the removal of the queue head element, otherwise a pointer to
|
||||
the successfully removed queue head element is returned.
|
||||
note: none
|
||||
date: 2022/8/13
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
struct mc_lqueue_item* mc_lqueue_remove(struct mc_lqueue* q, struct mc_lqueue_item* q_item)
|
||||
{
|
||||
if (q == NULL) {
|
||||
|
|
@ -89,6 +110,18 @@ struct mc_lqueue_item* mc_lqueue_remove(struct mc_lqueue* q, struct mc_lqueue_it
|
|||
return q_item;
|
||||
}
|
||||
|
||||
/*
|
||||
function name: mc_lqueue_init
|
||||
description: This function is used to open an area in the memory area. One part of the area is used to store a queue with
|
||||
a certain specification, and the other part is used to store the information of the queue, such as the specification
|
||||
and the number of elements. Finally, a pointer to the area is returned.
|
||||
arguments: This parameter specifies that the maximum number of elements that the queue can hold is size, but this does
|
||||
not mean that the size of the queue is so large at the beginning.
|
||||
return value: If the function runs successfully, it returns a pointer to the opened memory area; otherwise, it returns NULL.
|
||||
note: none
|
||||
date: 2022/8/13
|
||||
contact tel: 18720816902
|
||||
*/
|
||||
struct mc_lqueue* mc_lqueue_init(unsigned long size)
|
||||
{
|
||||
if (size == 0) {
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ NON_EXEC_STATIC void PercentileMain()
|
|||
g_instance.stat_cxt.force_process = false;
|
||||
sleep(SLEEP_INTERVAL);
|
||||
}
|
||||
elog(LOG, "instrumention percentile ended");
|
||||
gs_thread_exit(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,11 +14,23 @@ import os
|
|||
|
||||
from . import feature_mapping
|
||||
from . import features
|
||||
# To import file feature_mapping and features from parent folder
|
||||
|
||||
#function name: load_feature_lib
|
||||
#description: Print the variable FEATURE_LIB in the file-- features
|
||||
#return value: The value of FEATURE_LIB
|
||||
#date: 2022/8/2
|
||||
#contact: 1865997821
|
||||
|
||||
def load_feature_lib():
|
||||
return features.FEATURE_LIB
|
||||
|
||||
#function name: get_feature_mapper
|
||||
#description: Get the item and value of a dictionary type in the file-- feature_mapping and output it as a generator.
|
||||
#return value: The item and value in _dict_ variable
|
||||
#note:Dictionary key-value pairs must start with C then the item and value will be return.
|
||||
#date: 2022/8/2
|
||||
#contact: 1865997821
|
||||
|
||||
def get_feature_mapper():
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -11,22 +11,27 @@
|
|||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
# See the Mulan PSL v2 for more details.
|
||||
import csv
|
||||
#import csv packet
|
||||
from collections import defaultdict
|
||||
from typing import List
|
||||
# To import defaultdict in the parent floder collections and List in the parent floder typing
|
||||
|
||||
import numpy as np
|
||||
# import numpy packet as the name np
|
||||
|
||||
from ..analyzer import _euclid_distance as euclid_distance
|
||||
from dbmind.common.utils import ExceptionCatch
|
||||
#To import private function-- _euclid_distance as euclid_distance
|
||||
|
||||
#function name: calculate_weight
|
||||
#description: This function will output feature_weight (= residual_vector / the sum of residual_vector)
|
||||
#The data used for the calculation is from the features_labels_dict, and the key value pairs of the features_labels_dict are filtered
|
||||
#arguments: np.ndarray and np.ndarray
|
||||
#return value: weight_matrix
|
||||
#date: 2022/8/2
|
||||
#contact: 1865997821
|
||||
|
||||
def calculate_weight(features: np.ndarray, labels: np.ndarray) -> List:
|
||||
"""
|
||||
Calculate weight matrix based on feature set
|
||||
:param features: feature set
|
||||
:param labels: label set
|
||||
:return: weight_matrix
|
||||
"""
|
||||
normalize_features, normalize_labels = [], []
|
||||
features_labels_dict = defaultdict(list)
|
||||
for i in range(len(labels)):
|
||||
|
|
@ -56,6 +61,16 @@ def calculate_weight(features: np.ndarray, labels: np.ndarray) -> List:
|
|||
return weight_matrix
|
||||
|
||||
|
||||
# function name: build_model
|
||||
# description: Create two variables-- features and labels.There are refer to two numpy array(all elements are zero)
|
||||
# The features array's size is feature_number and dimension is feature_dimension
|
||||
# This function will read the two arrays and write it as a matrix in a csv file(the save path is './features_new.npz')
|
||||
# And then it will call the function calculate_weight to calculate the matrix
|
||||
# arguments: feature_path, feature_number, feature_dimension
|
||||
# return value: None
|
||||
# note:A ExceptionCatch function modifier is used
|
||||
# date: 2022/8/2
|
||||
#contact: 1865997821
|
||||
@ExceptionCatch(strategy='exit', name='FEATURE')
|
||||
def build_model(feature_path: str, feature_number: int, feature_dimension: int,
|
||||
save_path: str = './features_new.npz') -> None:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,13 @@
|
|||
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
# See the Mulan PSL v2 for more details.
|
||||
|
||||
#function name: detect
|
||||
#description: if the method is "bool" type, then call the functions sum_detect、avg_detect、ks_detect to diagnose errors
|
||||
#These functions are in the parent slow_sql/significance_detection
|
||||
#arguments: data1(array), data2(array), method
|
||||
#return value: bool type
|
||||
#date: 2022/8/2
|
||||
#contact: 1865997821
|
||||
|
||||
def detect(data1, data2, method='bool', threshold=0.01, p_value=0.5):
|
||||
if method == 'bool':
|
||||
|
|
|
|||
|
|
@ -12,17 +12,16 @@
|
|||
# See the Mulan PSL v2 for more details.
|
||||
|
||||
alpha = 1e-10
|
||||
#Define a minimum number of errors
|
||||
|
||||
#function name: detect
|
||||
#description: Calculate whether the data has abrupt changes based on the average value
|
||||
#arguments: data1, data2, threshold,method
|
||||
#return value: bool
|
||||
#date: 2022/8/
|
||||
#contact: 1865997821
|
||||
|
||||
def detect(data1, data2, threshold=0.5, method='bool'):
|
||||
"""
|
||||
Calculate whether the data has abrupt changes based on the average value
|
||||
:param data1: input data array
|
||||
:param data2: input data array
|
||||
:param threshold: Mutation rate
|
||||
:param method: The way to calculate the mutation
|
||||
:return: bool
|
||||
"""
|
||||
if not isinstance(data1, list) or not isinstance(data2, list):
|
||||
raise TypeError("The format of the input data is wrong.")
|
||||
avg1 = sum(data1) / len(data1) if data1 else 0
|
||||
|
|
|
|||
|
|
@ -13,8 +13,14 @@
|
|||
import sys
|
||||
|
||||
from .cli import DBMindRun
|
||||
#To import DBMindRun method from the parent file cli
|
||||
|
||||
|
||||
#function name: main
|
||||
#description: Get the system command parameters, pass to the DBMindRun and call this function,if an InterruptedError is reported, the program will exit( sys.exit(1)).
|
||||
#arguments: None
|
||||
#return value: None
|
||||
#date: 2022/8/3
|
||||
#contact: 1865997821
|
||||
def main() -> None:
|
||||
try:
|
||||
DBMindRun(sys.argv[1:])
|
||||
|
|
|
|||
|
|
@ -55,7 +55,12 @@ CONFIG_OPTIONS = {
|
|||
'LOG-level': ['DEBUG', 'INFO', 'WARNING', 'ERROR']
|
||||
}
|
||||
|
||||
|
||||
#function name: check_config_validity
|
||||
#description: Checks the validity of the passed parameter
|
||||
#arguments: section, option, value
|
||||
#return value: bool and string
|
||||
#date: 2022/8/
|
||||
#contact: 1865997821
|
||||
def check_config_validity(section, option, value):
|
||||
config_item = '%s-%s' % (section, option)
|
||||
# exceptional cases:
|
||||
|
|
@ -87,6 +92,16 @@ def check_config_validity(section, option, value):
|
|||
return True, None
|
||||
|
||||
|
||||
|
||||
#function name: load_sys_configs
|
||||
#description: Create and load the modification file
|
||||
#arguments: The configuration to modify
|
||||
#return value: a new configuration file
|
||||
#note:To facilitate the user to modify the configuration items through the
|
||||
#configuration file easily, we add inline comments to the file, but we need to remove the inline comments while parsing.
|
||||
#Otherwise, it will cause the read configuration items to be wrong.
|
||||
#date: 2022/8/
|
||||
#contact: 1865997821
|
||||
def load_sys_configs(confile):
|
||||
# Note: To facilitate the user to modify the configuration items through the
|
||||
# configuration file easily, we add inline comments to the file, but we need
|
||||
|
|
@ -96,6 +111,8 @@ def load_sys_configs(confile):
|
|||
with open(file=confile, mode='r') as fp:
|
||||
configs.read_file(fp)
|
||||
|
||||
|
||||
# Define a class that encapsulates the modification item
|
||||
class ConfigWrapper(object):
|
||||
def __getattribute__(self, name):
|
||||
try:
|
||||
|
|
@ -122,7 +139,7 @@ def load_sys_configs(confile):
|
|||
|
||||
return ConfigWrapper()
|
||||
|
||||
|
||||
# Defines a class that updates the encapsulated modification file
|
||||
class ConfigUpdater:
|
||||
def __init__(self, filepath):
|
||||
self.config = ConfigParser(inline_comment_prefixes=None)
|
||||
|
|
@ -170,7 +187,7 @@ class ConfigUpdater:
|
|||
self.fp.flush()
|
||||
self.fp.close()
|
||||
|
||||
|
||||
# Defines a class that dynamically displays a modified item
|
||||
class DynamicConfig:
|
||||
@staticmethod
|
||||
def get(*args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ except ImportError:
|
|||
|
||||
SKIP_LIST = ('COMMENT', 'LOG')
|
||||
|
||||
# The global variable acts as a switch that controls whether the program runs
|
||||
dbmind_master_should_exit = False
|
||||
|
||||
|
||||
|
|
@ -57,8 +58,16 @@ def _process_clean(force=False):
|
|||
global_vars.worker.terminate(cancel_futures=force)
|
||||
TimedTaskManager.stop()
|
||||
|
||||
#function name: signal_handler
|
||||
#description: The function processes the received signal parameters, reassigns variable x according to different signals
|
||||
#or calls other functions to complete the content indicated by signals
|
||||
#arguments: signum, frame
|
||||
#return value: bool (dbmind_master_should_exit)
|
||||
#date: 2022/8/3
|
||||
#contact: 1865997821
|
||||
|
||||
def signal_handler(signum, frame):
|
||||
# The global variable dbmind_master_should_exit can be modified in this function to continue to play a control role
|
||||
global dbmind_master_should_exit
|
||||
|
||||
if signum == signal.SIGINT or signum == signal.SIGHUP:
|
||||
|
|
@ -148,10 +157,12 @@ class DBMindMain(Daemon):
|
|||
time.sleep(1)
|
||||
logging.info('DBMind will close.')
|
||||
|
||||
# Emptying the execution pool
|
||||
def clean(self):
|
||||
if os.path.exists(self.pid_file):
|
||||
os.unlink(self.pid_file)
|
||||
|
||||
|
||||
# Reload the execution pool and solve the error
|
||||
def reload(self):
|
||||
pid = read_dbmind_pid_file(self.pid_file)
|
||||
if pid > 0:
|
||||
|
|
|
|||
|
|
@ -27,6 +27,17 @@ def do_after(rt_result):
|
|||
def do_exception(exception):
|
||||
"""Nothing"""
|
||||
|
||||
|
||||
#function name: around
|
||||
#description: Preserve the function properties and prevent an error from terminating the program
|
||||
#arguments: One or more functions
|
||||
#return value: none
|
||||
#note: Decorators are implemented in such a way that the function being decorated is actually another function (the function name and other properties change).
|
||||
#To avoid this, Python's FuncTools package provides a decorator called wraps to remove such side effects.
|
||||
#When writing a decorator, it is a good idea to wrap FuncTools before implementing it.
|
||||
#It preserves the name and properties of the original function
|
||||
#date: 2022/8/4
|
||||
#contact: 1865997821
|
||||
def around(func, *args, **kw):
|
||||
@wraps(func)
|
||||
def wrapper():
|
||||
|
|
|
|||
|
|
@ -15,7 +15,11 @@ from typing import Optional, Iterable, Union
|
|||
from .root_cause import RootCause
|
||||
from .enumerations import ALARM_TYPES, ALARM_LEVEL
|
||||
|
||||
|
||||
#Define an Alarm class that takes the error parameters entered by the user and displays the error content and cause
|
||||
#method:Display the error content and suggestions, and retrieve suggestions provided by the system. If there are no suggestions, return “ no suggestions”
|
||||
#note:The property decorator turns a method into a property call.(root_causes、suggestions)
|
||||
#date:2022/8/4
|
||||
#contact:18365997821
|
||||
class Alarm:
|
||||
def __init__(self,
|
||||
host: Union[str],
|
||||
|
|
|
|||
|
|
@ -12,7 +12,11 @@
|
|||
# See the Mulan PSL v2 for more details.
|
||||
from .root_cause import RootCause
|
||||
|
||||
|
||||
#Define anSlowQuery class thatSlow query accepts user input commands and performs operations on the database
|
||||
#method:Display the error content and suggestions, and retrieve suggestions provided by the system. If there are no suggestions, return “ no suggestions”
|
||||
#note:The property decorator turns a method into a property call.(root_causes、suggestions)
|
||||
#date:2022/8/4
|
||||
#contact:18365997821
|
||||
class SlowQuery:
|
||||
def __init__(self, db_host, db_port, db_name, schema_name, query, start_timestamp, duration_time,
|
||||
hit_rate=None, fetch_rate=None, cpu_time=None, data_io_time=None, template_id=None, sort_count=None,
|
||||
|
|
|
|||
|
|
@ -18,13 +18,19 @@ import psycopg2
|
|||
from .execute_factory import ExecuteFactory
|
||||
from .execute_factory import IndexInfo
|
||||
|
||||
#class name: DriverExecute (Inherits from the parent class ExecuteFactory)
|
||||
#description: The SQL statement performs the operations associated with the call
|
||||
#date: 2022/8/10
|
||||
#contact: 1865997821
|
||||
|
||||
class DriverExecute(ExecuteFactory):
|
||||
def __init__(self, *arg):
|
||||
#Call the arguments of the parent class __init__ method
|
||||
super(DriverExecute, self).__init__(*arg)
|
||||
self.conn = None
|
||||
self.cur = None
|
||||
|
||||
#Connecting to the database
|
||||
def init_conn_handle(self):
|
||||
self.conn = psycopg2.connect(dbname=self.dbname,
|
||||
user=self.user,
|
||||
|
|
@ -33,6 +39,7 @@ class DriverExecute(ExecuteFactory):
|
|||
port=self.port)
|
||||
self.cur = self.conn.cursor()
|
||||
|
||||
#If an error occurs after the SQL statement is executed, the error information is reported to the user
|
||||
def execute(self, sql):
|
||||
try:
|
||||
self.cur.execute(sql)
|
||||
|
|
@ -41,11 +48,13 @@ class DriverExecute(ExecuteFactory):
|
|||
except Exception:
|
||||
self.conn.commit()
|
||||
|
||||
#Disconnecting from the database
|
||||
def close_conn(self):
|
||||
if self.conn and self.cur:
|
||||
self.cur.close()
|
||||
self.conn.close()
|
||||
|
||||
#Check whether multiple nodes exist
|
||||
def is_multi_node(self):
|
||||
self.init_conn_handle()
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@
|
|||
|
||||
import re
|
||||
|
||||
#class name: IndexInfo
|
||||
#description: Define information about table indexes
|
||||
#methods: __init__
|
||||
#date: 2022/8/10
|
||||
#contact: 1865997821
|
||||
|
||||
class IndexInfo:
|
||||
def __init__(self, schema, table, indexname, columns, indexdef):
|
||||
|
|
@ -24,7 +29,9 @@ class IndexInfo:
|
|||
self.primary_key = False
|
||||
self.redundant_obj = []
|
||||
|
||||
|
||||
#class name: ExecuteFactory
|
||||
#date: 2022/8/10
|
||||
#contact: 1865997821
|
||||
class ExecuteFactory:
|
||||
def __init__(self, dbname, user, password, host, port, schema, multi_node, max_index_storage):
|
||||
self.dbname = dbname
|
||||
|
|
@ -36,11 +43,11 @@ class ExecuteFactory:
|
|||
self.max_index_storage = max_index_storage
|
||||
self.multi_node = multi_node
|
||||
|
||||
# Record redundant indexes
|
||||
@staticmethod
|
||||
def record_redundant_indexes(cur_table_indexes, redundant_indexes):
|
||||
cur_table_indexes = sorted(cur_table_indexes,
|
||||
key=lambda index_obj: len(index_obj.columns.split(',')))
|
||||
# record redundant indexes
|
||||
for pos, index in enumerate(cur_table_indexes[:-1]):
|
||||
is_redundant = False
|
||||
for candidate_index in cur_table_indexes[pos + 1:]:
|
||||
|
|
@ -52,6 +59,7 @@ class ExecuteFactory:
|
|||
if is_redundant:
|
||||
redundant_indexes.append(index)
|
||||
|
||||
#Match the name of the table against the index of the query
|
||||
@staticmethod
|
||||
def match_table_name(table_name, query_index_dict):
|
||||
for elem in query_index_dict.keys():
|
||||
|
|
@ -66,6 +74,7 @@ class ExecuteFactory:
|
|||
return False, table_name
|
||||
return True, table_name
|
||||
|
||||
#Retrieves a valid index based on the regular expression, adding the corresponding index and empty element if none exists
|
||||
@staticmethod
|
||||
def get_valid_indexes(record, hypoid_table_column, valid_indexes):
|
||||
tokens = record.split(' ')
|
||||
|
|
@ -88,6 +97,7 @@ class ExecuteFactory:
|
|||
if columns not in valid_indexes[table_name]:
|
||||
valid_indexes[table_name].append((columns, index_type))
|
||||
|
||||
#Record invalid SQL statements and returns the corresponding help information that matches the corresponding SQL statement
|
||||
@staticmethod
|
||||
def record_ineffective_negative_sql(candidate_index, obj, ind):
|
||||
cur_table = candidate_index.table
|
||||
|
|
@ -125,6 +135,7 @@ class ExecuteFactory:
|
|||
candidate_index.ineffective_pos.append(ind)
|
||||
candidate_index.total_sql_num += obj.frequency
|
||||
|
||||
#Returns the last input and the corresponding result
|
||||
@staticmethod
|
||||
def match_last_result(table_name, index_column, history_indexes, history_invalid_indexes):
|
||||
for column in history_indexes.get(table_name, dict()):
|
||||
|
|
@ -142,6 +153,7 @@ class ExecuteFactory:
|
|||
if not history_indexes[table_name]:
|
||||
del history_indexes[table_name]
|
||||
|
||||
#Correcting SQL statements
|
||||
@staticmethod
|
||||
def make_single_advisor_sql(ori_sql):
|
||||
sql = 'select gs_index_advise(\''
|
||||
|
|
|
|||
|
|
@ -23,12 +23,16 @@ from .execute_factory import IndexInfo
|
|||
|
||||
BASE_CMD = None
|
||||
|
||||
|
||||
#class name: GSqlExecute
|
||||
#description: Solve the optimization problem of GSQL statement execution
|
||||
#date: 2022/8/11
|
||||
#contact: 1865997821
|
||||
class GSqlExecute(ExecuteFactory):
|
||||
def __init__(self, *args):
|
||||
super(GSqlExecute, self).__init__(*args)
|
||||
|
||||
def init_conn_handle(self):
|
||||
#define a global variable BASE_CMD,it is a connection command statement
|
||||
global BASE_CMD
|
||||
BASE_CMD = 'gsql -p ' + str(self.port) + ' -d ' + self.dbname
|
||||
if self.host:
|
||||
|
|
@ -38,6 +42,7 @@ class GSqlExecute(ExecuteFactory):
|
|||
if self.password:
|
||||
BASE_CMD += ' -W ' + self.password
|
||||
|
||||
#Run the shell command in BASE_CMD
|
||||
def run_shell_cmd(self, target_sql_list):
|
||||
cmd = BASE_CMD + ' -c \"'
|
||||
if self.schema:
|
||||
|
|
@ -47,6 +52,7 @@ class GSqlExecute(ExecuteFactory):
|
|||
cmd += '\"'
|
||||
proc = subprocess.Popen(
|
||||
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
||||
#Read data from stdout and stderr,If an error message is displayed, an error message is displayed
|
||||
(stdout, stderr) = proc.communicate()
|
||||
stdout, stderr = stdout.decode(), stderr.decode()
|
||||
if 'gsql: FATAL:' in stderr or 'failed to connect' in stderr:
|
||||
|
|
@ -74,6 +80,7 @@ class GSqlExecute(ExecuteFactory):
|
|||
print(e.output.decode(), file=sys.stderr)
|
||||
return int(ret.decode().strip().split()[2]) > 0
|
||||
|
||||
#Parse the recommended result returned
|
||||
@staticmethod
|
||||
def parse_single_advisor_result(res, table_index_dict):
|
||||
if len(res) > 2 and res[0:2] == ' (':
|
||||
|
|
@ -183,6 +190,7 @@ class GSqlExecute(ExecuteFactory):
|
|||
total_cost = 0
|
||||
found_plan = False
|
||||
hypo_index = False
|
||||
# create hypo-indexes
|
||||
for line in res:
|
||||
if 'QUERY PLAN' in line:
|
||||
found_plan = True
|
||||
|
|
@ -222,6 +230,7 @@ class GSqlExecute(ExecuteFactory):
|
|||
i += 1
|
||||
return total_cost
|
||||
|
||||
#Production workflows consume report files
|
||||
def estimate_workload_cost_file(self, workload, index_config=None, ori_indexes_name=None):
|
||||
sql_file = str(time.time()) + '.sql'
|
||||
is_computed = False
|
||||
|
|
@ -264,6 +273,7 @@ class GSqlExecute(ExecuteFactory):
|
|||
|
||||
return total_cost
|
||||
|
||||
#Check for empty indexes and note them to optimize the table structure
|
||||
def check_useless_index(self, history_indexes, history_invalid_indexes):
|
||||
schemas = [elem.lower()
|
||||
for elem in filter(None, self.schema.split(','))]
|
||||
|
|
|
|||
|
|
@ -26,9 +26,11 @@ import logging
|
|||
try:
|
||||
from .dao.gsql_execute import GSqlExecute
|
||||
from .dao.execute_factory import ExecuteFactory
|
||||
from .mcts import MCTS
|
||||
except ImportError:
|
||||
from dao.gsql_execute import GSqlExecute
|
||||
from dao.execute_factory import ExecuteFactory
|
||||
from mcts import MCTS
|
||||
|
||||
ENABLE_MULTI_NODE = False
|
||||
SAMPLE_NUM = 5
|
||||
|
|
@ -192,9 +194,12 @@ class IndexAdvisor:
|
|||
self.workload_used_index))
|
||||
if DRIVER:
|
||||
self.db.close_conn()
|
||||
|
||||
opt_config = greedy_determine_opt_config(self.workload_info[0], atomic_config_total,
|
||||
candidate_indexes, self.index_cost_total[0])
|
||||
if MAX_INDEX_STORAGE:
|
||||
opt_config = MCTS(self.workload_info[0], atomic_config_total, candidate_indexes,
|
||||
MAX_INDEX_STORAGE, MAX_INDEX_NUM)
|
||||
else:
|
||||
opt_config = greedy_determine_opt_config(self.workload_info[0], atomic_config_total,
|
||||
candidate_indexes, self.index_cost_total[0])
|
||||
self.retain_lower_cost_index(candidate_indexes)
|
||||
if len(opt_config) == 0:
|
||||
print("No optimal indexes generated!")
|
||||
|
|
@ -943,7 +948,7 @@ def check_parameter(args):
|
|||
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
|
||||
args.max_index_num)
|
||||
if args.max_index_storage is not None and args.max_index_storage <= 0:
|
||||
raise argparse.ArgumentTypeError("%s is an invalid positive int value" %
|
||||
raise argparse.ArgumentTypeError("%s is an invalid positive float value" %
|
||||
args.max_index_storage)
|
||||
JSON_TYPE = args.json
|
||||
MAX_INDEX_NUM = args.max_index_num
|
||||
|
|
@ -971,7 +976,7 @@ def main(argv):
|
|||
arg_parser.add_argument(
|
||||
"--max_index_num", help="Maximum number of suggested indexes", type=int)
|
||||
arg_parser.add_argument("--max_index_storage",
|
||||
help="Maximum storage of suggested indexes/MB", type=int)
|
||||
help="Maximum storage of suggested indexes/MB", type=float)
|
||||
arg_parser.add_argument("--multi_iter_mode", action='store_true',
|
||||
help="Whether to use multi-iteration algorithm", default=False)
|
||||
arg_parser.add_argument("--multi_node", action='store_true',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,397 @@
|
|||
import sys
|
||||
import math
|
||||
import random
|
||||
import copy
|
||||
|
||||
STORAGE_THRESHOLD = 0
|
||||
AVAILABLE_CHOICES = None
|
||||
ATOMIC_CHOICES = None
|
||||
WORKLOAD_INFO = None
|
||||
MAX_INDEX_NUM = 0
|
||||
|
||||
|
||||
def is_same_index(index, compared_index):
|
||||
return index.table == compared_index.table and \
|
||||
index.columns == compared_index.columns and \
|
||||
index.index_type == compared_index.index_type
|
||||
|
||||
|
||||
def atomic_config_is_valid(atomic_config, config):
|
||||
# if candidate indexes contains all atomic index of current config1, then record it
|
||||
for atomic_index in atomic_config:
|
||||
is_exist = False
|
||||
for index in config:
|
||||
if is_same_index(index, atomic_index):
|
||||
index.storage = atomic_index.storage
|
||||
is_exist = True
|
||||
break
|
||||
if not is_exist:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def find_subsets_num(choice):
|
||||
atomic_subsets_num = []
|
||||
for pos, atomic in enumerate(ATOMIC_CHOICES):
|
||||
if not atomic or len(atomic) > len(choice):
|
||||
continue
|
||||
# find valid atomic index
|
||||
if atomic_config_is_valid(atomic, choice):
|
||||
atomic_subsets_num.append(pos)
|
||||
# find the same atomic index as the candidate index
|
||||
if len(atomic) == 1 and (is_same_index(choice[-1], atomic[0])):
|
||||
choice[-1].atomic_pos = pos
|
||||
return atomic_subsets_num
|
||||
|
||||
|
||||
def find_best_benefit(choice):
|
||||
atomic_subsets_num = find_subsets_num(choice)
|
||||
total_benefit = 0
|
||||
for ind, obj in enumerate(WORKLOAD_INFO):
|
||||
# calculate the best benefit for the current sql
|
||||
max_benefit = 0
|
||||
for pos in atomic_subsets_num:
|
||||
if (obj.cost_list[0] - obj.cost_list[pos]) > max_benefit:
|
||||
max_benefit = obj.cost_list[0] - obj.cost_list[pos]
|
||||
total_benefit += max_benefit
|
||||
return total_benefit
|
||||
|
||||
|
||||
def get_diff(available_choices, choices):
|
||||
except_choices = copy.copy(available_choices)
|
||||
for i in available_choices:
|
||||
for j in choices:
|
||||
if is_same_index(i, j):
|
||||
except_choices.remove(i)
|
||||
return except_choices
|
||||
|
||||
|
||||
class State(object):
|
||||
"""
|
||||
The game state of the Monte Carlo tree search,
|
||||
the state data recorded under a certain Node node,
|
||||
including the current game score, the current number of game rounds,
|
||||
and the execution record from the beginning to the current.
|
||||
|
||||
It is necessary to realize whether the current state has reached the end of the game state,
|
||||
and support the operation of randomly fetching from the Action collection.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.current_storage = 0.0
|
||||
self.current_benefit = 0.0
|
||||
# record the sum of choices up to the current state
|
||||
self.accumulation_choices = []
|
||||
# record available choices of current state
|
||||
self.available_choices = []
|
||||
self.displayable_choices = []
|
||||
|
||||
def get_available_choices(self):
|
||||
return self.available_choices
|
||||
|
||||
def set_available_choices(self, choices):
|
||||
self.available_choices = choices
|
||||
|
||||
def get_current_storage(self):
|
||||
return self.current_storage
|
||||
|
||||
def set_current_storage(self, value):
|
||||
self.current_storage = value
|
||||
|
||||
def get_current_benefit(self):
|
||||
return self.current_benefit
|
||||
|
||||
def set_current_benefit(self, value):
|
||||
self.current_benefit = value
|
||||
|
||||
def get_accumulation_choices(self):
|
||||
return self.accumulation_choices
|
||||
|
||||
def set_accumulation_choices(self, choices):
|
||||
self.accumulation_choices = choices
|
||||
|
||||
def is_terminal(self):
|
||||
# the current node is a leaf node
|
||||
return len(self.accumulation_choices) == MAX_INDEX_NUM
|
||||
|
||||
def compute_benefit(self):
|
||||
return self.current_benefit
|
||||
|
||||
def get_next_state_with_random_choice(self):
|
||||
# ensure that the choices taken are not repeated
|
||||
if not self.available_choices:
|
||||
return None
|
||||
random_choice = random.choice([choice for choice in self.available_choices])
|
||||
self.available_choices.remove(random_choice)
|
||||
choice = copy.copy(self.accumulation_choices)
|
||||
choice.append(random_choice)
|
||||
benefit = find_best_benefit(choice)
|
||||
# if current choice not satisfy restrictions, then continue get next choice
|
||||
if benefit <= self.current_benefit or \
|
||||
self.current_storage + random_choice.storage > STORAGE_THRESHOLD:
|
||||
return self.get_next_state_with_random_choice()
|
||||
|
||||
next_state = State()
|
||||
# initialize the properties of the new state
|
||||
next_state.set_accumulation_choices(choice)
|
||||
next_state.set_current_benefit(benefit)
|
||||
next_state.set_current_storage(self.current_storage + random_choice.storage)
|
||||
next_state.set_available_choices(get_diff(AVAILABLE_CHOICES, choice))
|
||||
return next_state
|
||||
|
||||
def __repr__(self):
|
||||
self.displayable_choices = ['{}: {}'.format(choice.table, choice.columns)
|
||||
for choice in self.accumulation_choices]
|
||||
return "reward: {}, storage :{}, choices: {}".format(
|
||||
self.current_benefit, self.current_storage, self.displayable_choices)
|
||||
|
||||
|
||||
class Node(object):
|
||||
"""
|
||||
The Node of the Monte Carlo tree search tree contains the parent node and
|
||||
current point information,
|
||||
which is used to calculate the traversal times and quality value of the UCB,
|
||||
and the State of the Node selected by the game.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.visit_number = 0
|
||||
self.quality = 0.0
|
||||
|
||||
self.parent = None
|
||||
self.children = []
|
||||
self.state = None
|
||||
|
||||
def get_parent(self):
|
||||
return self.parent
|
||||
|
||||
def set_parent(self, parent):
|
||||
self.parent = parent
|
||||
|
||||
def get_children(self):
|
||||
return self.children
|
||||
|
||||
def expand_child(self, node):
|
||||
node.set_parent(self)
|
||||
self.children.append(node)
|
||||
|
||||
def set_state(self, state):
|
||||
self.state = state
|
||||
|
||||
def get_state(self):
|
||||
return self.state
|
||||
|
||||
def get_visit_number(self):
|
||||
return self.visit_number
|
||||
|
||||
def set_visit_number(self, number):
|
||||
self.visit_number = number
|
||||
|
||||
def update_visit_number(self):
|
||||
self.visit_number += 1
|
||||
|
||||
def get_quality_value(self):
|
||||
return self.quality
|
||||
|
||||
def set_quality_value(self, value):
|
||||
self.quality = value
|
||||
|
||||
def update_quality_value(self, reward):
|
||||
self.quality += reward
|
||||
|
||||
def is_all_expand(self):
|
||||
return len(self.children) == \
|
||||
len(AVAILABLE_CHOICES) - len(self.get_state().get_accumulation_choices())
|
||||
|
||||
def __repr__(self):
|
||||
return "Node: {}, Q/N: {}/{}, State: {}".format(
|
||||
hash(self), self.quality, self.visit_number, self.state)
|
||||
|
||||
|
||||
def tree_policy(node):
|
||||
"""
|
||||
In the Selection and Expansion stages of Monte Carlo tree search,
|
||||
the node that needs to be searched (such as the root node) is passed in,
|
||||
and the best node that needs to be expanded is returned
|
||||
according to the exploration/exploitation algorithm.
|
||||
Note that if the node is a leaf node, it will be returned directly.
|
||||
|
||||
The basic strategy is to first find the child nodes that have not been selected at present,
|
||||
and select them randomly if there are more than one. If both are selected,
|
||||
find the one with the largest UCB value that has weighed exploration/exploitation,
|
||||
and randomly select if the UCB values are equal.
|
||||
"""
|
||||
|
||||
# check if the current node is leaf node
|
||||
while node and not node.get_state().is_terminal():
|
||||
|
||||
if node.is_all_expand():
|
||||
node = best_child(node, True)
|
||||
else:
|
||||
# return the new sub node
|
||||
sub_node = expand(node)
|
||||
# when there is no node that satisfies the condition in the remaining nodes,
|
||||
# this state is empty
|
||||
if sub_node.get_state():
|
||||
return sub_node
|
||||
|
||||
# return the leaf node
|
||||
return node
|
||||
|
||||
|
||||
def default_policy(node):
|
||||
"""
|
||||
In the Simulation stage of Monte Carlo tree search, input a node that needs to be expanded,
|
||||
create a new node after random operation, and return the reward of the new node.
|
||||
Note that the input node should not be a child node,
|
||||
and there are unexecuted Actions that can be expendable.
|
||||
|
||||
The basic strategy is to choose the Action at random.
|
||||
"""
|
||||
|
||||
# get the state of the game
|
||||
current_state = copy.deepcopy(node.get_state())
|
||||
|
||||
# run until the game over
|
||||
while not current_state.is_terminal():
|
||||
# pick one random action to play and get next state
|
||||
next_state = current_state.get_next_state_with_random_choice()
|
||||
if not next_state:
|
||||
break
|
||||
current_state = next_state
|
||||
|
||||
final_state_reward = current_state.compute_benefit()
|
||||
return final_state_reward
|
||||
|
||||
|
||||
def expand(node):
|
||||
"""
|
||||
Enter a node, expand a new node on the node, use the random method to execute the Action,
|
||||
and return the new node. Note that it is necessary to ensure that the newly
|
||||
added nodes are different from other node Action
|
||||
"""
|
||||
|
||||
new_state = node.get_state().get_next_state_with_random_choice()
|
||||
sub_node = Node()
|
||||
sub_node.set_state(new_state)
|
||||
node.expand_child(sub_node)
|
||||
|
||||
return sub_node
|
||||
|
||||
|
||||
def best_child(node, is_exploration):
|
||||
"""
|
||||
Using the UCB algorithm,
|
||||
select the child node with the highest score after weighing the exploration and exploitation.
|
||||
Note that if it is the prediction stage,
|
||||
the current Q-value score with the highest score is directly selected.
|
||||
"""
|
||||
|
||||
best_score = -sys.maxsize
|
||||
best_sub_node = None
|
||||
|
||||
# travel all sub nodes to find the best one
|
||||
for sub_node in node.get_children():
|
||||
# The children nodes of the node contains the children node whose state is empty,
|
||||
# this kind of node comes from the node that does not meet the conditions.
|
||||
if not sub_node.get_state():
|
||||
continue
|
||||
# ignore exploration for inference
|
||||
if is_exploration:
|
||||
C = 1 / math.sqrt(2.0)
|
||||
else:
|
||||
C = 0.0
|
||||
|
||||
# UCB = quality / times + C * sqrt(2 * ln(total_times) / times)
|
||||
left = sub_node.get_quality_value() / sub_node.get_visit_number()
|
||||
right = 2.0 * math.log(node.get_visit_number()) / sub_node.get_visit_number()
|
||||
score = left + C * math.sqrt(right)
|
||||
# get the maximum score, while filtering nodes that do not meet the space constraints and
|
||||
# nodes that have no revenue
|
||||
if score > best_score \
|
||||
and sub_node.get_state().get_current_storage() <= STORAGE_THRESHOLD \
|
||||
and sub_node.get_state().get_current_benefit() > 0:
|
||||
best_sub_node = sub_node
|
||||
best_score = score
|
||||
|
||||
return best_sub_node
|
||||
|
||||
|
||||
def backpropagate(node, reward):
|
||||
"""
|
||||
In the Backpropagation stage of Monte Carlo tree search,
|
||||
input the node that needs to be expended and the reward of the newly executed Action,
|
||||
feed it back to the expend node and all upstream nodes,
|
||||
and update the corresponding data.
|
||||
"""
|
||||
|
||||
# update util the root node
|
||||
while node is not None:
|
||||
# update the visit number
|
||||
node.update_visit_number()
|
||||
|
||||
# update the quality value
|
||||
node.update_quality_value(reward)
|
||||
|
||||
# change the node to the parent node
|
||||
node = node.parent
|
||||
|
||||
|
||||
def monte_carlo_tree_search(node):
|
||||
"""
|
||||
Implement the Monte Carlo tree search algorithm, pass in a root node,
|
||||
expand new nodes and update data according to the
|
||||
tree structure that has been explored before in a limited time,
|
||||
and then return as long as the child node with the highest exploitation.
|
||||
|
||||
When making predictions,
|
||||
you only need to select the node with the largest exploitation according to the Q value,
|
||||
and find the next optimal node.
|
||||
"""
|
||||
|
||||
computation_budget = len(AVAILABLE_CHOICES) * 3
|
||||
|
||||
# run as much as possible under the computation budget
|
||||
for i in range(computation_budget):
|
||||
# 1. find the best node to expand
|
||||
expand_node = tree_policy(node)
|
||||
if not expand_node:
|
||||
# when it is None, it means that all nodes are added but no nodes meet the space limit
|
||||
break
|
||||
# 2. random get next action and get reward
|
||||
reward = default_policy(expand_node)
|
||||
|
||||
# 3. update all passing nodes with reward
|
||||
backpropagate(expand_node, reward)
|
||||
|
||||
# get the best next node
|
||||
best_next_node = best_child(node, False)
|
||||
|
||||
return best_next_node
|
||||
|
||||
|
||||
def MCTS(workload_info, atomic_choices, available_choices, storage_threshold, max_index_num):
|
||||
global ATOMIC_CHOICES, STORAGE_THRESHOLD, WORKLOAD_INFO, AVAILABLE_CHOICES, MAX_INDEX_NUM
|
||||
WORKLOAD_INFO = workload_info
|
||||
AVAILABLE_CHOICES = available_choices
|
||||
ATOMIC_CHOICES = atomic_choices
|
||||
STORAGE_THRESHOLD = storage_threshold
|
||||
MAX_INDEX_NUM = max_index_num if max_index_num else len(available_choices)
|
||||
|
||||
# create the initialized state and initialized node
|
||||
init_state = State()
|
||||
choices = copy.copy(available_choices)
|
||||
init_state.set_available_choices(choices)
|
||||
init_node = Node()
|
||||
init_node.set_state(init_state)
|
||||
current_node = init_node
|
||||
|
||||
opt_config = []
|
||||
# set the rounds to play
|
||||
for i in range(len(AVAILABLE_CHOICES)):
|
||||
if current_node:
|
||||
current_node = monte_carlo_tree_search(current_node)
|
||||
if current_node:
|
||||
opt_config = current_node.state.accumulation_choices
|
||||
else:
|
||||
break
|
||||
return opt_config
|
||||
|
|
@ -539,13 +539,14 @@ class RnnModel():
|
|||
keras.backend.clear_session()
|
||||
set_session(self.session)
|
||||
with self.graph.as_default():
|
||||
# Judge whether the model needs to be initialized according to the changes of the model input and output dimensions.
|
||||
feature, label, need_init = self.parse(filename)
|
||||
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
|
||||
epsilon = self.model_info.make_epsilon()
|
||||
if need_init:
|
||||
if need_init:# Cold start training
|
||||
epoch_start = 0
|
||||
self.model = self._build_model(epsilon)
|
||||
else:
|
||||
else:# Incremental training
|
||||
epoch_start = int(self.model_info.last_epoch)
|
||||
ratio_error = ratio_error_loss_wrapper(epsilon)
|
||||
ratio_acc_2 = ratio_error_acc_wrapper(epsilon, 2)
|
||||
|
|
@ -556,12 +557,16 @@ class RnnModel():
|
|||
log_path = os.path.realpath(os.path.join(settings.PATH_LOG, self.model_info.model_name + '_log.json'))
|
||||
if not os.path.exists(log_path):
|
||||
os.mknod(log_path, mode=0o600)
|
||||
# Training logging callback function
|
||||
json_logging_callback = LossHistory(log_path, self.model_info.model_name, self.model_info.last_epoch)
|
||||
# Data segmentation
|
||||
X_train, X_val, y_train, y_val = \
|
||||
train_test_split(feature, label, test_size=0.1)
|
||||
# model training
|
||||
self.model.fit(X_train, y_train, epochs=self.model_info.last_epoch,
|
||||
batch_size=int(self.model_info.batch_size), validation_data=(X_val, y_val),
|
||||
verbose=0, initial_epoch=epoch_start, callbacks=[json_logging_callback])
|
||||
# save model
|
||||
self.model.save(self.model_info.model_path)
|
||||
val_pred = self.model.predict(X_val)
|
||||
val_re = get_ratio_errors_general(val_pred, y_val, epsilon)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ from . import AbstractModel
|
|||
|
||||
|
||||
class TemplateModel(AbstractModel):
|
||||
# Initialize algorithm parameters
|
||||
def __init__(self, params):
|
||||
super().__init__(params)
|
||||
self.bias = 1e-5
|
||||
|
|
|
|||
|
|
@ -173,11 +173,16 @@ def procedure_main(mode, db_info, config):
|
|||
def rl_model(mode, env, config):
|
||||
# Lazy loading. Because loading Tensorflow takes a long time.
|
||||
from tuner.algorithms.rl_agent import RLAgent
|
||||
# Start reinforcement learning agent class.
|
||||
rl = RLAgent(env, alg=config['rl_algorithm'])
|
||||
# The two modes of training and tuning correspond to different execution processes.
|
||||
# The model needs to be trained before it can be used for tuning. The output of the training and tuning process is the list of parameters to be tuned. Because they share a set of models, it is required that the list of parameters to be tuned must be consistent in the two modes, otherwise exceptions with different output dimensions will be thrown.
|
||||
if mode == 'train':
|
||||
logging.warning('The list of tuned knobs in the training mode '
|
||||
'based on the reinforcement learning algorithm must be the same as '
|
||||
'that in the tuning mode. ')
|
||||
# The key parameter is the maximum iteration round rl_ steps, theoretically, the longer the more accurate, but also more time-consuming.
|
||||
# max_episode_steps is the maximum number of rounds in each round of reinforcement learning algorithm. In the implementation of x-tuner, this parameter is weakened, and it is generally default.
|
||||
rl.fit(config['rl_steps'], nb_max_episode_steps=config['max_episode_steps'])
|
||||
rl.save(config['rl_model_path'])
|
||||
logging.info('Saved reinforcement learning model at %s.', config['rl_model_path'])
|
||||
|
|
@ -200,6 +205,7 @@ def rl_model(mode, env, config):
|
|||
|
||||
def global_search(env, config):
|
||||
method = config['gop_algorithm']
|
||||
# Determine which algorithm to use.
|
||||
if method == 'bayes':
|
||||
from bayes_opt import BayesianOptimization
|
||||
|
||||
|
|
@ -207,6 +213,13 @@ def global_search(env, config):
|
|||
pbound = {name: (0, 1) for name in env.db.ordered_knob_list}
|
||||
|
||||
def performance_function(**params):
|
||||
"""
|
||||
function name: performance_function
|
||||
description: Define a black box function to adapt to the interface of the third-party library.
|
||||
author: Li Xinran
|
||||
date: 2022/8/4
|
||||
contact: 19154068808
|
||||
"""
|
||||
if not len(params) == env.nb_actions:
|
||||
raise AssertionError('Failed to check the input feature dimension.')
|
||||
|
||||
|
|
@ -222,12 +235,21 @@ def global_search(env, config):
|
|||
pbounds=pbound
|
||||
)
|
||||
optimizer.maximize(
|
||||
# The larger the maximum iteration round, the more accurate the result is, but it is also more time-consuming.
|
||||
n_iter=config['max_iterations']
|
||||
)
|
||||
elif method == 'pso':
|
||||
from tuner.algorithms.pso import Pso
|
||||
|
||||
def performance_function(v):
|
||||
"""
|
||||
function name: performance_function
|
||||
description: Find the global minimum value.
|
||||
note: Because the implementation of PSO algorithm is to find the global minimum value, take the opposite number here, so we need to change to take the global maximum value.
|
||||
author: Li Xinran
|
||||
date: 2022/8/4
|
||||
contact: 19154068808
|
||||
"""
|
||||
s, r, d, _ = env.step(v)
|
||||
return -r # Use -reward because PSO wishes to minimize.
|
||||
|
||||
|
|
@ -237,6 +259,7 @@ def global_search(env, config):
|
|||
particle_nums=config['particle_nums'],
|
||||
# max_iterations on the PSO indicates the maximum number of iterations per particle,
|
||||
# so it must be divided by the number of particles to be consistent with Bayes.
|
||||
# The larger the maximum iteration round is, the more accurate the result is, but also the more time-consuming.
|
||||
max_iteration=config['max_iterations'] // config['particle_nums'],
|
||||
x_min=0, x_max=1, max_vel=0.5
|
||||
)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ from collections.abc import Iterable
|
|||
from collections import defaultdict
|
||||
|
||||
import index_advisor_workload as iaw
|
||||
import mcts
|
||||
|
||||
|
||||
def hash_any(obj):
|
||||
|
|
@ -227,6 +228,32 @@ select * from student_range_part1 where credit=1;
|
|||
|
||||
class IndexAdvisorTester(unittest.TestCase):
|
||||
|
||||
def test_mcts(self):
|
||||
storage_threshold = 12
|
||||
index1 = iaw.IndexItem('public.a', 'col1', index_type='global')
|
||||
index2 = iaw.IndexItem('public.b', 'col1', index_type='global')
|
||||
index3 = iaw.IndexItem('public.c', 'col1', index_type='global')
|
||||
index4 = iaw.IndexItem('public.d', 'col1', index_type='global')
|
||||
|
||||
atomic_index1 = iaw.IndexItem('public.a', 'col1', index_type='global')
|
||||
atomic_index2 = iaw.IndexItem('public.b', 'col1', index_type='global')
|
||||
atomic_index3 = iaw.IndexItem('public.c', 'col1', index_type='global')
|
||||
atomic_index4 = iaw.IndexItem('public.d', 'col1', index_type='global')
|
||||
|
||||
atomic_index1.storage = 10
|
||||
atomic_index2.storage = 4
|
||||
atomic_index3.storage = 7
|
||||
available_choices = [index1, index2, index3, index4]
|
||||
atomic_choices = [[], [atomic_index2], [atomic_index1], [atomic_index3],
|
||||
[atomic_index2, atomic_index3], [atomic_index4]]
|
||||
query = iaw.QueryItem('select * from gia_01', 1)
|
||||
query.cost_list = [10, 7, 5, 9, 4, 11]
|
||||
workload_info = [query]
|
||||
|
||||
results = mcts.MCTS(workload_info, atomic_choices, available_choices, storage_threshold, 2)
|
||||
self.assertLessEqual([index1.atomic_pos, index2.atomic_pos, index3.atomic_pos], [2, 1, 3])
|
||||
self.assertSetEqual({results[0].table, results[1].table}, {'public.b', 'public.c'})
|
||||
|
||||
def test_get_indexable_columns(self):
|
||||
tables = 'table1 table2 table2 table3 table3 table3'.split()
|
||||
columns = 'col1,col2 col2 col3 col1,col2 col2,col3 col2,col5'.split()
|
||||
|
|
|
|||
|
|
@ -90,7 +90,10 @@ static void DropExtensionInListIsSupported(List* objname)
|
|||
}
|
||||
}
|
||||
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("EXTENSION is not yet supported.")));
|
||||
/* Enable DROP operation of the above objects during inplace upgrade or support_extended_features is true */
|
||||
if (!u_sess->attr.attr_common.IsInplaceUpgrade && !g_instance.attr.attr_common.support_extended_features) {
|
||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("EXTENSION is not yet supported.")));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1175,7 +1175,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
|
|||
FEATURE_NOT_PUBLIC_ERROR("EXTENSION is not yet supported.");
|
||||
}
|
||||
|
||||
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
|
||||
if (pg_strcasecmp(stmt->extname, "dolphin") == 0 && !DB_IS_CMPT(B_FORMAT)) {
|
||||
ereport(ERROR,
|
||||
(errmsg("please create extension \"%s\" with B type DBCOMPATIBILITY", stmt->extname)));
|
||||
}
|
||||
|
|
@ -1418,8 +1418,8 @@ void CreateExtension(CreateExtensionStmt* stmt)
|
|||
|
||||
u_sess->exec_cxt.extension_is_valid = true;
|
||||
|
||||
if (pg_strcasecmp(stmt->extname, "b_sql_plugin") == 0) {
|
||||
u_sess->attr.attr_sql.b_sql_plugin = true;
|
||||
if (pg_strcasecmp(stmt->extname, "dolphin") == 0) {
|
||||
u_sess->attr.attr_sql.dolphin = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -23175,7 +23175,7 @@ static void checkValidationForExchangeTable(Relation partTableRel, Relation ordT
|
|||
int2 bucketId = InvalidBktId;
|
||||
|
||||
// get right partition oid for the tuple
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (HeapTuple) tuple);
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (HeapTuple)tuple, true);
|
||||
|
||||
searchFakeReationForPartitionOid(
|
||||
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
|
||||
|
|
@ -24797,7 +24797,8 @@ static Oid AddTemporaryPartitionForAlterPartitions(const AlterTableCmd* cmd, Rel
|
|||
destPartOid = AddTemporaryHashPartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
|
||||
break;
|
||||
}
|
||||
case PART_TYPE_RANGE: {
|
||||
case PART_TYPE_RANGE:
|
||||
case PART_TYPE_INTERVAL: {
|
||||
destPartOid = AddTemporaryRangePartitionForAlterPartitions(cmd, partTableRel, partSeq, renameTargetPart);
|
||||
break;
|
||||
}
|
||||
|
|
@ -25098,11 +25099,11 @@ static void readTuplesAndInsertInternal(Relation tempTableRel, Relation partTabl
|
|||
|
||||
/* tableam_tops_copy_tuple is not ready so we add UStore hack path */
|
||||
copyTuple = tableam_tops_copy_tuple(tuple);
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple);
|
||||
targetPartOid = heapTupleGetPartitionId(partTableRel, (void *)tuple, true);
|
||||
searchFakeReationForPartitionOid(
|
||||
partRelHTAB, CurrentMemoryContext, partTableRel, targetPartOid, partRel, part, RowExclusiveLock);
|
||||
if (RelationIsSubPartitioned(partTableRel)) {
|
||||
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple);
|
||||
targetPartOid = heapTupleGetPartitionId(partRel, (void *)tuple, true);
|
||||
searchFakeReationForPartitionOid(partRelHTAB, CurrentMemoryContext, partRel, targetPartOid, subPartRel,
|
||||
subPart, RowExclusiveLock);
|
||||
partRel = subPartRel;
|
||||
|
|
|
|||
|
|
@ -5911,6 +5911,7 @@ Datum calculate_encrypted_combined_password(const char* password, const char* ro
|
|||
errno_t rc = EOK;
|
||||
|
||||
/* For PG ecological compatibility, we stored both sha256 and md5 password. */
|
||||
/* the encrypted method of sha256 */
|
||||
if (!pg_sha256_encrypt(password,
|
||||
salt_string,
|
||||
strlen(salt_string),
|
||||
|
|
@ -5921,7 +5922,7 @@ Datum calculate_encrypted_combined_password(const char* password, const char* ro
|
|||
securec_check(rc, "\0", "\0");
|
||||
ereport(ERROR, (errcode(ERRCODE_INVALID_PASSWORD), errmsg("first stage encryption password failed")));
|
||||
}
|
||||
|
||||
/* the encrypted method of md5 */
|
||||
if (!pg_md5_encrypt(password, rolname, strlen(rolname), encrypted_md5_password)) {
|
||||
rc = memset_s(encrypted_md5_password, MD5_PASSWD_LEN + 1, 0, MD5_PASSWD_LEN + 1);
|
||||
securec_check(rc, "\0", "\0");
|
||||
|
|
@ -6052,6 +6053,7 @@ static Datum gs_calculate_encrypted_sm3_password(const char* password, const cha
|
|||
Datum calculate_encrypted_password(bool is_encrypted, const char* password, const char* rolname,
|
||||
const char* salt_string)
|
||||
{
|
||||
/* If the password is '\0' or not exist */
|
||||
if (password == NULL || password[0] == '\0') {
|
||||
ereport(ERROR, (errcode(ERRCODE_INVALID_PASSWORD), errmsg("The password could not be NULL.")));
|
||||
}
|
||||
|
|
@ -6059,6 +6061,7 @@ Datum calculate_encrypted_password(bool is_encrypted, const char* password, cons
|
|||
char encrypted_md5_password[MD5_PASSWD_LEN + 1] = {0};
|
||||
Datum datum_value;
|
||||
|
||||
/* If the password has encrypted */
|
||||
if (!is_encrypted || isPWDENCRYPTED(password)) {
|
||||
return CStringGetTextDatum(password);
|
||||
}
|
||||
|
|
@ -6068,6 +6071,7 @@ Datum calculate_encrypted_password(bool is_encrypted, const char* password, cons
|
|||
* if Password_encryption_type is 0, the encrypted password is md5.
|
||||
* if Password_encryption_type is 1, the encrypted password is sha256 + md5.
|
||||
* if Password_encryption_type is 2, the encrypted password is sha256.
|
||||
* if Password_encryption_type is 3, the encrypted password is SM3.
|
||||
*/
|
||||
if (u_sess->attr.attr_security.Password_encryption_type == 0) {
|
||||
if (!pg_md5_encrypt(password, rolname, strlen(rolname), encrypted_md5_password)) {
|
||||
|
|
|
|||
|
|
@ -1181,6 +1181,17 @@ static Node* pull_up_simple_subquery(PlannerInfo* root, Node* jtnode, RangeTblEn
|
|||
return jtnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* We must flatten any join alias Vars in the subquery's targetlist,
|
||||
* because pulling up the subquery's subqueries might have changed their
|
||||
* expansions into arbitrary expressions, which could affect
|
||||
* pullup_replace_vars' decisions about whether PlaceHolderVar wrappers
|
||||
* are needed for tlist entries. (Likely it'd be better to do
|
||||
* flatten_join_alias_vars on the whole query tree at some earlier stage,
|
||||
* maybe even in the rewriter; but for now let's just fix this case here.)
|
||||
*/
|
||||
subquery->targetList = (List *) flatten_join_alias_vars(subroot, (Node *) subquery->targetList);
|
||||
|
||||
/*
|
||||
* Adjust level-0 varnos in subquery so that we can append its rangetable
|
||||
* to upper query's. We have to fix the subquery's append_rel_list as
|
||||
|
|
|
|||
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* openGauss is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* datasource.cpp
|
||||
* support for data source
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/gausskernel/process/datasource/datasource.cpp
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
*//*
|
||||
* data_source.c
|
||||
* Support functions for operations on data sources.
|
||||
*
|
||||
* This module is responsible for interfacing with the pg_extension_data_source
|
||||
* system catalog table, and providing a low-level API for working with these
|
||||
* objects. It is also responsible for interpreting some of the common fields
|
||||
* that are used throughout the system.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
#include "access/htup_details.h"
|
||||
#include "access/reloptions.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_extension_data_source.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
/*
|
||||
* get_data_source_oid - 通过数据源名称获取对应的oid
|
||||
*
|
||||
* @param sourcename: 数据源名称
|
||||
* @param missing_ok: 是否允许缺失,true表示允许,false表示不允许
|
||||
* @return 返回对应的oid,如果数据源不存在且不允许缺失,则抛出错误
|
||||
*/
|
||||
Oid get_data_source_oid(const char* sourcename, bool missing_ok)
|
||||
{
|
||||
Oid oid;
|
||||
|
||||
oid = GetSysCacheOid1(DATASOURCENAME, CStringGetDatum(sourcename));
|
||||
|
||||
if (!OidIsValid(oid) && !missing_ok)
|
||||
ereport(ERROR,
|
||||
(errmodule(MOD_EC), errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("source \"%s\" does not exist", sourcename)));
|
||||
return oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetDataSource - 查找数据源定义
|
||||
*
|
||||
* @param sourceid: 数据源oid
|
||||
* @return 返回数据源
|
||||
*/
|
||||
DataSource* GetDataSource(Oid sourceid)
|
||||
{
|
||||
Form_pg_extension_data_source sourceform = NULL;
|
||||
DataSource* source = NULL;
|
||||
HeapTuple tp = NULL;
|
||||
Datum datum;
|
||||
bool isnull = false;
|
||||
|
||||
tp = SearchSysCache1(DATASOURCEOID, ObjectIdGetDatum(sourceid));
|
||||
|
||||
if (!HeapTupleIsValid(tp))
|
||||
ereport(ERROR,
|
||||
(errmodule(MOD_EC),
|
||||
errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("cache lookup failed for data source %u", sourceid)));
|
||||
|
||||
sourceform = (Form_pg_extension_data_source)GETSTRUCT(tp);
|
||||
|
||||
source = (DataSource*)palloc0(sizeof(DataSource));
|
||||
source->sourceid = sourceid;
|
||||
source->srcname = pstrdup(NameStr(sourceform->srcname));
|
||||
source->owner = sourceform->srcowner;
|
||||
|
||||
/* Extract source type */
|
||||
datum = SysCacheGetAttr(DATASOURCEOID, tp, Anum_pg_extension_data_source_srctype, &isnull);
|
||||
source->srctype = isnull ? NULL : pstrdup(TextDatumGetCString(datum));
|
||||
|
||||
/* Extract source version */
|
||||
datum = SysCacheGetAttr(DATASOURCEOID, tp, Anum_pg_extension_data_source_srcversion, &isnull);
|
||||
source->srcversion = isnull ? NULL : pstrdup(TextDatumGetCString(datum));
|
||||
|
||||
/* Extract the srcoptions */
|
||||
datum = SysCacheGetAttr(DATASOURCEOID, tp, Anum_pg_extension_data_source_srcoptions, &isnull);
|
||||
if (isnull)
|
||||
source->options = NIL;
|
||||
else
|
||||
source->options = untransformRelOptions(datum);
|
||||
|
||||
ReleaseSysCache(tp);
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetDataSourceByName - 通过名称查找数据源定义
|
||||
*
|
||||
* @param sourcename: 数据源名称
|
||||
* @param missing_ok: 是否允许缺失,true表示允许,false表示不允许
|
||||
* @return 返回数据源,如果数据源不存在且允许缺失,则返回NULL
|
||||
*/
|
||||
DataSource* GetDataSourceByName(const char* sourcename, bool missing_ok)
|
||||
{
|
||||
Oid sourceid;
|
||||
|
||||
if (sourcename == NULL)
|
||||
return NULL;
|
||||
|
||||
sourceid = get_data_source_oid(sourcename, missing_ok);
|
||||
|
||||
if (!OidIsValid(sourceid))
|
||||
return NULL;
|
||||
|
||||
return GetDataSource(sourceid);
|
||||
}
|
||||
|
||||
|
|
@ -20,29 +20,35 @@
|
|||
* src/gausskernel/process/datasource/datasource.cpp
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
*//*
|
||||
* data_source.c
|
||||
* Support functions for operations on data sources.
|
||||
*
|
||||
* This module is responsible for interfacing with the pg_extension_data_source
|
||||
* system catalog table, and providing a low-level API for working with these
|
||||
* objects. It is also responsible for interpreting some of the common fields
|
||||
* that are used throughout the system.
|
||||
*
|
||||
*/
|
||||
#include "postgres.h"
|
||||
#include "knl/knl_variable.h"
|
||||
|
||||
#include "postgres.h"
|
||||
#include "access/htup_details.h"
|
||||
#include "access/reloptions.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/dependency.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_extension_data_source.h"
|
||||
#include "datasource/datasource.h"
|
||||
#include "lib/stringinfo.h"
|
||||
#include "miscadmin.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/rel_gs.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
/*
|
||||
* get_data_source_oid
|
||||
* look up the OID by source name
|
||||
* get_data_source_oid - 通过数据源名称获取对应的oid
|
||||
*
|
||||
* @IN sourcename: source name
|
||||
* @IN missing_ok: If missing_ok is false, throw an error if name not found.
|
||||
* If true, just return InvalidOid.
|
||||
* @RETURN: oid of the data source.
|
||||
* @param sourcename: 数据源名称
|
||||
* @param missing_ok: 是否允许缺失,true表示允许,false表示不允许
|
||||
* @return 返回对应的oid,如果数据源不存在且不允许缺失,则抛出错误
|
||||
*/
|
||||
Oid get_data_source_oid(const char* sourcename, bool missing_ok)
|
||||
{
|
||||
|
|
@ -56,12 +62,11 @@ Oid get_data_source_oid(const char* sourcename, bool missing_ok)
|
|||
return oid;
|
||||
}
|
||||
|
||||
/*
|
||||
* GetDataSource
|
||||
* look up the data source definition
|
||||
/**
|
||||
* GetDataSource - 查找数据源定义
|
||||
*
|
||||
* @IN sourceid: data source oid
|
||||
* @RETURN: a data source
|
||||
* @param sourceid: 数据源oid
|
||||
* @return 返回数据源
|
||||
*/
|
||||
DataSource* GetDataSource(Oid sourceid)
|
||||
{
|
||||
|
|
@ -106,13 +111,12 @@ DataSource* GetDataSource(Oid sourceid)
|
|||
return source;
|
||||
}
|
||||
|
||||
/*
|
||||
* GetDataSourceByName
|
||||
* look up the data source definition by name.
|
||||
/**
|
||||
* GetDataSourceByName - 通过名称查找数据源定义
|
||||
*
|
||||
* @IN sourcename: source name
|
||||
* @IN missing_ok: missing source name ok
|
||||
* @RETURN: data source
|
||||
* @param sourcename: 数据源名称
|
||||
* @param missing_ok: 是否允许缺失,true表示允许,false表示不允许
|
||||
* @return 返回数据源,如果数据源不存在且允许缺失,则返回NULL
|
||||
*/
|
||||
DataSource* GetDataSourceByName(const char* sourcename, bool missing_ok)
|
||||
{
|
||||
|
|
@ -128,3 +132,4 @@ DataSource* GetDataSourceByName(const char* sourcename, bool missing_ok)
|
|||
|
||||
return GetDataSource(sourceid);
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
bool GlobalPlanCache::MsgCheck(const SharedInvalidationMessage *msg)
|
||||
{
|
||||
// 检查共享缓存清理消息的合法性
|
||||
if (msg->id >= 0) {
|
||||
if (msg->cc.id == PROCOID || msg->cc.id == NAMESPACEOID || msg->cc.id == OPEROID || msg->cc.id == AMOPOPID) {
|
||||
return true;
|
||||
|
|
@ -53,6 +54,7 @@ bool GlobalPlanCache::MsgCheck(const SharedInvalidationMessage *msg)
|
|||
|
||||
bool GlobalPlanCache::NeedDropEntryByLocalMsg(CachedPlanSource* plansource, int tot, const int *idx, const SharedInvalidationMessage *msgs)
|
||||
{
|
||||
// 检查本地缓存是否需要被清除
|
||||
Oid database_id = plansource->gpc.key->env.plainenv.database_id;
|
||||
|
||||
for (int j = 0; j < tot; j++) {
|
||||
|
|
@ -92,6 +94,7 @@ bool GlobalPlanCache::NeedDropEntryByLocalMsg(CachedPlanSource* plansource, int
|
|||
|
||||
void GlobalPlanCache::InvalMsg(const SharedInvalidationMessage *msgs, int n)
|
||||
{
|
||||
// 处理共享缓存清理消息
|
||||
int *idx = (int *)palloc0(n * sizeof(int));
|
||||
int tot = 0;
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -68,20 +68,21 @@
|
|||
static bool run_sql_job(Datum job_name, StringInfoData *buf);
|
||||
static bool run_procedure_job(Datum job_name, StringInfoData *buf);
|
||||
static char *run_external_job(Datum job_name);
|
||||
|
||||
/*
|
||||
* @brief delete_by_syscache
|
||||
* Perform a simple heap delete by searching syscache.
|
||||
* @param rel Target relation
|
||||
* @param object_name Delete by key
|
||||
* @param cache_id Cache ID
|
||||
* 通过搜索系统缓存执行简单的堆删除。
|
||||
* @param rel 目标关系
|
||||
* @param object_name 删除的键
|
||||
* @param cache_id 缓存ID
|
||||
*/
|
||||
static void delete_by_syscache(Relation rel, const Datum object_name, SysCacheIdentifier cache_id)
|
||||
{
|
||||
/* 在系统缓存中查找对象 */
|
||||
CatCList *tuples = SearchSysCacheList1(cache_id, object_name);
|
||||
if (tuples == NULL) {
|
||||
return;
|
||||
}
|
||||
/* 循环遍历对象并删除 */
|
||||
for (int i = 0; i < tuples->n_members; i++) {
|
||||
HeapTuple tuple = t_thrd.lsc_cxt.FetchTupleFromCatCList(tuples, i);
|
||||
simple_heap_delete(rel, &tuple->t_self);
|
||||
|
|
@ -91,7 +92,7 @@ static void delete_by_syscache(Relation rel, const Datum object_name, SysCacheId
|
|||
|
||||
/*
|
||||
* @brief delete_from_attribute
|
||||
* Delete from gs_job_attribute.
|
||||
* 从gs_job_attribute表中删除。
|
||||
* @param object_name
|
||||
*/
|
||||
void delete_from_attribute(const Datum object_name)
|
||||
|
|
@ -103,7 +104,7 @@ void delete_from_attribute(const Datum object_name)
|
|||
|
||||
/*
|
||||
* @brief delete_from_argument
|
||||
* Delete from gs_job_argument.
|
||||
* 从gs_job_argument表中删除。
|
||||
* @param job_name
|
||||
*/
|
||||
void delete_from_argument(const Datum object_name)
|
||||
|
|
@ -115,7 +116,7 @@ void delete_from_argument(const Datum object_name)
|
|||
|
||||
/*
|
||||
* @brief delete_from_job
|
||||
* Delete from pg_job.
|
||||
* 从pg_job表中删除。
|
||||
* @param job_name
|
||||
*/
|
||||
void delete_from_job(const Datum job_name)
|
||||
|
|
@ -130,7 +131,7 @@ void delete_from_job(const Datum job_name)
|
|||
|
||||
/*
|
||||
* @brief delete_from_job_proc
|
||||
* Delete from pg_job_proc.
|
||||
* 从pg_job_proc表中删除。
|
||||
* @param job_name
|
||||
*/
|
||||
void delete_from_job_proc(const Datum job_name)
|
||||
|
|
@ -142,34 +143,35 @@ void delete_from_job_proc(const Datum job_name)
|
|||
}
|
||||
heap_close(rel, NoLock);
|
||||
}
|
||||
|
||||
HeapTuple search_from_pg_job(Relation pg_job_rel, Datum job_name)
|
||||
{
|
||||
ScanKeyInfo scan_key_info1;
|
||||
scan_key_info1.attribute_value = job_name;
|
||||
scan_key_info1.attribute_number = Anum_pg_job_job_name;
|
||||
scan_key_info1.procedure = F_TEXTEQ;
|
||||
scan_key_info1.attribute_value = job_name; // 设置扫描键的属性值为job_name
|
||||
scan_key_info1.attribute_number = Anum_pg_job_job_name; // 设置扫描键的属性编号为Anum_pg_job_job_name
|
||||
scan_key_info1.procedure = F_TEXTEQ; // 设置扫描键的比较函数为F_TEXTEQ
|
||||
|
||||
ScanKeyInfo scan_key_info2;
|
||||
scan_key_info2.attribute_value = PointerGetDatum(u_sess->proc_cxt.MyProcPort->database_name);
|
||||
scan_key_info2.attribute_number = Anum_pg_job_dbname;
|
||||
scan_key_info2.procedure = F_NAMEEQ;
|
||||
scan_key_info2.attribute_value = PointerGetDatum(u_sess->proc_cxt.MyProcPort->database_name); // 设置扫描键的属性值为当前数据库名称
|
||||
scan_key_info2.attribute_number = Anum_pg_job_dbname; // 设置扫描键的属性编号为Anum_pg_job_dbname
|
||||
scan_key_info2.procedure = F_NAMEEQ; // 设置扫描键的比较函数为F_NAMEEQ
|
||||
|
||||
List *tuples = search_by_sysscan_2(pg_job_rel, &scan_key_info1, &scan_key_info2);
|
||||
List *tuples = search_by_sysscan_2(pg_job_rel, &scan_key_info1, &scan_key_info2); // 在pg_job_rel上执行扫描操作,并返回符合条件的元组列表
|
||||
if (tuples == NIL) {
|
||||
return NULL;
|
||||
}
|
||||
Assert(list_length(tuples) == 1);
|
||||
Assert(list_length(tuples) == 1); // 断言元组列表长度为1
|
||||
if (list_length(tuples) != 1) {
|
||||
ereport(ERROR, (errmodule(MOD_JOB), errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("find %d tuples match job_name %s in system table pg_job.", list_length(tuples),
|
||||
TextDatumGetCString(job_name)),
|
||||
errdetail("N/A"), errcause("job name is not exist"), erraction("Please check job_name")));
|
||||
}
|
||||
HeapTuple tuple = (HeapTuple)linitial(tuples);
|
||||
list_free_ext(tuples);
|
||||
return tuple;
|
||||
HeapTuple tuple = (HeapTuple)linitial(tuples); // 获取元组列表中的第一个元组
|
||||
list_free_ext(tuples); // 释放元组列表的内存
|
||||
return tuple; // 返回元组
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief update_pg_job
|
||||
* Update pg_job.
|
||||
|
|
@ -277,12 +279,18 @@ List *search_related_attribute(Relation gs_job_attribute_rel, Datum attribute_na
|
|||
|
||||
/*
|
||||
* @brief disable_related_jobs_force
|
||||
*//*
|
||||
* @brief disable_related_jobs_force
|
||||
*
|
||||
* @param gs_job_attribute_rel
|
||||
* @param disable_job_names 要禁用的作业名称列表
|
||||
*/
|
||||
static void disable_related_jobs_force(Relation gs_job_attribute_rel, List *disable_job_names)
|
||||
{
|
||||
ListCell *lc = NULL;
|
||||
foreach (lc, disable_job_names) {
|
||||
Datum job_name = PointerGetDatum(lfirst(lc));
|
||||
// 禁用指定名称的作业
|
||||
update_pg_job(job_name, Anum_pg_job_enable, BoolGetDatum(false));
|
||||
}
|
||||
}
|
||||
|
|
@ -291,8 +299,9 @@ static void disable_related_jobs_force(Relation gs_job_attribute_rel, List *disa
|
|||
* @brief reset_job_class
|
||||
*
|
||||
* @param gs_job_attribute_rel
|
||||
* @param disable_job_names
|
||||
* @param attribute_name
|
||||
* @param disable_job_names 在设置默认 job_class 前需要先禁用这些作业
|
||||
* @param attribute_name 要重置为默认 job_class 的属性名称
|
||||
* @param force 是否强制执行重置操作
|
||||
*/
|
||||
static void reset_job_class(Relation gs_job_attribute_rel, List *disable_job_names, Datum attribute_name, bool force)
|
||||
{
|
||||
|
|
@ -306,10 +315,12 @@ static void reset_job_class(Relation gs_job_attribute_rel, List *disable_job_nam
|
|||
ListCell *lc = NULL;
|
||||
foreach (lc, disable_job_names) {
|
||||
Datum job_name = PointerGetDatum(lfirst(lc));
|
||||
// 将指定作业的 attribute_name 属性重置为默认 job_class
|
||||
update_attribute(job_name, attribute_name, CStringGetTextDatum("DEFAULT_JOB_CLASS"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief search_related_jobs
|
||||
* search all related jobs.
|
||||
|
|
@ -318,6 +329,7 @@ static void reset_job_class(Relation gs_job_attribute_rel, List *disable_job_nam
|
|||
* @param force
|
||||
* @return List*
|
||||
*/
|
||||
//search_related_jobs 函数:用于查找所有与给定对象和属性名相关的任务,并返回任务名称列表。
|
||||
static List *search_related_jobs(Relation gs_job_attribute_rel, Datum object_name, Datum attribute_name, bool force)
|
||||
{
|
||||
List *tuples = search_related_attribute(gs_job_attribute_rel, attribute_name, object_name);
|
||||
|
|
@ -352,6 +364,7 @@ static List *search_related_jobs(Relation gs_job_attribute_rel, Datum object_nam
|
|||
* Drop inline program if exists.
|
||||
* @param job_name
|
||||
*/
|
||||
//drop_inline_program 函数:删除指定任务的内联程序(如果存在)及其相关信息。
|
||||
void drop_inline_program(const Datum job_name)
|
||||
{
|
||||
Datum attribute_name = CStringGetTextDatum("program_name");
|
||||
|
|
@ -380,6 +393,7 @@ void drop_inline_program(const Datum job_name)
|
|||
* @param force
|
||||
* @param simple when set to true, do not disable relatied objects
|
||||
*/
|
||||
//drop_single_object_name 函数:删除指定的对象,并禁用所有相关对象。
|
||||
static void drop_single_object_name(Datum object_name, const char *object_type, bool force)
|
||||
{
|
||||
check_object_type_matched(object_name, object_type);
|
||||
|
|
@ -417,6 +431,7 @@ static void drop_single_object_name(Datum object_name, const char *object_type,
|
|||
* Note:
|
||||
* Dropping a job class requires the MANAGE SCHEDULER system privilege.
|
||||
*/
|
||||
//此函数用于删除单个作业类。
|
||||
void drop_single_job_class_internal(PG_FUNCTION_ARGS)
|
||||
{
|
||||
check_object_is_visible(PG_GETARG_DATUM(0), false);
|
||||
|
|
@ -433,6 +448,7 @@ void drop_single_job_class_internal(PG_FUNCTION_ARGS)
|
|||
* @brief drop_single_program_internal
|
||||
* Drop a single program.
|
||||
*/
|
||||
//此函数用于删除单个程序。
|
||||
void drop_single_program_internal(PG_FUNCTION_ARGS)
|
||||
{
|
||||
check_object_is_visible(PG_GETARG_DATUM(0), false);
|
||||
|
|
@ -459,6 +475,7 @@ void drop_single_program_internal(PG_FUNCTION_ARGS)
|
|||
* @brief drop_single_schedule_internal
|
||||
* Drop a single schedule.
|
||||
*/
|
||||
//此函数用于删除单个调度。
|
||||
void drop_single_schedule_internal(PG_FUNCTION_ARGS)
|
||||
{
|
||||
check_object_is_visible(PG_GETARG_DATUM(0), false);
|
||||
|
|
@ -471,6 +488,7 @@ void drop_single_schedule_internal(PG_FUNCTION_ARGS)
|
|||
* @brief drop_credential_internal
|
||||
* Drop a single credential.
|
||||
*/
|
||||
//此函数用于删除单个凭据。
|
||||
void drop_credential_internal(PG_FUNCTION_ARGS)
|
||||
{
|
||||
if (!superuser()) {
|
||||
|
|
@ -1725,4 +1743,4 @@ void remove_scheduler_objects_from_owner(const char *user_str)
|
|||
}
|
||||
list_free_deep(drop_object_names);
|
||||
list_free_deep(drop_object_types);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -93,6 +93,7 @@ static void FreeJobWorkerInfo(int code, Datum arg);
|
|||
*
|
||||
* Returns: bool
|
||||
*/
|
||||
//此函数用于判断当前线程是否为作业工作进程。如果是作业工作进程,则返回true;否则返回false。
|
||||
bool IsJobWorkerProcess(void)
|
||||
{
|
||||
return t_thrd.role == JOB_WORKER;
|
||||
|
|
@ -103,6 +104,7 @@ bool IsJobWorkerProcess(void)
|
|||
*
|
||||
* Returns: void
|
||||
*/
|
||||
//此函数用于为作业工作进程注册信号处理程序。
|
||||
static void SetupSignalHook(void)
|
||||
{
|
||||
(void)gspqsignal(SIGHUP, SIG_IGN);
|
||||
|
|
@ -122,6 +124,7 @@ static void SetupSignalHook(void)
|
|||
*
|
||||
* Returns: void
|
||||
*/
|
||||
//此函数用于在线程退出时释放作业工作进程的信息。
|
||||
static void FreeJobWorkerInfo(int code, Datum arg)
|
||||
{
|
||||
if (t_thrd.job_cxt.MyWorkerInfo != NULL) {
|
||||
|
|
@ -148,6 +151,20 @@ static void FreeJobWorkerInfo(int code, Datum arg)
|
|||
* @in argv: detail info for each args.
|
||||
* Returns: void
|
||||
*/
|
||||
/*
|
||||
这个函数是一个作业执行器的主函数。它实现了以下功能:
|
||||
|
||||
初始化进程和线程上下文。
|
||||
创建内存上下文并设置处理模式。
|
||||
设置信号处理钩子和信号屏蔽。
|
||||
处理异常和错误,记录日志并清理资源。
|
||||
从共享内存获取作业信息,并将自己添加到运行中的作业工作者列表中。
|
||||
设置会话用户名和数据库名。
|
||||
执行作业初始化操作。
|
||||
报告自己的状态和活动到PgBackendStatus和pg_stat_activity。
|
||||
执行作业具体的逻辑。
|
||||
清理资源并退出进程。
|
||||
*/
|
||||
void JobExecuteWorkerMain()
|
||||
{
|
||||
sigjmp_buf local_sigjmp_buf;
|
||||
|
|
|
|||
|
|
@ -76,228 +76,245 @@ extern int encrypte_main(int argc, char* const argv[]);
|
|||
*/
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char* mmap_env = NULL;
|
||||
syscall_lock_init();
|
||||
char* mmap_env = NULL;
|
||||
syscall_lock_init();
|
||||
|
||||
// 从环境变量中获取GAUSS_MMAP_THRESHOLD的值,并设置mmap_threshold变量
|
||||
mmap_env = gs_getenv_r("GAUSS_MMAP_THRESHOLD");
|
||||
if (mmap_env != NULL) {
|
||||
check_backend_env(mmap_env);
|
||||
mmap_threshold = (size_t)atol(mmap_env);
|
||||
}
|
||||
|
||||
// 初始化KNL实例
|
||||
knl_instance_init();
|
||||
|
||||
// 创建增量检查点上下文
|
||||
g_instance.increCheckPoint_context = AllocSetContextCreate(
|
||||
INSTANCE_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_STORAGE),
|
||||
"IncreCheckPointContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE,
|
||||
SHARED_CONTEXT);
|
||||
|
||||
// 创建备机帐号上下文
|
||||
g_instance.account_context = AllocSetContextCreate(g_instance.instance_context,
|
||||
"StandbyAccontContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE,
|
||||
SHARED_CONTEXT);
|
||||
|
||||
// 创建通信全局内存上下文
|
||||
g_instance.comm_cxt.comm_global_mem_cxt = AllocSetContextCreate(g_instance.instance_context,
|
||||
"CommunnicatorGlobalMemoryContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE,
|
||||
SHARED_CONTEXT);
|
||||
|
||||
// 创建内置过程内存上下文
|
||||
g_instance.builtin_proc_context = AllocSetContextCreate(g_instance.instance_context,
|
||||
"builtin_procGlobalMemoryContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE,
|
||||
SHARED_CONTEXT);
|
||||
|
||||
/*
|
||||
* Fire up essential subsystems: error and memory management
|
||||
*
|
||||
* Code after this point is allowed to use elog/ereport, though
|
||||
* localization of messages may not work right away, and messages won't go
|
||||
* anywhere but stderr until GUC settings get loaded.
|
||||
*/
|
||||
// 初始化内存上下文
|
||||
MemoryContextInit();
|
||||
|
||||
// 设置全局变量PmTopMemoryContext为顶层内存上下文
|
||||
PmTopMemoryContext = t_thrd.top_mem_cxt;
|
||||
|
||||
// 初始化线程
|
||||
knl_thread_init(MASTER_THREAD);
|
||||
|
||||
// 创建虚拟会话
|
||||
t_thrd.fake_session = create_session_context(t_thrd.top_mem_cxt, 0);
|
||||
t_thrd.fake_session->status = KNL_SESS_FAKE;
|
||||
|
||||
// 将当前会话设置为虚拟会话
|
||||
u_sess = t_thrd.fake_session;
|
||||
|
||||
// 设置SelfMemoryContext为默认内存上下文组
|
||||
SelfMemoryContext = THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT);
|
||||
|
||||
// 切换到默认内存上下文组
|
||||
MemoryContextSwitchTo(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));
|
||||
|
||||
// 获取程序名称
|
||||
progname = get_progname(argv[0]);
|
||||
|
||||
mmap_env = gs_getenv_r("GAUSS_MMAP_THRESHOLD");
|
||||
if (mmap_env != NULL) {
|
||||
check_backend_env(mmap_env);
|
||||
mmap_threshold = (size_t)atol(mmap_env);
|
||||
}
|
||||
|
||||
knl_instance_init();
|
||||
|
||||
g_instance.increCheckPoint_context = AllocSetContextCreate(
|
||||
INSTANCE_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_STORAGE),
|
||||
"IncreCheckPointContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE,
|
||||
SHARED_CONTEXT);
|
||||
|
||||
g_instance.account_context = AllocSetContextCreate(g_instance.instance_context,
|
||||
"StandbyAccontContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE,
|
||||
SHARED_CONTEXT);
|
||||
|
||||
g_instance.comm_cxt.comm_global_mem_cxt = AllocSetContextCreate(g_instance.instance_context,
|
||||
"CommunnicatorGlobalMemoryContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE,
|
||||
SHARED_CONTEXT);
|
||||
|
||||
g_instance.builtin_proc_context = AllocSetContextCreate(g_instance.instance_context,
|
||||
"builtin_procGlobalMemoryContext",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE,
|
||||
SHARED_CONTEXT);
|
||||
/*
|
||||
* Fire up essential subsystems: error and memory management
|
||||
*
|
||||
* Code after this point is allowed to use elog/ereport, though
|
||||
* localization of messages may not work right away, and messages won't go
|
||||
* anywhere but stderr until GUC settings get loaded.
|
||||
*/
|
||||
MemoryContextInit();
|
||||
|
||||
PmTopMemoryContext = t_thrd.top_mem_cxt;
|
||||
|
||||
knl_thread_init(MASTER_THREAD);
|
||||
|
||||
t_thrd.fake_session = create_session_context(t_thrd.top_mem_cxt, 0);
|
||||
t_thrd.fake_session->status = KNL_SESS_FAKE;
|
||||
|
||||
u_sess = t_thrd.fake_session;
|
||||
|
||||
SelfMemoryContext = THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT);
|
||||
|
||||
MemoryContextSwitchTo(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));
|
||||
|
||||
progname = get_progname(argv[0]);
|
||||
|
||||
/*
|
||||
* Platform-specific startup hacks
|
||||
*/
|
||||
startup_hacks(progname);
|
||||
* Platform-specific startup hacks
|
||||
*/
|
||||
startup_hacks(progname);
|
||||
|
||||
/* if gaussdb's name is gs_encrypt, so run in encrypte_main() */
|
||||
if (!strcmp(progname, "gs_encrypt")) {
|
||||
return encrypte_main(argc, argv);
|
||||
}
|
||||
|
||||
// 初始化plog全局内存
|
||||
init_plog_global_mem();
|
||||
|
||||
/*
|
||||
* Remember the physical location of the initially given argv[] array for
|
||||
* possible use by ps display. On some platforms, the argv[] storage must
|
||||
* be overwritten in order to set the process title for ps. In such cases,
|
||||
* save_ps_display_args makes and returns a new copy of the argv[] array.
|
||||
*
|
||||
* save_ps_display_args may also move the environment strings to make
|
||||
* extra room. Therefore this should be done as early as possible during
|
||||
* startup, to avoid entanglements with code that might save a getenv()
|
||||
* result pointer.
|
||||
*/
|
||||
argv = save_ps_display_args(argc, argv);
|
||||
|
||||
/*
|
||||
* If supported on the current platform, set up a handler to be called if
|
||||
* the backend/postmaster crashes with a fatal signal or exception.
|
||||
*/
|
||||
#if defined(WIN32) && defined(HAVE_MINIDUMP_TYPE)
|
||||
pgwin32_install_crashdump_handler();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set up locale information from environment. Note that LC_CTYPE and
|
||||
* LC_COLLATE will be overridden later from pg_control if we are in an
|
||||
* already-initialized database. We set them here so that they will be
|
||||
* available to fill pg_control during initdb. LC_MESSAGES will get set
|
||||
* later during GUC option processing, but we set it here to allow startup
|
||||
* error messages to be localized.
|
||||
*/
|
||||
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("gaussdb"));
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/*
|
||||
* Windows uses codepages rather than the environment, so we work around
|
||||
* that by querying the environment explicitly first for LC_COLLATE and
|
||||
* LC_CTYPE. We have to do this because initdb passes those values in the
|
||||
* environment. If there is nothing there we fall back on the codepage.
|
||||
*/
|
||||
{
|
||||
char* env_locale = NULL;
|
||||
|
||||
if ((env_locale = gs_getenv_r("LC_COLLATE")) != NULL) {
|
||||
check_backend_env(env_locale);
|
||||
pg_perm_setlocale(LC_COLLATE, env_locale);
|
||||
} else
|
||||
pg_perm_setlocale(LC_COLLATE, "");
|
||||
|
||||
if ((env_locale = gs_getenv_r("LC_CTYPE")) != NULL) {
|
||||
check_backend_env(env_locale);
|
||||
pg_perm_setlocale(LC_CTYPE, env_locale);
|
||||
} else
|
||||
pg_perm_setlocale(LC_CTYPE, "");
|
||||
}
|
||||
#else
|
||||
pg_perm_setlocale(LC_COLLATE, "");
|
||||
pg_perm_setlocale(LC_CTYPE, "");
|
||||
#endif
|
||||
|
||||
/* if gaussdb's name is gs_encrypt, so run in encrypte_main() */
|
||||
if (!strcmp(progname, "gs_encrypt")) {
|
||||
return encrypte_main(argc, argv);
|
||||
}
|
||||
|
||||
init_plog_global_mem();
|
||||
|
||||
/*
|
||||
* Remember the physical location of the initially given argv[] array for
|
||||
* possible use by ps display. On some platforms, the argv[] storage must
|
||||
* be overwritten in order to set the process title for ps. In such cases
|
||||
* save_ps_display_args makes and returns a new copy of the argv[] array.
|
||||
*
|
||||
* save_ps_display_args may also move the environment strings to make
|
||||
* extra room. Therefore this should be done as early as possible during
|
||||
* startup, to avoid entanglements with code that might save a getenv()
|
||||
* result pointer.
|
||||
*/
|
||||
argv = save_ps_display_args(argc, argv);
|
||||
|
||||
/*
|
||||
* If supported on the current platform, set up a handler to be called if
|
||||
* the backend/postmaster crashes with a fatal signal or exception.
|
||||
*/
|
||||
#if defined(WIN32) && defined(HAVE_MINIDUMP_TYPE)
|
||||
pgwin32_install_crashdump_handler();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set up locale information from environment. Note that LC_CTYPE and
|
||||
* LC_COLLATE will be overridden later from pg_control if we are in an
|
||||
* already-initialized database. We set them here so that they will be
|
||||
* available to fill pg_control during initdb. LC_MESSAGES will get set
|
||||
* later during GUC option processing, but we set it here to allow startup
|
||||
* error messages to be localized.
|
||||
*/
|
||||
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("gaussdb"));
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/*
|
||||
* Windows uses codepages rather than the environment, so we work around
|
||||
* that by querying the environment explicitly first for LC_COLLATE and
|
||||
* LC_CTYPE. We have to do this because initdb passes those values in the
|
||||
* environment. If there is nothing there we fall back on the codepage.
|
||||
*/
|
||||
{
|
||||
char* env_locale = NULL;
|
||||
|
||||
if ((env_locale = gs_getenv_r("LC_COLLATE")) != NULL) {
|
||||
check_backend_env(env_locale);
|
||||
pg_perm_setlocale(LC_COLLATE, env_locale);
|
||||
} else
|
||||
pg_perm_setlocale(LC_COLLATE, "");
|
||||
|
||||
if ((env_locale = gs_getenv_r("LC_CTYPE")) != NULL) {
|
||||
check_backend_env(env_locale);
|
||||
pg_perm_setlocale(LC_CTYPE, env_locale);
|
||||
} else
|
||||
pg_perm_setlocale(LC_CTYPE, "");
|
||||
}
|
||||
#else
|
||||
pg_perm_setlocale(LC_COLLATE, "");
|
||||
pg_perm_setlocale(LC_CTYPE, "");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We keep these set to "C" always, except transiently in pg_locale.c; see
|
||||
* that file for explanations.
|
||||
*/
|
||||
pg_perm_setlocale(LC_MONETARY, "C");
|
||||
pg_perm_setlocale(LC_NUMERIC, "C");
|
||||
pg_perm_setlocale(LC_TIME, "C");
|
||||
|
||||
/*
|
||||
* Now that we have absorbed as much as we wish to from the locale
|
||||
* environment, remove any LC_ALL setting, so that the environment
|
||||
* variables installed by pg_perm_setlocale have force.
|
||||
*/
|
||||
(void)unsetenv("LC_ALL");
|
||||
|
||||
/*
|
||||
* Catch standard options before doing much else
|
||||
*/
|
||||
if (argc > 1) {
|
||||
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) {
|
||||
help(progname);
|
||||
exit(0);
|
||||
}
|
||||
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) {
|
||||
puts("gaussdb " DEF_GS_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we are not running as root.
|
||||
*/
|
||||
check_root(progname);
|
||||
|
||||
/*
|
||||
* Dispatch to one of various subprograms depending on first argument.
|
||||
*/
|
||||
#ifdef WIN32
|
||||
|
||||
/*
|
||||
* Start our win32 signal implementation
|
||||
*
|
||||
* SubPostmasterMain() will do this for itself, but the remaining modes
|
||||
* need it here
|
||||
*/
|
||||
pgwin32_signal_initialize();
|
||||
#endif
|
||||
|
||||
t_thrd.mem_cxt.gs_signal_mem_cxt = AllocSetContextCreate(
|
||||
t_thrd.top_mem_cxt, "gs_signal", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE);
|
||||
if (NULL == t_thrd.mem_cxt.gs_signal_mem_cxt) {
|
||||
ereport(LOG, (errmsg("could not start a new thread, because of no enough system resource. ")));
|
||||
proc_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* @BuiltinFunc
|
||||
* Create a global BuiltinFunc object shared among threads
|
||||
*/
|
||||
if (g_sorted_funcs[0] == NULL) {
|
||||
initBuiltinFuncs();
|
||||
}
|
||||
|
||||
bool isBoot = (argc > 1 && strcmp(argv[1], "--boot") == 0);
|
||||
if (isBoot) {
|
||||
IsInitdb = true;
|
||||
gs_signal_monitor_startup();
|
||||
gs_signal_slots_init(1);
|
||||
(void)gs_signal_unblock_sigusr2();
|
||||
gs_signal_startup_siginfo("AuxiliaryProcessMain");
|
||||
BootStrapProcessMain(argc, argv); /* does not return */
|
||||
}
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "--describe-config") == 0)
|
||||
exit(GucInfoMain());
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "--single") == 0) {
|
||||
IsInitdb = true;
|
||||
gs_signal_monitor_startup();
|
||||
gs_signal_slots_init(1);
|
||||
(void)gs_signal_unblock_sigusr2();
|
||||
gs_signal_startup_siginfo("PostgresMain");
|
||||
|
||||
exit(PostgresMain(argc, argv, NULL, get_current_username(progname)));
|
||||
}
|
||||
|
||||
exit(PostmasterMain(argc, argv));
|
||||
}
|
||||
/*
|
||||
* We keep these set to "C" always, except transiently in pg_locale.c; see
|
||||
* that file for explanations.
|
||||
*/
|
||||
pg_perm_setlocale(LC_MONETARY, "C"); // 将货币格式化设置为"C"语言环境
|
||||
pg_perm_setlocale(LC_NUMERIC, "C"); // 将数字格式化设置为"C"语言环境
|
||||
pg_perm_setlocale(LC_TIME, "C"); // 将时间格式化设置为"C"语言环境
|
||||
|
||||
/*
|
||||
* Now that we have absorbed as much as we wish to from the locale
|
||||
* environment, remove any LC_ALL setting, so that the environment
|
||||
* variables installed by pg_perm_setlocale have force.
|
||||
*/
|
||||
(void)unsetenv("LC_ALL"); // 移除LC_ALL设置,以确保pg_perm_setlocale设置的环境变量生效
|
||||
|
||||
/*
|
||||
* Catch standard options before doing much else
|
||||
*/
|
||||
if (argc > 1) {
|
||||
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) {
|
||||
help(progname); // 显示帮助信息
|
||||
exit(0);
|
||||
}
|
||||
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) {
|
||||
puts("gaussdb " DEF_GS_VERSION); // 显示版本号
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we are not running as root.
|
||||
*/
|
||||
check_root(progname); // 检查是否以root用户身份运行
|
||||
|
||||
/*
|
||||
* Dispatch to one of various subprograms depending on first argument.
|
||||
*/
|
||||
#ifdef WIN32
|
||||
|
||||
/*
|
||||
* Start our win32 signal implementation
|
||||
*
|
||||
* SubPostmasterMain() will do this for itself, but the remaining modes
|
||||
* need it here
|
||||
*/
|
||||
pgwin32_signal_initialize(); // 在Windows平台上启动信号处理
|
||||
|
||||
#endif
|
||||
|
||||
t_thrd.mem_cxt.gs_signal_mem_cxt = AllocSetContextCreate(
|
||||
t_thrd.top_mem_cxt, "gs_signal", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE);
|
||||
if (NULL == t_thrd.mem_cxt.gs_signal_mem_cxt) {
|
||||
ereport(LOG, (errmsg("could not start a new thread, because of no enough system resource. ")));
|
||||
proc_exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* @BuiltinFunc
|
||||
* Create a global BuiltinFunc object shared among threads
|
||||
*/
|
||||
if (g_sorted_funcs[0] == NULL) {
|
||||
initBuiltinFuncs(); // 初始化内置函数相关的全局变量
|
||||
}
|
||||
|
||||
bool isBoot = (argc > 1 && strcmp(argv[1], "--boot") == 0);
|
||||
if (isBoot) {
|
||||
IsInitdb = true;
|
||||
gs_signal_monitor_startup(); // 启动信号监控工作线程
|
||||
gs_signal_slots_init(1); // 初始化信号插槽
|
||||
(void)gs_signal_unblock_sigusr2(); // 解除SIGUSR2信号的阻塞
|
||||
gs_signal_startup_siginfo("AuxiliaryProcessMain"); // 记录启动信息
|
||||
BootStrapProcessMain(argc, argv); /* does not return */
|
||||
}
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "--describe-config") == 0)
|
||||
exit(GucInfoMain()); // 打印GUC参数信息
|
||||
|
||||
if (argc > 1 && strcmp(argv[1], "--single") == 0) {
|
||||
IsInitdb = true;
|
||||
gs_signal_monitor_startup(); // 启动信号监控工作线程
|
||||
gs_signal_slots_init(1); // 初始化信号插槽
|
||||
(void)gs_signal_unblock_sigusr2(); // 解除SIGUSR2信号的阻塞
|
||||
gs_signal_startup_siginfo("PostgresMain"); // 记录启动信息
|
||||
|
||||
exit(PostgresMain(argc, argv, NULL, get_current_username(progname))); // 进入PostgreSQL主循环
|
||||
}
|
||||
|
||||
exit(PostmasterMain(argc, argv)); // 进入Postmaster主循环
|
||||
|
||||
/*
|
||||
* Place platform-specific startup hacks here. This is the right
|
||||
|
|
@ -496,43 +513,55 @@ static void check_root(const char* progname)
|
|||
}
|
||||
#endif /* WIN32 */
|
||||
}
|
||||
/**
|
||||
* get_current_username - 获取当前操作系统的用户名
|
||||
* @progname: 程序名称
|
||||
*
|
||||
* 返回当前操作系统的用户名。
|
||||
*/
|
||||
static char* get_current_username(const char* progname)
|
||||
{
|
||||
#ifndef WIN32 // 非Windows平台代码
|
||||
struct passwd* pw = NULL;
|
||||
char* pRet = NULL;
|
||||
|
||||
(void)syscalllockAcquire(&getpwuid_lock); // 获取线程锁
|
||||
pw = getpwuid(geteuid()); // 获取与实际用户ID关联的密码记录
|
||||
if (pw == NULL) { // 如果无法获取则报错
|
||||
(void)syscalllockRelease(&getpwuid_lock);
|
||||
write_stderr("%s: invalid effective UID: %d\n", progname, (int)geteuid());
|
||||
exit(1);
|
||||
}
|
||||
/* Allocate new memory because later getpwuid() calls can overwrite it. */
|
||||
pRet = MemoryContextStrdup(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), pw->pw_name); // 分配新内存来储存用户名,并返回该内存地址
|
||||
(void)syscalllockRelease(&getpwuid_lock); // 释放线程锁
|
||||
return pRet; // 返回用户名
|
||||
#else // Windows平台代码
|
||||
unsigned long namesize = 256 /* UNLEN */ + 1;
|
||||
char* name = NULL;
|
||||
|
||||
name = MemoryContextAlloc(
|
||||
SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), namesize); // 分配内存来储存用户名,返回该内存地址
|
||||
if (!GetUserName(name, &namesize)) { // 获取当前用户的用户名
|
||||
write_stderr("%s: could not determine user name (GetUserName failed)\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return name; // 返回用户名
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* syscall_lock_init - 初始化系统调用锁
|
||||
*
|
||||
* 初始化用于保护某些系统调用(如 getenv)的线程锁。
|
||||
*/
|
||||
static void syscall_lock_init(void)
|
||||
{
|
||||
syscalllockInit(&getpwuid_lock); // 初始化获取用户ID对应密码记录的线程锁
|
||||
syscalllockInit(&env_lock); // 初始化 getenv 的线程锁
|
||||
syscalllockInit(&dlerror_lock); // 初始化 dlerror 的线程锁
|
||||
syscalllockInit(&kerberos_conn_lock); // 初始化 Kerberos 连接相关的线程锁
|
||||
syscalllockInit(&read_cipher_lock); // 初始化加密算法相关的线程锁
|
||||
}
|
||||
|
||||
static char* get_current_username(const char* progname)
|
||||
{
|
||||
#ifndef WIN32
|
||||
struct passwd* pw = NULL;
|
||||
char* pRet = NULL;
|
||||
|
||||
(void)syscalllockAcquire(&getpwuid_lock);
|
||||
pw = getpwuid(geteuid());
|
||||
if (pw == NULL) {
|
||||
(void)syscalllockRelease(&getpwuid_lock);
|
||||
write_stderr("%s: invalid effective UID: %d\n", progname, (int)geteuid());
|
||||
exit(1);
|
||||
}
|
||||
/* Allocate new memory because later getpwuid() calls can overwrite it. */
|
||||
pRet = MemoryContextStrdup(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), pw->pw_name);
|
||||
(void)syscalllockRelease(&getpwuid_lock);
|
||||
return pRet;
|
||||
#else
|
||||
unsigned long namesize = 256 /* UNLEN */ + 1;
|
||||
char* name = NULL;
|
||||
|
||||
name = MemoryContextAlloc(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), namesize);
|
||||
if (!GetUserName(name, &namesize)) {
|
||||
write_stderr("%s: could not determine user name (GetUserName failed)\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return name;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void syscall_lock_init(void)
|
||||
{
|
||||
syscalllockInit(&getpwuid_lock);
|
||||
syscalllockInit(&env_lock);
|
||||
syscalllockInit(&dlerror_lock);
|
||||
syscalllockInit(&kerberos_conn_lock);
|
||||
syscalllockInit(&read_cipher_lock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,4 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
*
|
||||
* openGauss is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
*
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* alarmchecker.cpp
|
||||
*
|
||||
* openGauss Alarm checker thread Implementation
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/gausskernel/process/postmaster/alarmchecker.cpp
|
||||
*
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
//这些是各种头文件的引用,包含了一些系统库、PostgreSQL内部模块和自定义的模块
|
||||
#include "postgres.h"
|
||||
#include "knl/knl_variable.h"
|
||||
|
||||
|
|
@ -46,18 +23,15 @@
|
|||
#include "postmaster/alarmchecker.h"
|
||||
#include "gssignal/gs_signal.h"
|
||||
#include "replication/walsender.h"
|
||||
//定义一些全局变量
|
||||
int g_alarmReportInterval;//报警上报的时间间隔
|
||||
char g_alarmComponentPath[MAXPGPATH];// 报警组件的路径
|
||||
int g_alarmReportMaxCount;//报警上报的最大次数
|
||||
|
||||
// declare the global variable of alarm module
|
||||
int g_alarmReportInterval;
|
||||
char g_alarmComponentPath[MAXPGPATH];
|
||||
int g_alarmReportMaxCount;
|
||||
/* seconds, interval of alarm check loop. */
|
||||
static const int AlarmCheckInterval = 1;
|
||||
|
||||
bool enable_alarm = false;
|
||||
|
||||
static const int AlarmCheckInterval = 1;//定义了一个静态常量 AlarmCheckInterval,值为1,表示报警检查的时间间隔(单位:秒)
|
||||
bool enable_alarm = false;//定义并初始化了一个bool型变量 enable_alarm,初始值为 false,表示是否启用报警功能。
|
||||
//定义了静态变量 DataInstAlarmList 和 DataInstAlarmListSize,用于存储报警项的列表和列表大小
|
||||
static Alarm* DataInstAlarmList = NULL;
|
||||
|
||||
static int DataInstAlarmListSize = 0;
|
||||
|
||||
AlarmCheckResult DataOrRedoDirNotExistChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam);
|
||||
|
|
@ -70,15 +44,17 @@ static void acSigquitHandler(SIGNAL_ARGS);
|
|||
extern AlarmCheckResult DataInstArchChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam);
|
||||
extern AlarmCheckResult ConnAuthMethodChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam);
|
||||
extern AlarmCheckResult DataInstConnToGTMChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam);
|
||||
|
||||
//用于初始化报警项列表
|
||||
void DataInstAlarmItemInitialize(void)
|
||||
{
|
||||
DataInstAlarmListSize = 6;
|
||||
DataInstAlarmList = (Alarm*)AlarmAlloc(sizeof(Alarm) * DataInstAlarmListSize);
|
||||
DataInstAlarmListSize = 6;//设置列表大小为6
|
||||
DataInstAlarmList = (Alarm*)AlarmAlloc(sizeof(Alarm) * DataInstAlarmListSize);//给 DataInstAlarmList分配内存
|
||||
//如果分配失败
|
||||
if (NULL == DataInstAlarmList) {
|
||||
AlarmLog(ALM_LOG, "Out of memory: DataInstAlarmItemInitialize failed.");
|
||||
AlarmLog(ALM_LOG, "Out of memory: DataInstAlarmItemInitialize failed.");//记录错误日志并退出程序
|
||||
exit(1);
|
||||
}
|
||||
//调用函数AlarmItemInitialize对每个报警项进行初始化,每个报警项由一个Alarm结构体表示,包含报警项的类型、报警状态和报警检查函数
|
||||
// ALM_AI_MissingDataInstDataOrRedoDir
|
||||
AlarmItemInitialize(
|
||||
&(DataInstAlarmList[0]), ALM_AI_MissingDataInstDataOrRedoDir, ALM_AS_Normal, DataOrRedoDirNotExistChecker);
|
||||
|
|
@ -96,50 +72,38 @@ void DataInstAlarmItemInitialize(void)
|
|||
AlarmItemInitialize(
|
||||
&(DataInstAlarmList[5]), ALM_AI_AbnormalDataInstConnToGTM, ALM_AS_Normal, DataInstConnToGTMChecker);
|
||||
}
|
||||
|
||||
//用于启动报警检查进程
|
||||
ThreadId startAlarmChecker(void)
|
||||
{
|
||||
if (!IsPostmasterEnvironment || !enable_alarm) {
|
||||
//看是否处于Postmaster环境并且是否启用了报警功能
|
||||
if (!IsPostmasterEnvironment || !enable_alarm) {//如果不满足条件,则返回0。
|
||||
return 0;
|
||||
}
|
||||
|
||||
//否则,调用initialize_util_thread函数来启动报警检查器线程。
|
||||
return initialize_util_thread(ALARMCHECK);
|
||||
}
|
||||
|
||||
//定义了一个名为AlarmCheckerMain的静态函数。
|
||||
//NON_EXEC_STATIC用于指定函数不会被直接执行,而是作为子进程在PostgreSQL中运行。
|
||||
NON_EXEC_STATIC void AlarmCheckerMain()
|
||||
{
|
||||
IsUnderPostmaster = true;//设置变量IsUnderPostmaster为true,表示当前进程是一个后台进程
|
||||
|
||||
/* we are a postmaster subprocess now */
|
||||
IsUnderPostmaster = true;
|
||||
|
||||
/* reset t_thrd.proc_cxt.MyProcPid */
|
||||
t_thrd.proc_cxt.MyProcPid = gs_thread_self();
|
||||
|
||||
/* record Start Time for logging */
|
||||
t_thrd.proc_cxt.MyStartTime = time(NULL);
|
||||
|
||||
/* reord my name */
|
||||
t_thrd.proc_cxt.MyProgName = "AlarmChecker";
|
||||
|
||||
/* Identify myself via ps */
|
||||
init_ps_display("AlarmChecker", "", "", "");
|
||||
|
||||
t_thrd.proc_cxt.MyProcPid = gs_thread_self();//重置t_thrd.proc_cxt.MyProcPid为当前线程
|
||||
|
||||
t_thrd.proc_cxt.MyStartTime = time(NULL);//记录当前时间为t_thrd.proc_cxt.MyStartTime
|
||||
|
||||
t_thrd.proc_cxt.MyProgName = "AlarmChecker";//将当前进程名设置为AlarmChecker
|
||||
|
||||
init_ps_display("AlarmChecker", "", "", "");//调用函数init_ps_display来显示初始化进程状态
|
||||
//调用函数AlarmLog记录日志,表示报警检查程序已经启动
|
||||
AlarmLog(ALM_LOG, "alarm checker started.");
|
||||
|
||||
//调用函数InitializeLatchSupport来初始化latch支持。
|
||||
InitializeLatchSupport(); /* needed for latch waits */
|
||||
|
||||
/* Initialize private latch for use by signal handlers */
|
||||
//初始化一个latch对象,用于处理信号处理程序中的同步等待。
|
||||
InitLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch);
|
||||
|
||||
/*
|
||||
* Properly accept or ignore signals the postmaster might send us
|
||||
*
|
||||
* Note: we deliberately ignore SIGTERM, because during a standard Unix
|
||||
* system shutdown cycle, init will SIGTERM all processes at once. We
|
||||
* want to wait for the backends to exit, whereupon the postmaster will
|
||||
* tell us it's okay to shut down (via SIGUSR2).
|
||||
*/
|
||||
(void)gspqsignal(SIGHUP, acSighupHandler); /* set flag to read config file */
|
||||
//使用gspqsignal函数设置了一些信号的处理行为,如SIGHUP、SIGINT、SIGTERM等。
|
||||
(void)gspqsignal(SIGHUP, acSighupHandler);
|
||||
(void)gspqsignal(SIGINT, SIG_IGN);
|
||||
(void)gspqsignal(SIGTERM, SIG_IGN);
|
||||
(void)gspqsignal(SIGQUIT, acSigquitHandler);
|
||||
|
|
@ -147,160 +111,141 @@ NON_EXEC_STATIC void AlarmCheckerMain()
|
|||
(void)gspqsignal(SIGPIPE, SIG_IGN);
|
||||
(void)gspqsignal(SIGUSR1, SIG_IGN);
|
||||
(void)gspqsignal(SIGUSR2, SIG_IGN);
|
||||
//对于某些信号通过SIG_IGN忽略,而对于其他信号通过SIG_DFL恢复为默认行为。
|
||||
|
||||
/*
|
||||
* Reset some signals that are accepted by postmaster but not here
|
||||
*/
|
||||
(void)gspqsignal(SIGCHLD, SIG_DFL);
|
||||
(void)gspqsignal(SIGTTIN, SIG_DFL);
|
||||
(void)gspqsignal(SIGTTOU, SIG_DFL);
|
||||
(void)gspqsignal(SIGCONT, SIG_DFL);
|
||||
(void)gspqsignal(SIGWINCH, SIG_DFL);
|
||||
|
||||
//设置信号掩码使得非阻塞的信号可用
|
||||
gs_signal_setmask(&t_thrd.libpq_cxt.UnBlockSig, NULL);
|
||||
//解除SIGUSR2信号的阻塞
|
||||
(void)gs_signal_unblock_sigusr2();
|
||||
|
||||
/* all is done info top memory context. */
|
||||
//切换到默认内存上下文中
|
||||
(void)MemoryContextSwitchTo(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));
|
||||
|
||||
|
||||
//调用初始化报警项列表
|
||||
DataInstAlarmItemInitialize();
|
||||
|
||||
for (;;) {
|
||||
/* Clear any already-pending wakeups */
|
||||
//清除任何已经挂起的唤醒信号
|
||||
ResetLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch);
|
||||
|
||||
/* the normal shutdown case */
|
||||
if (t_thrd.alarm_cxt.gotSigdie)
|
||||
if (t_thrd.alarm_cxt.gotSigdie)// 接收到终止信号,跳出循环,结束线程
|
||||
break;
|
||||
|
||||
/*
|
||||
* reload the postgresql.conf
|
||||
*/
|
||||
//检查是否接收到了SIGDIE信号
|
||||
if (t_thrd.alarm_cxt.gotSighup) {
|
||||
t_thrd.alarm_cxt.gotSighup = false;
|
||||
t_thrd.alarm_cxt.gotSighup = false;//接收到,重新加载postgresql.conf配置文件
|
||||
ProcessConfigFile(PGC_SIGHUP);
|
||||
}
|
||||
|
||||
//进行报警检查
|
||||
AlarmCheckerLoop(DataInstAlarmList, DataInstAlarmListSize);
|
||||
|
||||
/*
|
||||
* Sleep until there's something to do
|
||||
*/
|
||||
//进入休眠状态,等待下一次循环
|
||||
(void)WaitLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch, WL_LATCH_SET | WL_TIMEOUT, AlarmCheckInterval * 1000);
|
||||
}
|
||||
|
||||
//调用AlarmLog函数记录日志,表示报警检查程序即将关闭
|
||||
AlarmLog(ALM_LOG, "alarm checker shutting down...");
|
||||
|
||||
//结束进程
|
||||
proc_exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* signal handle functions
|
||||
*/
|
||||
/*
|
||||
* @@GaussDB@@
|
||||
* Brief : handle SIGHUP signal and set t_thrd.alarm_cxt.gotSighup flag
|
||||
* Description :
|
||||
* Notes :
|
||||
*/
|
||||
//定义了一个名为acSighupHandler的静态函数,用于处理SIGHUP信号,SIGNAL_ARGS是用于接收信号处理程序的参数。
|
||||
static void acSighupHandler(SIGNAL_ARGS)
|
||||
{
|
||||
int save_errno = errno;
|
||||
|
||||
t_thrd.alarm_cxt.gotSighup = true;
|
||||
int save_errno = errno;//保存当前错误码
|
||||
|
||||
t_thrd.alarm_cxt.gotSighup = true;//置为true,表示接收到了SIGHUP信号
|
||||
//调用SetLatch函数设置latch对象,以唤醒等待该latch的进程
|
||||
SetLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch);
|
||||
|
||||
//恢复之前保存的错误码
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* @@GaussDB@@
|
||||
* Brief : handle SIGTERM, SIGINT signal and set t_thrd.alarm_cxt.gotSigdie flag
|
||||
* Description :
|
||||
* Notes :
|
||||
*/
|
||||
//定义了一个名为acSigquitHandler的静态函数,用于处理SIGQUIT信号。SIGNAL_ARGS用于接收信号处理程序的参数。
|
||||
static void acSigquitHandler(SIGNAL_ARGS)
|
||||
{
|
||||
int save_errno = errno;
|
||||
|
||||
t_thrd.alarm_cxt.gotSigdie = true;
|
||||
int save_errno = errno;//保存当前错误码
|
||||
|
||||
t_thrd.alarm_cxt.gotSigdie = true;//置为true,表示接收到了SIGQUIT信号
|
||||
//调用SetLatch函数设置latch对象,以唤醒等待该latch的进程
|
||||
SetLatch(&t_thrd.alarm_cxt.AlarmCheckerLatch);
|
||||
|
||||
//恢复之前保存的错误码
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
//定义了一个名为isDirExist的函数,用于判断指定目录是否存在。参数dir表示要检查的目录路径。
|
||||
bool isDirExist(const char* dir)
|
||||
{
|
||||
struct stat stat_buf;
|
||||
|
||||
if (stat(dir, &stat_buf) != 0)
|
||||
struct stat stat_buf;//定义了一个stat结构体用于存储目录的属性信息
|
||||
//使用stat函数获取目录的属性信息
|
||||
if (stat(dir, &stat_buf) != 0)//如果返回值不为0
|
||||
return false;//获取失败,说明目录不存在,返回false
|
||||
//判断获取到的目录的属性中的st_mode字段是否为目录类型
|
||||
if (!S_ISDIR(stat_buf.st_mode))//若不是目录类型,则返回false
|
||||
return false;
|
||||
|
||||
if (!S_ISDIR(stat_buf.st_mode))
|
||||
return false;
|
||||
|
||||
//这是对非Windows和非Cygwin系统上的额外检查:
|
||||
#if !defined(WIN32) && !defined(__CYGWIN__)
|
||||
|
||||
if (stat_buf.st_uid != geteuid())
|
||||
if (stat_buf.st_uid != geteuid())//检查目录的拥有者是否与当前用户ID相同
|
||||
return false;
|
||||
|
||||
if ((stat_buf.st_mode & S_IRWXU) != S_IRWXU)
|
||||
if ((stat_buf.st_mode & S_IRWXU) != S_IRWXU)//检查目录的权限是否设置为用户可读、写、执行的权限
|
||||
return false;
|
||||
|
||||
#endif
|
||||
|
||||
//目录存在且满足所有条件,返回true,否则返回false
|
||||
return true;
|
||||
}
|
||||
|
||||
//定义了一个名为DataOrRedoDirNotExistChecker的函数,用于检查数据目录和pg_xlog目录是否存在。
|
||||
//有两个参数:alarm表示报警对象,additionalParam表示额外的参数。
|
||||
AlarmCheckResult DataOrRedoDirNotExistChecker(Alarm* alarm, AlarmAdditionalParam* additionalParam)
|
||||
{
|
||||
if (isDirExist(t_thrd.proc_cxt.DataDir) && isDirExist("pg_xlog")) {
|
||||
// fill the alarm message
|
||||
WriteAlarmAdditionalInfo(additionalParam,
|
||||
//调用isDirExist函数判断数据目录和pg_xlog目录是否都存在
|
||||
if (isDirExist(t_thrd.proc_cxt.DataDir) && isDirExist("pg_xlog")) {//如果两个目录都存在,则执行以下操作:
|
||||
// fill the alarm message //- 使用WriteAlarmAdditionalInfo函数填充报警消息的额外信息。
|
||||
WriteAlarmAdditionalInfo(additionalParam,
|
||||
g_instance.attr.attr_common.PGXCNodeName,
|
||||
"",
|
||||
"",
|
||||
alarm,
|
||||
ALM_AT_Resume,
|
||||
g_instance.attr.attr_common.PGXCNodeName);
|
||||
return ALM_ACR_Normal;
|
||||
} else {
|
||||
return ALM_ACR_Normal;//- 返回ALM_ACR_Normal,表示检查结果正常。
|
||||
} else { //如果两个目录有任何一个不存在,则执行以下操作
|
||||
// fill the alarm message
|
||||
WriteAlarmAdditionalInfo(additionalParam,
|
||||
WriteAlarmAdditionalInfo(additionalParam, //使用WriteAlarmAdditionalInfo函数填充报警消息的额外信息
|
||||
g_instance.attr.attr_common.PGXCNodeName,
|
||||
"",
|
||||
"",
|
||||
alarm,
|
||||
ALM_AT_Fault,
|
||||
g_instance.attr.attr_common.PGXCNodeName);
|
||||
return ALM_ACR_Abnormal;
|
||||
return ALM_ACR_Abnormal;// 返回ALM_ACR_Abnormal,表示检查结果异常
|
||||
}
|
||||
}
|
||||
|
||||
/* implementation of alarm module. */
|
||||
//定义了一个名为AlarmFree的函数,用于释放内存。pointer表示要释放的内存指针。
|
||||
void AlarmFree(void* pointer)
|
||||
{
|
||||
//检查指针是否为空
|
||||
if (pointer != NULL)
|
||||
pfree(pointer);
|
||||
pfree(pointer);//如果不为空,则调用pfree函数释放内存
|
||||
}
|
||||
|
||||
//定义了一个名为AlarmAlloc的函数,用于分配内存。size表示要分配的内存大小
|
||||
void* AlarmAlloc(size_t size)
|
||||
{
|
||||
return palloc(size);
|
||||
return palloc(size);//调用palloc函数分配内存,并将分配的内存地址返回
|
||||
}
|
||||
|
||||
//定义了一个名为AlarmLogImplementation的函数,用于记录报警日志。
|
||||
//有三个参数:level表示日志级别,prefix表示日志前缀,logtext表示要记录的日志文本。
|
||||
void AlarmLogImplementation(int level, const char* prefix, const char* logtext)
|
||||
{
|
||||
//使用switch语句根据日志级别执行不同的操作。
|
||||
switch (level) {
|
||||
case ALM_DEBUG:
|
||||
ereport(DEBUG3, (errmsg("%s%s", prefix, logtext)));
|
||||
case ALM_DEBUG://如果级别是ALM_DEBUG
|
||||
ereport(DEBUG3, (errmsg("%s%s", prefix, logtext)));//调用ereport函数使用DEBUG3级别记录日志
|
||||
break;
|
||||
case ALM_LOG:
|
||||
ereport(LOG, (errmsg("%s%s", prefix, logtext)));
|
||||
case ALM_LOG://如果级别是ALM_LOG
|
||||
ereport(LOG, (errmsg("%s%s", prefix, logtext)));//调用ereport函数使用LOG级别记录日志。
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;//其他情况不执行任何操作。
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1263,7 +1263,7 @@ static void ckpt_pagewriter_main_thread_loop(void)
|
|||
HandlePageWriterMainInterrupts();
|
||||
|
||||
candidate_num = get_curr_candidate_nums(false) + get_curr_candidate_nums(true);
|
||||
if (candidate_num == 0) {
|
||||
if (candidate_num == 0 && !t_thrd.pagewriter_cxt.shutdown_requested) {
|
||||
/* wakeup sub thread scan the buffer pool, init the candidate list */
|
||||
wakeup_sub_thread();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -825,13 +825,10 @@ void client_read_ended(void)
|
|||
#define INIT_PLUGIN_OBJECT "init_plugin_object"
|
||||
void InitBSqlPluginHookIfNeeded()
|
||||
{
|
||||
const char* b_sql_plugin = "b_sql_plugin";
|
||||
const char* dolphin = "dolphin";
|
||||
CFunInfo tmpCF;
|
||||
if (!CheckIfExtensionExists(b_sql_plugin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
tmpCF = load_external_function(b_sql_plugin, INIT_PLUGIN_OBJECT, false, false);
|
||||
tmpCF = load_external_function(dolphin, INIT_PLUGIN_OBJECT, false, false);
|
||||
if (tmpCF.user_fn != NULL) {
|
||||
((void* (*)(void))(tmpCF.user_fn))();
|
||||
}
|
||||
|
|
@ -865,9 +862,11 @@ List* pg_parse_query(const char* query_string, List** query_string_locationlist)
|
|||
|
||||
List* (*parser_hook)(const char*, List**) = raw_parser;
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
int id = GetCustomParserId();
|
||||
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
||||
parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
|
||||
if (u_sess->attr.attr_sql.dolphin) {
|
||||
int id = GetCustomParserId();
|
||||
if (id >= 0 && g_instance.raw_parser_hook[id] != NULL) {
|
||||
parser_hook = (List* (*)(const char*, List**))g_instance.raw_parser_hook[id];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
raw_parsetree_list = parser_hook(query_string, query_string_locationlist);
|
||||
|
|
@ -6115,6 +6114,9 @@ void ProcessInterrupts(void)
|
|||
|
||||
/* The logical replication launcher can be stopped at any time. */
|
||||
proc_exit(0);
|
||||
} else if (IsLogicalWorker()) {
|
||||
ereport(FATAL, (errcode(ERRCODE_ADMIN_SHUTDOWN),
|
||||
errmsg("terminating logical replication worker due to administrator command")));
|
||||
#endif
|
||||
} else if (IsTxnSnapCapturerProcess()) {
|
||||
ereport(FATAL,
|
||||
|
|
@ -7572,7 +7574,7 @@ int PostgresMain(int argc, char* argv[], const char* dbname, const char* usernam
|
|||
init_set_params_htab();
|
||||
|
||||
#ifndef ENABLE_MULTIPLE_NODES
|
||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT)) {
|
||||
if (u_sess->proc_cxt.MyDatabaseId != InvalidOid && DB_IS_CMPT(B_FORMAT) && u_sess->attr.attr_sql.dolphin) {
|
||||
InitBSqlPluginHookIfNeeded();
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue