diff --git a/hio/bin/t04.c b/hio/bin/t04.c index aa9aae1..c4d789e 100644 --- a/hio/bin/t04.c +++ b/hio/bin/t04.c @@ -237,7 +237,7 @@ int main (int argc, char* argv[]) 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) { printf ("Cannot start a mariadb client service\n"); diff --git a/hio/lib/hio-mar.h b/hio/lib/hio-mar.h index 82345ec..c2bafa7 100644 --- a/hio/lib/hio-mar.h +++ b/hio/lib/hio-mar.h @@ -125,6 +125,8 @@ struct hio_dev_mar_make_t { int flags; 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_read_t on_read; /* mandatory */ 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_t* hio, 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 ( diff --git a/hio/lib/hio.h b/hio/lib/hio.h index ba314da..248a00f 100644 --- a/hio/lib/hio.h +++ b/hio/lib/hio.h @@ -222,7 +222,8 @@ struct hio_dev_mth_t 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. diff --git a/hio/lib/mar-cli.c b/hio/lib/mar-cli.c index 5e09387..ed7b973 100644 --- a/hio/lib/mar-cli.c +++ b/hio/lib/mar-cli.c @@ -45,6 +45,8 @@ struct hio_svc_marc_t int stopping; int tmout_set; + const hio_bch_t* default_group; + hio_svc_marc_connect_t ci; hio_svc_marc_tmout_t tmout; @@ -90,7 +92,7 @@ struct dev_xtn_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; @@ -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_set = 1; } + marc->default_group = default_group; HIO_SVCL_APPEND_SVC (&hio->actsvc, (hio_svc_t*)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.tmout = marc->tmout; } + mi.default_group = marc->default_group; mi.on_connect = mar_on_connect; 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; xtn = (dev_xtn_t*)hio_dev_mar_getxtn(mar); - xtn->sid = sid; xtn->svc = marc; + xtn->sid = sid; if (hio_dev_mar_connect(mar, &marc->ci) <= -1) { + /* connection failed immediately */ xtn->sid = INVALID_SID; hio_dev_mar_halt (mar); 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]; - HIO_ASSERT (hio, sess->sid == sid); HIO_ASSERT (hio, sess->svc == marc); + HIO_ASSERT (hio, sess->sid == sid); if (!sess->dev) { diff --git a/hio/lib/mar.c b/hio/lib/mar.c index 60f1f1a..cebe5b5 100644 --- a/hio/lib/mar.c +++ b/hio/lib/mar.c @@ -52,6 +52,9 @@ static int dev_mar_make (hio_dev_t* dev, void* ctx) 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) { 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->broken = 0; + rdev->broken_syshnd = HIO_SYSHND_INVALID; 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); } +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) { 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 */ { /* 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)); 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); rdev->connected_deferred = 1; /* to let the ready() handler to trigger on_connect() */ /* 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() */ const hio_ooch_t* prev_errmsg; prev_errmsg = hio_backuperrmsg(hio); + + rdev->connected = 0; 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); 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); @@ -335,6 +354,7 @@ static hio_dev_mth_t dev_mar_methods = dev_mar_kill, HIO_NULL, dev_mar_getsyshnd, + dev_mar_issyshndbroken, HIO_NULL, HIO_NULL, @@ -416,8 +436,16 @@ static int dev_evcb_mar_ready (hio_dev_t* dev, int events) { /* 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_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(). * the underlying low-level operation may fail. but i don't care. the best is not to open diff --git a/hio/lib/pipe.c b/hio/lib/pipe.c index 880273d..e0f7320 100644 --- a/hio/lib/pipe.c +++ b/hio/lib/pipe.c @@ -376,6 +376,7 @@ static hio_dev_mth_t dev_pipe_methods = dev_pipe_kill_master, HIO_NULL, dev_pipe_getsyshnd, + 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_fail_before_make_slave, dev_pipe_getsyshnd_slave, + HIO_NULL, dev_pipe_read_slave, dev_pipe_write_slave, diff --git a/hio/lib/pro.c b/hio/lib/pro.c index cdeb251..67b2934 100644 --- a/hio/lib/pro.c +++ b/hio/lib/pro.c @@ -738,6 +738,7 @@ static hio_dev_mth_t dev_pro_methods = dev_pro_kill_master, HIO_NULL, dev_pro_getsyshnd, + HIO_NULL, HIO_NULL, /* read */ HIO_NULL, /* write */ @@ -752,6 +753,7 @@ static hio_dev_mth_t dev_pro_methods_slave = dev_pro_kill_slave, HIO_NULL, dev_pro_getsyshnd_slave, + HIO_NULL, dev_pro_read_slave, dev_pro_write_slave, diff --git a/hio/lib/sck.c b/hio/lib/sck.c index 0be43fc..1666ab9 100644 --- a/hio/lib/sck.c +++ b/hio/lib/sck.c @@ -1398,6 +1398,7 @@ static hio_dev_mth_t dev_mth_sck_stateless = dev_sck_kill, HIO_NULL, dev_sck_getsyshnd, + HIO_NULL, dev_sck_read_stateless, dev_sck_write_stateless, @@ -1413,6 +1414,7 @@ static hio_dev_mth_t dev_mth_sck_stateful = dev_sck_kill, HIO_NULL, dev_sck_getsyshnd, + HIO_NULL, dev_sck_read_stateful, dev_sck_write_stateful, @@ -1427,6 +1429,7 @@ static hio_dev_mth_t dev_mth_clisck = dev_sck_kill, dev_sck_fail_before_make_client, dev_sck_getsyshnd, + HIO_NULL, dev_sck_read_stateful, dev_sck_write_stateful, @@ -1441,6 +1444,7 @@ static hio_dev_mth_t dev_mth_sck_bpf = dev_sck_kill, HIO_NULL, dev_sck_getsyshnd, + HIO_NULL, dev_sck_read_bpf, dev_sck_write_bpf, diff --git a/hio/lib/sys-mux.c b/hio/lib/sys-mux.c index 7d5b609..e83a1aa 100644 --- a/hio/lib/sys-mux.c +++ b/hio/lib/sys-mux.c @@ -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; 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); 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; 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); events = 0; diff --git a/hio/lib/thr.c b/hio/lib/thr.c index f36dabb..12f8fd4 100644 --- a/hio/lib/thr.c +++ b/hio/lib/thr.c @@ -568,6 +568,7 @@ static hio_dev_mth_t dev_thr_methods = dev_thr_kill_master, HIO_NULL, dev_thr_getsyshnd, + 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_fail_before_make_slave, dev_thr_getsyshnd_slave, + HIO_NULL, dev_thr_read_slave, dev_thr_write_slave,