added the default group option to the mariadb device and the mariadb client service

added the issyshndbroken() callback to hio_dev_mth_t
implemented the callback in the mariadb device.
enhanced the epoll/kqueue multiplexer implementation to use the callback
This commit is contained in:
hyung-hwan 2021-07-26 15:19:31 +00:00
parent 9558e12c3e
commit d7e5ebdf4f
10 changed files with 67 additions and 10 deletions

View File

@ -237,7 +237,7 @@ int main (int argc, char* argv[])
HIO_INIT_NTIME (&tmout.w, -1, 0); HIO_INIT_NTIME (&tmout.w, -1, 0);
*/ */
marc = hio_svc_marc_start(hio, &ci, HIO_NULL); marc = hio_svc_marc_start(hio, &ci, HIO_NULL, HIO_NULL);
if (!marc) if (!marc)
{ {
printf ("Cannot start a mariadb client service\n"); printf ("Cannot start a mariadb client service\n");

View File

@ -125,6 +125,8 @@ struct hio_dev_mar_make_t
{ {
int flags; int flags;
hio_dev_mar_tmout_t tmout; hio_dev_mar_tmout_t tmout;
const hio_bch_t* default_group;
hio_dev_mar_on_write_t on_write; /* mandatory */ hio_dev_mar_on_write_t on_write; /* mandatory */
hio_dev_mar_on_read_t on_read; /* mandatory */ hio_dev_mar_on_read_t on_read; /* mandatory */
hio_dev_mar_on_connect_t on_connect; /* optional */ hio_dev_mar_on_connect_t on_connect; /* optional */
@ -251,7 +253,8 @@ HIO_EXPORT hio_oow_t hio_dev_mar_escapebchars (
HIO_EXPORT hio_svc_marc_t* hio_svc_marc_start ( HIO_EXPORT hio_svc_marc_t* hio_svc_marc_start (
hio_t* hio, hio_t* hio,
const hio_svc_marc_connect_t* ci, const hio_svc_marc_connect_t* ci,
const hio_svc_marc_tmout_t* tmout const hio_svc_marc_tmout_t* tmout,
const hio_bch_t* default_group
); );
HIO_EXPORT void hio_svc_marc_stop ( HIO_EXPORT void hio_svc_marc_stop (

View File

@ -222,7 +222,8 @@ struct hio_dev_mth_t
void (*fail_before_make) (void* ctx); void (*fail_before_make) (void* ctx);
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
hio_syshnd_t (*getsyshnd) (hio_dev_t* dev); /* mandatory. called in hio_dev_make() after successful make() */ hio_syshnd_t (*getsyshnd) (hio_dev_t* dev); /* mandatory. called in hio_dev_make() after successful make() */
int (*issyshndbroken) (hio_dev_t* dev); /* the device whose underlying system handle can get closed before kill() must implement this */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
/* return -1 on failure, 0 if no data is availble, 1 otherwise. /* return -1 on failure, 0 if no data is availble, 1 otherwise.

View File

@ -45,6 +45,8 @@ struct hio_svc_marc_t
int stopping; int stopping;
int tmout_set; int tmout_set;
const hio_bch_t* default_group;
hio_svc_marc_connect_t ci; hio_svc_marc_connect_t ci;
hio_svc_marc_tmout_t tmout; hio_svc_marc_tmout_t tmout;
@ -90,7 +92,7 @@ struct dev_xtn_t
#define INVALID_SID HIO_TYPE_MAX(hio_oow_t) #define INVALID_SID HIO_TYPE_MAX(hio_oow_t)
hio_svc_marc_t* hio_svc_marc_start (hio_t* hio, const hio_svc_marc_connect_t* ci, const hio_svc_marc_tmout_t* tmout) hio_svc_marc_t* hio_svc_marc_start (hio_t* hio, const hio_svc_marc_connect_t* ci, const hio_svc_marc_tmout_t* tmout, const hio_bch_t* default_group)
{ {
hio_svc_marc_t* marc = HIO_NULL; hio_svc_marc_t* marc = HIO_NULL;
@ -108,6 +110,7 @@ hio_svc_marc_t* hio_svc_marc_start (hio_t* hio, const hio_svc_marc_connect_t* ci
marc->tmout = *tmout; marc->tmout = *tmout;
marc->tmout_set = 1; marc->tmout_set = 1;
} }
marc->default_group = default_group;
HIO_SVCL_APPEND_SVC (&hio->actsvc, (hio_svc_t*)marc); HIO_SVCL_APPEND_SVC (&hio->actsvc, (hio_svc_t*)marc);
return marc; return marc;
@ -368,6 +371,7 @@ static hio_dev_mar_t* alloc_device (hio_svc_marc_t* marc, hio_oow_t sid)
mi.flags = HIO_DEV_MAR_USE_TMOUT; mi.flags = HIO_DEV_MAR_USE_TMOUT;
mi.tmout = marc->tmout; mi.tmout = marc->tmout;
} }
mi.default_group = marc->default_group;
mi.on_connect = mar_on_connect; mi.on_connect = mar_on_connect;
mi.on_disconnect = mar_on_disconnect; mi.on_disconnect = mar_on_disconnect;
@ -378,11 +382,12 @@ static hio_dev_mar_t* alloc_device (hio_svc_marc_t* marc, hio_oow_t sid)
if (HIO_UNLIKELY(!mar)) return HIO_NULL; if (HIO_UNLIKELY(!mar)) return HIO_NULL;
xtn = (dev_xtn_t*)hio_dev_mar_getxtn(mar); xtn = (dev_xtn_t*)hio_dev_mar_getxtn(mar);
xtn->sid = sid;
xtn->svc = marc; xtn->svc = marc;
xtn->sid = sid;
if (hio_dev_mar_connect(mar, &marc->ci) <= -1) if (hio_dev_mar_connect(mar, &marc->ci) <= -1)
{ {
/* connection failed immediately */
xtn->sid = INVALID_SID; xtn->sid = INVALID_SID;
hio_dev_mar_halt (mar); hio_dev_mar_halt (mar);
return HIO_NULL; return HIO_NULL;
@ -422,8 +427,8 @@ static sess_t* get_session (hio_svc_marc_t* marc, hio_oow_t sid)
} }
sess = &marc->sess.ptr[sid]; sess = &marc->sess.ptr[sid];
HIO_ASSERT (hio, sess->sid == sid);
HIO_ASSERT (hio, sess->svc == marc); HIO_ASSERT (hio, sess->svc == marc);
HIO_ASSERT (hio, sess->sid == sid);
if (!sess->dev) if (!sess->dev)
{ {

View File

@ -52,6 +52,9 @@ static int dev_mar_make (hio_dev_t* dev, void* ctx)
return -1; return -1;
} }
if (mi->default_group) /* don't care about success/failure */
mysql_options(rdev->hnd, MYSQL_READ_DEFAULT_GROUP, mi->default_group);
if (mysql_options(rdev->hnd, MYSQL_OPT_NONBLOCK, 0) != 0) if (mysql_options(rdev->hnd, MYSQL_OPT_NONBLOCK, 0) != 0)
{ {
hio_seterrbfmt (hio, HIO_ESYSERR, "%hs", mysql_error(rdev->hnd)); hio_seterrbfmt (hio, HIO_ESYSERR, "%hs", mysql_error(rdev->hnd));
@ -137,6 +140,7 @@ static int dev_mar_kill (hio_dev_t* dev, int force)
rdev->connected = 0; rdev->connected = 0;
rdev->broken = 0; rdev->broken = 0;
rdev->broken_syshnd = HIO_SYSHND_INVALID;
return 0; return 0;
} }
@ -148,6 +152,12 @@ static hio_syshnd_t dev_mar_getsyshnd (hio_dev_t* dev)
return (hio_syshnd_t)mysql_get_socket(rdev->hnd); return (hio_syshnd_t)mysql_get_socket(rdev->hnd);
} }
static int dev_mar_issyshndbroken (hio_dev_t* dev)
{
hio_dev_mar_t* rdev = (hio_dev_mar_t*)dev;
return rdev->broken;
}
static int events_to_mysql_wstatus (int events) static int events_to_mysql_wstatus (int events)
{ {
int wstatus = 0; int wstatus = 0;
@ -235,12 +245,17 @@ static int dev_mar_ioctl (hio_dev_t* dev, int cmd, void* arg)
if (HIO_UNLIKELY(!tmp)) /* connection attempt failed immediately */ if (HIO_UNLIKELY(!tmp)) /* connection attempt failed immediately */
{ {
/* immediate failure doesn't invoke on_discoonect(). /* immediate failure doesn't invoke on_discoonect().
* the caller must check the return code of this function. */ * the caller must check the return code of this function. */
rdev->connected = 0;
rdev->broken = 1;
rdev->broken_syshnd = HIO_SYSHND_INVALID;
hio_seterrbfmt (hio, HIO_ESYSERR, "%hs", mysql_error(rdev->hnd)); hio_seterrbfmt (hio, HIO_ESYSERR, "%hs", mysql_error(rdev->hnd));
return -1; return -1;
} }
/* connected_deferred immediately. postpone actual handling to the ready() callback */ /* connected immediately. postpone actual handling to the ready() callback */
HIO_DEV_MAR_SET_PROGRESS (rdev, HIO_DEV_MAR_CONNECTING); HIO_DEV_MAR_SET_PROGRESS (rdev, HIO_DEV_MAR_CONNECTING);
rdev->connected_deferred = 1; /* to let the ready() handler to trigger on_connect() */ rdev->connected_deferred = 1; /* to let the ready() handler to trigger on_connect() */
/* regiter it in the multiplexer so that the ready() handler is /* regiter it in the multiplexer so that the ready() handler is
@ -291,8 +306,12 @@ static int dev_mar_ioctl (hio_dev_t* dev, int cmd, void* arg)
/* the underlying socket must have gotten closed by mysql_real_query_start() */ /* the underlying socket must have gotten closed by mysql_real_query_start() */
const hio_ooch_t* prev_errmsg; const hio_ooch_t* prev_errmsg;
prev_errmsg = hio_backuperrmsg(hio); prev_errmsg = hio_backuperrmsg(hio);
rdev->connected = 0;
rdev->broken = 1; rdev->broken = 1;
rdev->broken_syshnd = syshnd; /* remember the previous handle - this may be needed by the poll/select based multiplexer */
rdev->broken_syshnd = syshnd;
watch_mysql (rdev, 0); watch_mysql (rdev, 0);
hio_dev_mar_halt (rdev); /* i can't keep this device alive regardless of the caller's post-action */ hio_dev_mar_halt (rdev); /* i can't keep this device alive regardless of the caller's post-action */
hio_seterrbfmt (hio, HIO_ESYSERR, "%js", prev_errmsg); hio_seterrbfmt (hio, HIO_ESYSERR, "%js", prev_errmsg);
@ -335,6 +354,7 @@ static hio_dev_mth_t dev_mar_methods =
dev_mar_kill, dev_mar_kill,
HIO_NULL, HIO_NULL,
dev_mar_getsyshnd, dev_mar_getsyshnd,
dev_mar_issyshndbroken,
HIO_NULL, HIO_NULL,
HIO_NULL, HIO_NULL,
@ -416,8 +436,16 @@ static int dev_evcb_mar_ready (hio_dev_t* dev, int events)
{ {
/* connection attempt failed */ /* connection attempt failed */
/* the mysql client library closes the underlying socket handle
* whenever the connection attempt fails. this prevent hio from
* managing the the mysql connections properly. this also causes
* race condition if this library is used in multi-threaded programs. */
rdev->connected = 0;
rdev->broken = 1; /* trick dev_mar_getsyshnd() to return rdev->broken_syshnd. */ rdev->broken = 1; /* trick dev_mar_getsyshnd() to return rdev->broken_syshnd. */
rdev->broken_syshnd = syshnd; /* mysql_get_socket() over a failed mariadb handle ends up with segfault */ /* remember the previous handle - this may be needed by the poll/select based multiplexer
* mysql_get_socket() over a failed mariadb handle ends up with segfault */
rdev->broken_syshnd = syshnd;
/* this attempts to trigger the low-level multiplxer to delete 'syshnd' closed by mysql_real_connect_cont(). /* this attempts to trigger the low-level multiplxer to delete 'syshnd' closed by mysql_real_connect_cont().
* the underlying low-level operation may fail. but i don't care. the best is not to open * the underlying low-level operation may fail. but i don't care. the best is not to open

View File

@ -376,6 +376,7 @@ static hio_dev_mth_t dev_pipe_methods =
dev_pipe_kill_master, dev_pipe_kill_master,
HIO_NULL, HIO_NULL,
dev_pipe_getsyshnd, dev_pipe_getsyshnd,
HIO_NULL,
HIO_NULL, HIO_NULL,
HIO_NULL, HIO_NULL,
@ -389,6 +390,7 @@ static hio_dev_mth_t dev_pipe_methods_slave =
dev_pipe_kill_slave, dev_pipe_kill_slave,
dev_pipe_fail_before_make_slave, dev_pipe_fail_before_make_slave,
dev_pipe_getsyshnd_slave, dev_pipe_getsyshnd_slave,
HIO_NULL,
dev_pipe_read_slave, dev_pipe_read_slave,
dev_pipe_write_slave, dev_pipe_write_slave,

View File

@ -738,6 +738,7 @@ static hio_dev_mth_t dev_pro_methods =
dev_pro_kill_master, dev_pro_kill_master,
HIO_NULL, HIO_NULL,
dev_pro_getsyshnd, dev_pro_getsyshnd,
HIO_NULL,
HIO_NULL, /* read */ HIO_NULL, /* read */
HIO_NULL, /* write */ HIO_NULL, /* write */
@ -752,6 +753,7 @@ static hio_dev_mth_t dev_pro_methods_slave =
dev_pro_kill_slave, dev_pro_kill_slave,
HIO_NULL, HIO_NULL,
dev_pro_getsyshnd_slave, dev_pro_getsyshnd_slave,
HIO_NULL,
dev_pro_read_slave, dev_pro_read_slave,
dev_pro_write_slave, dev_pro_write_slave,

View File

@ -1398,6 +1398,7 @@ static hio_dev_mth_t dev_mth_sck_stateless =
dev_sck_kill, dev_sck_kill,
HIO_NULL, HIO_NULL,
dev_sck_getsyshnd, dev_sck_getsyshnd,
HIO_NULL,
dev_sck_read_stateless, dev_sck_read_stateless,
dev_sck_write_stateless, dev_sck_write_stateless,
@ -1413,6 +1414,7 @@ static hio_dev_mth_t dev_mth_sck_stateful =
dev_sck_kill, dev_sck_kill,
HIO_NULL, HIO_NULL,
dev_sck_getsyshnd, dev_sck_getsyshnd,
HIO_NULL,
dev_sck_read_stateful, dev_sck_read_stateful,
dev_sck_write_stateful, dev_sck_write_stateful,
@ -1427,6 +1429,7 @@ static hio_dev_mth_t dev_mth_clisck =
dev_sck_kill, dev_sck_kill,
dev_sck_fail_before_make_client, dev_sck_fail_before_make_client,
dev_sck_getsyshnd, dev_sck_getsyshnd,
HIO_NULL,
dev_sck_read_stateful, dev_sck_read_stateful,
dev_sck_write_stateful, dev_sck_write_stateful,
@ -1441,6 +1444,7 @@ static hio_dev_mth_t dev_mth_sck_bpf =
dev_sck_kill, dev_sck_kill,
HIO_NULL, HIO_NULL,
dev_sck_getsyshnd, dev_sck_getsyshnd,
HIO_NULL,
dev_sck_read_bpf, dev_sck_read_bpf,
dev_sck_write_bpf, dev_sck_write_bpf,

View File

@ -419,6 +419,11 @@ int hio_sys_ctrlmux (hio_t* hio, hio_sys_mux_cmd_t cmd, hio_dev_t* dev, int dev_
int x; int x;
HIO_ASSERT (hio, hio == dev->hio); HIO_ASSERT (hio, hio == dev->hio);
/* no operation over a broken(closed) handle to prevent multiplexer from failing.
* close of the handle leads to auto-deletion from the kqueue multiplexer.
* the closed handle must not be fed to the multiplexer */
if (dev->dev_mth->issyshndbroken && dev->dev_mth->issyshndbroken(dev)) return 0;
hnd = dev->dev_mth->getsyshnd(dev); hnd = dev->dev_mth->getsyshnd(dev);
switch (cmd) switch (cmd)
@ -495,6 +500,11 @@ int hio_sys_ctrlmux (hio_t* hio, hio_sys_mux_cmd_t cmd, hio_dev_t* dev, int dev_
int x; int x;
HIO_ASSERT (hio, hio == dev->hio); HIO_ASSERT (hio, hio == dev->hio);
/* no operation over a broken(closed) handle to prevent multiplexer from failing.
* close of the handle leads to auto-deletion from the epoll multiplexer.
* the closed handle must not be fed to the multiplexer */
if (dev->dev_mth->issyshndbroken && dev->dev_mth->issyshndbroken(dev)) return 0;
hnd = dev->dev_mth->getsyshnd(dev); hnd = dev->dev_mth->getsyshnd(dev);
events = 0; events = 0;

View File

@ -568,6 +568,7 @@ static hio_dev_mth_t dev_thr_methods =
dev_thr_kill_master, dev_thr_kill_master,
HIO_NULL, HIO_NULL,
dev_thr_getsyshnd, dev_thr_getsyshnd,
HIO_NULL,
HIO_NULL, HIO_NULL,
HIO_NULL, HIO_NULL,
@ -581,6 +582,7 @@ static hio_dev_mth_t dev_thr_methods_slave =
dev_thr_kill_slave, dev_thr_kill_slave,
dev_thr_fail_before_make_slave, dev_thr_fail_before_make_slave,
dev_thr_getsyshnd_slave, dev_thr_getsyshnd_slave,
HIO_NULL,
dev_thr_read_slave, dev_thr_read_slave,
dev_thr_write_slave, dev_thr_write_slave,