2020-06-14 16:09:17 +00:00
|
|
|
/*
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in the
|
|
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
|
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES
|
|
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <mio-mar.h>
|
2020-06-18 09:28:36 +00:00
|
|
|
#include "mio-prv.h"
|
2020-06-14 16:09:17 +00:00
|
|
|
|
|
|
|
#include <mariadb/mysql.h>
|
2020-06-24 03:00:46 +00:00
|
|
|
#include <mariadb/errmsg.h>
|
2020-06-14 16:09:17 +00:00
|
|
|
|
2020-06-18 09:28:36 +00:00
|
|
|
typedef struct sess_t sess_t;
|
|
|
|
typedef struct sess_qry_t sess_qry_t;
|
|
|
|
|
2020-06-14 16:09:17 +00:00
|
|
|
struct mio_svc_marc_t
|
|
|
|
{
|
|
|
|
MIO_SVC_HEADER;
|
2020-06-17 13:53:38 +00:00
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
mio_svc_marc_connect_t ci;
|
2020-06-24 03:00:46 +00:00
|
|
|
int stopping;
|
2020-06-19 09:17:42 +00:00
|
|
|
|
2020-06-18 09:28:36 +00:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
sess_t* ptr;
|
|
|
|
mio_oow_t capa;
|
|
|
|
} sess;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sess_qry_t
|
|
|
|
{
|
|
|
|
mio_bch_t* qptr;
|
|
|
|
mio_oow_t qlen;
|
|
|
|
void* qctx;
|
2020-06-21 08:42:36 +00:00
|
|
|
unsigned int sent: 1;
|
|
|
|
unsigned int need_fetch: 1;
|
2020-06-18 09:28:36 +00:00
|
|
|
|
2020-06-21 08:42:36 +00:00
|
|
|
mio_svc_marc_on_result_t on_result;
|
2020-06-18 09:28:36 +00:00
|
|
|
sess_qry_t* sq_next;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sess_t
|
|
|
|
{
|
2020-06-19 09:17:42 +00:00
|
|
|
mio_oow_t sid;
|
|
|
|
mio_svc_marc_t* svc;
|
2020-06-18 09:28:36 +00:00
|
|
|
mio_dev_mar_t* dev;
|
2020-06-19 09:17:42 +00:00
|
|
|
int connected;
|
2020-06-18 09:28:36 +00:00
|
|
|
|
|
|
|
sess_qry_t* q_head;
|
2020-06-19 09:17:42 +00:00
|
|
|
sess_qry_t* q_tail;
|
2020-06-14 16:09:17 +00:00
|
|
|
};
|
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
typedef struct dev_xtn_t dev_xtn_t;
|
|
|
|
|
|
|
|
struct dev_xtn_t
|
|
|
|
{
|
|
|
|
sess_t* sess;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
mio_svc_marc_t* mio_svc_marc_start (mio_t* mio, const mio_svc_marc_connect_t* ci)
|
2020-06-14 16:09:17 +00:00
|
|
|
{
|
|
|
|
mio_svc_marc_t* marc = MIO_NULL;
|
|
|
|
|
|
|
|
marc = (mio_svc_marc_t*)mio_callocmem(mio, MIO_SIZEOF(*marc));
|
|
|
|
if (MIO_UNLIKELY(!marc)) goto oops;
|
|
|
|
|
2020-06-18 09:28:36 +00:00
|
|
|
marc->mio = mio;
|
2020-06-14 16:09:17 +00:00
|
|
|
marc->svc_stop = mio_svc_marc_stop;
|
2020-06-19 09:17:42 +00:00
|
|
|
marc->ci = *ci;
|
2020-06-14 16:09:17 +00:00
|
|
|
|
|
|
|
MIO_SVCL_APPEND_SVC (&mio->actsvc, (mio_svc_t*)marc);
|
|
|
|
return marc;
|
|
|
|
|
|
|
|
oops:
|
|
|
|
if (marc)
|
|
|
|
{
|
|
|
|
mio_freemem (mio, marc);
|
|
|
|
}
|
|
|
|
return MIO_NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mio_svc_marc_stop (mio_svc_marc_t* marc)
|
|
|
|
{
|
|
|
|
mio_t* mio = marc->mio;
|
2020-06-24 03:00:46 +00:00
|
|
|
mio_oow_t i;
|
|
|
|
|
|
|
|
marc->stopping = 1;
|
|
|
|
|
|
|
|
for (i = 0; i < marc->sess.capa; i++)
|
|
|
|
{
|
|
|
|
if (marc->sess.ptr[i].dev) mio_dev_mar_kill (marc->sess.ptr[i].dev);
|
|
|
|
}
|
|
|
|
mio_freemem (mio, marc->sess.ptr);
|
2020-06-14 16:09:17 +00:00
|
|
|
|
|
|
|
MIO_SVCL_UNLINK_SVC (marc);
|
|
|
|
mio_freemem (mio, marc);
|
|
|
|
}
|
2020-06-17 13:53:38 +00:00
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
|
2020-06-21 08:42:36 +00:00
|
|
|
static sess_qry_t* make_session_query (mio_t* mio, mio_svc_marc_qtype_t qtype, const mio_bch_t* qptr, mio_oow_t qlen, void* qctx, mio_svc_marc_on_result_t on_result)
|
2020-06-19 09:17:42 +00:00
|
|
|
{
|
|
|
|
sess_qry_t* sq;
|
|
|
|
|
|
|
|
sq = mio_allocmem(mio, MIO_SIZEOF(*sq) + (MIO_SIZEOF(*qptr) * qlen));
|
|
|
|
if (MIO_UNLIKELY(!sq)) return MIO_NULL;
|
|
|
|
|
|
|
|
MIO_MEMCPY (sq + 1, qptr, (MIO_SIZEOF(*qptr) * qlen));
|
|
|
|
|
|
|
|
sq->sent = 0;
|
2020-06-21 08:42:36 +00:00
|
|
|
sq->need_fetch = (qtype == MIO_SVC_MARC_QTYPE_SELECT);
|
2020-06-19 09:17:42 +00:00
|
|
|
sq->qptr = (mio_bch_t*)(sq + 1);
|
|
|
|
sq->qlen = qlen;
|
|
|
|
sq->qctx = qctx;
|
2020-06-21 08:42:36 +00:00
|
|
|
sq->on_result = on_result;
|
2020-06-19 09:17:42 +00:00
|
|
|
sq->sq_next = MIO_NULL;
|
|
|
|
|
|
|
|
return sq;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MIO_INLINE void free_session_query (mio_t* mio, sess_qry_t* sq)
|
|
|
|
{
|
|
|
|
mio_freemem (mio, sq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static MIO_INLINE void enqueue_session_query (sess_t* sess, sess_qry_t* sq)
|
|
|
|
{
|
|
|
|
/* the initialization creates a place holder. so no need to check if q_tail is NULL */
|
|
|
|
sess->q_tail->sq_next = sq;
|
|
|
|
sess->q_tail = sq;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MIO_INLINE void dequeue_session_query (mio_t* mio, sess_t* sess)
|
|
|
|
{
|
|
|
|
sess_qry_t* sq;
|
|
|
|
|
|
|
|
sq = sess->q_head;
|
|
|
|
MIO_ASSERT (mio, sq->sq_next != MIO_NULL); /* must not be empty */
|
|
|
|
sess->q_head = sq->sq_next;
|
|
|
|
free_session_query (mio, sq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static MIO_INLINE sess_qry_t* get_first_session_query (sess_t* sess)
|
|
|
|
{
|
|
|
|
return sess->q_head->sq_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static int send_pending_query_if_any (sess_t* sess)
|
|
|
|
{
|
|
|
|
sess_qry_t* sq;
|
|
|
|
|
|
|
|
sq = get_first_session_query(sess);
|
|
|
|
if (sq)
|
|
|
|
{
|
|
|
|
sq->sent = 1;
|
|
|
|
printf ("sending... %.*s\n", (int)sq->qlen, sq->qptr);
|
|
|
|
if (mio_dev_mar_querywithbchars(sess->dev, sq->qptr, sq->qlen) <= -1)
|
|
|
|
{
|
2020-06-24 03:00:46 +00:00
|
|
|
MIO_DEBUG1 (sess->svc->mio, "QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ SEND FAIL %js\n", mio_geterrmsg(sess->svc->mio));
|
2020-06-19 09:17:42 +00:00
|
|
|
sq->sent = 0;
|
2020-06-24 03:00:46 +00:00
|
|
|
mio_dev_mar_halt (sess->dev); /* this device can't carray on */
|
|
|
|
return -1; /* halted the device for failure */
|
2020-06-19 09:17:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1; /* sent */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0; /* nothing to send */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------- */
|
2020-06-24 03:00:46 +00:00
|
|
|
static mio_dev_mar_t* alloc_device (mio_svc_marc_t* marc, sess_t* sess);
|
2020-06-19 09:17:42 +00:00
|
|
|
|
2020-06-17 13:53:38 +00:00
|
|
|
static void mar_on_disconnect (mio_dev_mar_t* dev)
|
|
|
|
{
|
2020-06-24 03:00:46 +00:00
|
|
|
mio_t* mio = dev->mio;
|
2020-06-19 09:17:42 +00:00
|
|
|
dev_xtn_t* xtn = (dev_xtn_t*)mio_dev_mar_getxtn(dev);
|
|
|
|
sess_t* sess = xtn->sess;
|
|
|
|
|
2020-06-24 03:00:46 +00:00
|
|
|
MIO_DEBUG6 (mio, "MARC(%p) - device disconnected - sid %lu session %p session-connected %d device %p device-broken %d\n", sess->svc, (unsigned long int)sess->sid, sess, (int)sess->connected, dev, (int)dev->broken);
|
|
|
|
MIO_ASSERT (mio, dev == sess->dev);
|
|
|
|
|
|
|
|
if (MIO_UNLIKELY(!sess->svc->stopping && mio->stopreq == MIO_STOPREQ_NONE))
|
|
|
|
{
|
|
|
|
if (sess->connected && sess->dev->broken) /* risk of infinite cycle if the underlying db suffers never-ending 'broken' issue after getting connected */
|
|
|
|
{
|
|
|
|
/* restart the dead device */
|
|
|
|
mio_dev_mar_t* dev;
|
|
|
|
|
|
|
|
sess->connected = 0;
|
|
|
|
|
|
|
|
dev = alloc_device(sess->svc, sess);
|
|
|
|
if (MIO_LIKELY(dev))
|
|
|
|
{
|
|
|
|
sess->dev = dev;
|
|
|
|
/* the pending query will be sent in on_connect() */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if device allocation fails, just carry on */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
sess->connected = 0;
|
|
|
|
|
2020-06-24 03:00:46 +00:00
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
sess_qry_t* sq;
|
|
|
|
mio_svc_marc_dev_error_t err;
|
2020-06-19 09:17:42 +00:00
|
|
|
|
2020-06-24 03:00:46 +00:00
|
|
|
sq = get_first_session_query(sess);
|
|
|
|
if (!sq) break;
|
|
|
|
|
|
|
|
/* what is the best error code and message to use for this? */
|
|
|
|
err.mar_errcode = CR_SERVER_LOST;
|
|
|
|
err.mar_errmsg = "server lost";
|
|
|
|
sq->on_result (sess->svc, sess->sid, MIO_SVC_MARC_RCODE_ERROR, &err, sq->qctx);
|
|
|
|
dequeue_session_query (mio, sess);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* it should point to a placeholder node(either the initial one or the transited one after dequeing */
|
|
|
|
MIO_ASSERT (mio, sess->q_head == sess->q_tail);
|
|
|
|
MIO_ASSERT (mio, sess->q_head->sq_next == MIO_NULL);
|
|
|
|
free_session_query (mio, sess->q_head);
|
|
|
|
sess->q_head = sess->q_tail = MIO_NULL;
|
|
|
|
|
|
|
|
sess->dev = MIO_NULL;
|
2020-06-17 13:53:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void mar_on_connect (mio_dev_mar_t* dev)
|
|
|
|
{
|
2020-06-24 03:00:46 +00:00
|
|
|
mio_t* mio = dev->mio;
|
2020-06-19 09:17:42 +00:00
|
|
|
dev_xtn_t* xtn = (dev_xtn_t*)mio_dev_mar_getxtn(dev);
|
|
|
|
sess_t* sess = xtn->sess;
|
|
|
|
|
2020-06-24 03:00:46 +00:00
|
|
|
MIO_DEBUG5 (mio, "MARC(%p) - device connected - sid %lu session %p device %p device-broken %d\n", sess->svc, (unsigned long int)sess->sid, sess, dev, dev->broken);
|
2020-06-19 09:17:42 +00:00
|
|
|
|
2020-06-24 03:00:46 +00:00
|
|
|
sess->connected = 1;
|
|
|
|
send_pending_query_if_any (sess);
|
2020-06-17 13:53:38 +00:00
|
|
|
}
|
|
|
|
|
2020-06-21 08:42:36 +00:00
|
|
|
static void mar_on_query_started (mio_dev_mar_t* dev, int mar_ret, const mio_bch_t* mar_errmsg)
|
2020-06-17 13:53:38 +00:00
|
|
|
{
|
2020-06-21 08:42:36 +00:00
|
|
|
dev_xtn_t* xtn = (dev_xtn_t*)mio_dev_mar_getxtn(dev);
|
|
|
|
sess_t* sess = xtn->sess;
|
|
|
|
sess_qry_t* sq = get_first_session_query(sess);
|
|
|
|
|
|
|
|
if (mar_ret)
|
2020-06-19 09:17:42 +00:00
|
|
|
{
|
2020-06-21 15:30:44 +00:00
|
|
|
mio_svc_marc_dev_error_t err;
|
2020-06-21 08:42:36 +00:00
|
|
|
printf ("QUERY FAILED...%d -> %s\n", mar_ret, mar_errmsg);
|
|
|
|
|
2020-06-21 15:30:44 +00:00
|
|
|
err.mar_errcode = mar_ret;
|
|
|
|
err.mar_errmsg = mar_errmsg;
|
|
|
|
sq->on_result(sess->svc, sess->sid, MIO_SVC_MARC_RCODE_ERROR, &err, sq->qctx);
|
2020-06-21 08:42:36 +00:00
|
|
|
|
|
|
|
dequeue_session_query (sess->svc->mio, sess);
|
|
|
|
send_pending_query_if_any (sess);
|
2020-06-19 09:17:42 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-06-21 08:42:36 +00:00
|
|
|
printf ("QUERY STARTED\n");
|
|
|
|
if (sq->need_fetch)
|
2020-06-19 09:17:42 +00:00
|
|
|
{
|
2020-06-21 08:42:36 +00:00
|
|
|
if (mio_dev_mar_fetchrows(dev) <= -1)
|
|
|
|
{
|
|
|
|
//printf ("FETCH ROW FAILURE - %s\n", mysql_error(dev->hnd));
|
|
|
|
mio_dev_mar_halt (dev);
|
|
|
|
}
|
2020-06-19 09:17:42 +00:00
|
|
|
}
|
2020-06-21 08:42:36 +00:00
|
|
|
else
|
2020-06-17 13:53:38 +00:00
|
|
|
{
|
2020-06-24 03:00:46 +00:00
|
|
|
sq->on_result (sess->svc, sess->sid, MIO_SVC_MARC_RCODE_DONE, MIO_NULL, sq->qctx);
|
2020-06-21 08:42:36 +00:00
|
|
|
dequeue_session_query (sess->svc->mio, sess);
|
|
|
|
send_pending_query_if_any (sess);
|
2020-06-17 13:53:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void mar_on_row_fetched (mio_dev_mar_t* dev, void* data)
|
|
|
|
{
|
2020-06-19 09:17:42 +00:00
|
|
|
dev_xtn_t* xtn = (dev_xtn_t*)mio_dev_mar_getxtn(dev);
|
|
|
|
sess_t* sess = xtn->sess;
|
2020-06-21 08:42:36 +00:00
|
|
|
sess_qry_t* sq = get_first_session_query(sess);
|
2020-06-19 09:17:42 +00:00
|
|
|
|
2020-06-24 03:00:46 +00:00
|
|
|
sq->on_result (sess->svc, sess->sid, (data? MIO_SVC_MARC_RCODE_ROW: MIO_SVC_MARC_RCODE_DONE), data, sq->qctx);
|
2020-06-21 08:42:36 +00:00
|
|
|
|
|
|
|
if (!data)
|
2020-06-19 09:17:42 +00:00
|
|
|
{
|
2020-06-21 08:42:36 +00:00
|
|
|
dequeue_session_query (sess->svc->mio, sess);
|
|
|
|
send_pending_query_if_any (sess);
|
2020-06-19 09:17:42 +00:00
|
|
|
}
|
2020-06-17 13:53:38 +00:00
|
|
|
}
|
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
static mio_dev_mar_t* alloc_device (mio_svc_marc_t* marc, sess_t* sess)
|
2020-06-17 13:53:38 +00:00
|
|
|
{
|
|
|
|
mio_t* mio = (mio_t*)marc->mio;
|
|
|
|
mio_dev_mar_t* mar;
|
|
|
|
mio_dev_mar_make_t mi;
|
2020-06-19 09:17:42 +00:00
|
|
|
dev_xtn_t* xtn;
|
2020-06-17 13:53:38 +00:00
|
|
|
|
|
|
|
MIO_MEMSET (&mi, 0, MIO_SIZEOF(mi));
|
|
|
|
mi.on_connect = mar_on_connect;
|
|
|
|
mi.on_disconnect = mar_on_disconnect;
|
|
|
|
mi.on_query_started = mar_on_query_started;
|
|
|
|
mi.on_row_fetched = mar_on_row_fetched;
|
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
mar = mio_dev_mar_make(mio, MIO_SIZEOF(*xtn), &mi);
|
2020-06-17 13:53:38 +00:00
|
|
|
if (!mar) return MIO_NULL;
|
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
xtn = (dev_xtn_t*)mio_dev_mar_getxtn(mar);
|
|
|
|
xtn->sess = sess;
|
2020-06-17 13:53:38 +00:00
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
if (mio_dev_mar_connect(mar, &marc->ci) <= -1) return MIO_NULL;
|
2020-06-18 09:28:36 +00:00
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
return mar;
|
2020-06-18 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
/* ------------------------------------------------------------------- */
|
2020-06-18 09:28:36 +00:00
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
static sess_t* get_session (mio_svc_marc_t* marc, mio_oow_t sid)
|
2020-06-18 09:28:36 +00:00
|
|
|
{
|
|
|
|
mio_t* mio = marc->mio;
|
|
|
|
sess_t* sess;
|
|
|
|
|
|
|
|
if (sid >= marc->sess.capa)
|
|
|
|
{
|
|
|
|
sess_t* tmp;
|
|
|
|
mio_oow_t newcapa;
|
|
|
|
|
|
|
|
newcapa = marc->sess.capa + 16;
|
|
|
|
if (newcapa <= sid) newcapa = sid + 1;
|
|
|
|
newcapa = MIO_ALIGN_POW2(newcapa, 16);
|
|
|
|
|
|
|
|
tmp = mio_reallocmem(mio, marc->sess.ptr, MIO_SIZEOF(sess_t) * newcapa);
|
|
|
|
if (MIO_UNLIKELY(!tmp)) return MIO_NULL;
|
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
MIO_MEMSET (&tmp[marc->sess.capa], 0, MIO_SIZEOF(sess_t) * (newcapa - marc->sess.capa));
|
2020-06-18 09:28:36 +00:00
|
|
|
|
|
|
|
marc->sess.ptr = tmp;
|
|
|
|
marc->sess.capa = newcapa;
|
2020-06-19 09:17:42 +00:00
|
|
|
|
|
|
|
sess = &marc->sess.ptr[sid];
|
|
|
|
sess->svc = marc;
|
|
|
|
sess->sid = sid;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sess = &marc->sess.ptr[sid];
|
|
|
|
MIO_ASSERT (mio, sess->sid == sid);
|
|
|
|
MIO_ASSERT (mio, sess->svc == marc);
|
2020-06-18 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!sess->dev)
|
|
|
|
{
|
|
|
|
sess_qry_t* sq;
|
|
|
|
|
2020-06-21 08:42:36 +00:00
|
|
|
sq = make_session_query(mio, MIO_SVC_MARC_QTYPE_ACTION, "", 0, MIO_NULL, 0); /* this is a place holder */
|
2020-06-18 09:28:36 +00:00
|
|
|
if (MIO_UNLIKELY(!sq)) return MIO_NULL;
|
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
sess->dev = alloc_device(marc, sess);
|
2020-06-18 09:28:36 +00:00
|
|
|
if (MIO_UNLIKELY(!sess->dev))
|
|
|
|
{
|
|
|
|
free_session_query (mio, sq);
|
|
|
|
return MIO_NULL;
|
|
|
|
}
|
|
|
|
|
2020-06-24 03:00:46 +00:00
|
|
|
/* queue initialization with a place holder. the queue maintains a placeholder node.
|
|
|
|
* the first actual data node enqueued is inserted at the back and becomes the second
|
|
|
|
* node in terms of the entire queue.
|
|
|
|
*
|
|
|
|
* PH -> DN1 -> DN2 -> ... -> DNX
|
|
|
|
* ^ ^
|
|
|
|
* q_head q_tail
|
|
|
|
*
|
|
|
|
* get_first_session_query() returns the data of DN1, not the data held in PH.
|
|
|
|
*
|
|
|
|
* the first dequeing operations kills PH.
|
|
|
|
*
|
|
|
|
* DN1 -> DN2 -> ... -> DNX
|
|
|
|
* ^ ^
|
|
|
|
* q_head q_tail
|
|
|
|
*
|
|
|
|
* get_first_session_query() at this point returns the data of DN2, not the data held in DN1.
|
|
|
|
* dequeing kills DN1, however.
|
|
|
|
*/
|
|
|
|
|
2020-06-18 09:28:36 +00:00
|
|
|
sess->q_head = sess->q_tail = sq;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sess;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-21 08:42:36 +00:00
|
|
|
int mio_svc_mar_querywithbchars (mio_svc_marc_t* marc, mio_oow_t sid, mio_svc_marc_qtype_t qtype, const mio_bch_t* qptr, mio_oow_t qlen, mio_svc_marc_on_result_t on_result, void* qctx)
|
2020-06-18 09:28:36 +00:00
|
|
|
{
|
|
|
|
mio_t* mio = marc->mio;
|
|
|
|
sess_t* sess;
|
2020-06-19 09:17:42 +00:00
|
|
|
sess_qry_t* sq;
|
2020-06-18 09:28:36 +00:00
|
|
|
|
|
|
|
sess = get_session(marc, sid);
|
|
|
|
if (MIO_UNLIKELY(!sess)) return -1;
|
|
|
|
|
2020-06-21 08:42:36 +00:00
|
|
|
sq = make_session_query(mio, qtype, qptr, qlen, qctx, on_result);
|
2020-06-19 09:17:42 +00:00
|
|
|
if (MIO_UNLIKELY(!sq)) return -1;
|
2020-06-18 09:28:36 +00:00
|
|
|
|
2020-06-24 03:00:46 +00:00
|
|
|
if (get_first_session_query(sess) || !sess->connected)
|
2020-06-18 09:28:36 +00:00
|
|
|
{
|
2020-06-19 09:17:42 +00:00
|
|
|
/* there are other ongoing queries */
|
|
|
|
enqueue_session_query (sess, sq);
|
2020-06-18 09:28:36 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-06-24 03:00:46 +00:00
|
|
|
/* this is the first query or the device is not connected yet */
|
2020-06-19 09:17:42 +00:00
|
|
|
sess_qry_t* old_q_tail = sess->q_tail;
|
2020-06-24 03:00:46 +00:00
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
enqueue_session_query (sess, sq);
|
2020-06-17 13:53:38 +00:00
|
|
|
|
2020-06-24 03:00:46 +00:00
|
|
|
MIO_ASSERT (mio, sq->sent == 0);
|
|
|
|
|
|
|
|
sq->sent = 1;
|
|
|
|
if (mio_dev_mar_querywithbchars(sess->dev, sq->qptr, sq->qlen) <= -1)
|
2020-06-19 09:17:42 +00:00
|
|
|
{
|
2020-06-24 03:00:46 +00:00
|
|
|
sq->sent = 0;
|
|
|
|
if (!sess->dev->broken)
|
2020-06-19 09:17:42 +00:00
|
|
|
{
|
2020-06-24 03:00:46 +00:00
|
|
|
/* unlink the the last item added */
|
2020-06-19 09:17:42 +00:00
|
|
|
old_q_tail->sq_next = MIO_NULL;
|
|
|
|
sess->q_tail = old_q_tail;
|
|
|
|
|
|
|
|
free_session_query (mio, sq);
|
|
|
|
return -1;
|
|
|
|
}
|
2020-06-24 03:00:46 +00:00
|
|
|
|
|
|
|
/* the underlying socket of the device may get disconnected.
|
|
|
|
* in such a case, keep the enqueued query with sq->sent 0
|
|
|
|
* and defer actual sending and processing */
|
2020-06-19 09:17:42 +00:00
|
|
|
}
|
2020-06-18 09:28:36 +00:00
|
|
|
}
|
|
|
|
|
2020-06-19 09:17:42 +00:00
|
|
|
return 0;
|
2020-06-18 09:28:36 +00:00
|
|
|
}
|