MariaDB неблокируемый с EPOLL
У меня есть однопоточный сервер, написанный на C, который принимает соединения TCP/UDP на основе EPOLL и поддерживает плагины для множества уровней протоколов, которые нам необходимо поддерживать. Это немного хорошо.
Из-за однопоточной природы я хотел реализовать слой базы данных, который мог бы использовать ту же архитектуру EPOLL, а не раздельно перебирать все открытые соединения.
Мы используем MariaDB и коннектор MariaDB, который поддерживает неблокирующие функции в своем API.
https://mariadb.com/kb/en/mariadb/using-the-non-blocking-library/
Но то, что я нахожу, не то, что я ожидал, а то, что я ожидал, описано ниже.
Сначала я уволить mysql_real_connect_start()
и если он возвращает ноль, мы немедленно отправляем запрос, поскольку это указывает на то, что блокировка не требуется, хотя это никогда не происходит.
В противном случае я извлекаю дескриптор файла, который кажется немедленным, и регистрирую его в EPOLL и возвращаюсь к основному циклу EPOLL в ожидании событий.
s = mysql_get_socket(mysql);
if(s > 0)
{
brt_socket_set_fds(endpoint, s);
struct epoll_event event;
event.data.fd = s;
event.events = EPOLLRDHUP | EPOLLIN | EPOLLET | EPOLLOUT;
s = epoll_ctl(efd, EPOLL_CTL_ADD, s, &event);
if (s == -1) {
syslog(LOG_ERR, "brd_db : epoll error.");
// handle error.
}
...
Итак, через некоторое время я получаю EPOLLOUT, указывающий, что сокет был открыт.
И я покорно вызываю mysql_real_connect_cont(), но на этом этапе он все еще возвращает ненулевое значение, указывая, что я должен ждать дольше?
Но тогда это последнее событие EPOLL, которое я получаю, за исключением EPOLLRDHUP, когда я предполагаю, что MariaDB зависает через 10 секунд.
Может кто-нибудь помочь мне понять, если эта идея даже работоспособна?
Спасибо... Спасибо... большое Спасибо.
1 ответ
Хорошо для всех, кто приземлится здесь, я исправил это или, вернее, не сломал его.
Обратите внимание, что - из примеров - возвращенное состояние от вызовов _start / _cont передается в качестве параметра следующему _cont. Оказывается, это очень важно.
Статус содержит флаги MYSQL_WAIT_READ, MYSQL_WAIT_WRITE, MYSQL_WAIT_EXCEPT, MYSQL_WAIT_TIMEOUT, и если он не передан следующему _конту, я думаю, вы связываетесь с конечным автоматом _cont.
Я не сохранял состояние статуса между разными местами, где вызывались _start и _cont.
struct MC
{
MYSQL *mysql;
int status;
} MC;
...
// Initial call
mc->status = mysql_real_connect_start(&ret, mc->mysql, host, user, password, NULL, 0, NULL, 0);
// EPOLL raised calls.
mc->status = mysql_real_connect_cont(&ret, mc->mysql, mc->status);
if(mc->status) return... // keep waiting check for errors.