From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=A1=D0=B0=D0=BC?= =?UTF-8?q?=D1=83=D1=81=D0=B5=D0=BD=D0=BA=D0=BE?= Date: Mon, 25 Jun 2012 17:54:27 +0400 Subject: [PATCH] Removed all async Oracle operations - they didn't work well anyway diff --git a/modules/db_oracle/asynch.c b/modules/db_oracle/asynch.c deleted file mode 100644 index d1bbe84..0000000 --- a/modules/db_oracle/asynch.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * $Id$ - * - * Oracle module interface - * - * Copyright (C) 2007,2008 TRUNK MOBILE - * - * This file is part of opensips, a free SIP server. - * - * opensips is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version - * - * opensips is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* - * History: - * -------- - */ - -#include -#include -#include -#include -#include "../../dprint.h" -#include "../../sr_module.h" -#include "ora_con.h" -#include "asynch.h" - -#define MAX_TIMEOUT_S 10 -#define MIN_TIMEOUT_MS 100 - - -/* Default is 3.0 second */ -static struct timeval request_tm = { .tv_sec = 3, .tv_usec = 0 }; - -/* Default is 0.2 second */ -static struct timeval restore_tm = { .tv_sec = 0, .tv_usec = 200*1000 }; -static const struct timeval defrest_tm = { .tv_sec = 0, .tv_usec = 200*1000 }; - -static int synch_mode; -static int cur_asynch_mode; -static struct timeval wtm; - - -static __inline__ int is_zero_tm(const struct timeval* tv) -{ - return !tv->tv_usec && !tv->tv_sec; -} - - -/* - * parse timeout value in syntax: nnn.mmm (sec/ms) - */ -static int set_tv(unsigned type, const char* val, struct timeval* tv) -{ - char *eptr; - unsigned long s, ms; - double dv; - - if (type != STR_PARAM) { - LM_ERR("type of parameter is no STR\n"); - return -1; - } - - if (!val || !*val) { - LM_ERR("empty parameter\n"); - return -1; - } - - errno = 0; - dv = strtod(val, &eptr); - - if (*eptr) { - LM_ERR("invalid parameter string\n"); - return -2; - } - - if ( errno - || dv > (double)MAX_TIMEOUT_S - || (dv && dv < ((double)MIN_TIMEOUT_MS)/1000)) - { - LM_ERR("value must be between 0.%u and %u.0\n", - MIN_TIMEOUT_MS, MAX_TIMEOUT_S); - return -3; - } - - s = (unsigned)dv; - dv -= (double)s; - ms = (unsigned)(dv * 1000); - tv->tv_sec = (time_t)s; - tv->tv_usec = (suseconds_t)ms; - return 0; -} - - -/* - * set operation timeout - */ -int set_timeout(unsigned type, const char* val) -{ - int rc = set_tv(type, val, &request_tm); - - if (!rc) { - synch_mode = is_zero_tm(&request_tm); - if (!synch_mode && is_zero_tm(&restore_tm)) - restore_tm = defrest_tm; - } - - return rc; -} - - -/* - * set (re)connect timeout - */ -int set_reconnect(unsigned type, const char* val) -{ - int rc = set_tv(type, val, &restore_tm); - - if (!synch_mode && is_zero_tm(&restore_tm)) { - LM_WARN("in asyncronus mode reconnect time can't be zero. " - "Set default value\n"); - restore_tm = defrest_tm; - } - - return rc; -} - - -static sword change_mode(ora_con_t* con) -{ - return OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, NULL, 0, - OCI_ATTR_NONBLOCKING_MODE, con->errhp); -} - - -/* - * start timelimited operation (if work in synch mode return SUCCESS) - */ -sword begin_timelimit(ora_con_t* con, int connect) -{ - struct timeval* tv; - sword status; - - if (synch_mode) - return OCI_SUCCESS; - - if (connect || cur_asynch_mode) { - ub1 mode; - - status = OCIAttrGet(con->svchp, OCI_HTYPE_SVCCTX, &mode, NULL, - OCI_ATTR_NONBLOCKING_MODE, con->errhp); - if (status != OCI_SUCCESS) - return status; - - if (mode) { - status = change_mode(con); - if (status != OCI_SUCCESS) - return status; - } - cur_asynch_mode = 0; - } - - status = change_mode(con); - if (status != OCI_SUCCESS && connect >= 0) - return status; - - cur_asynch_mode = 1; - - gettimeofday(&wtm, NULL); - tv = &request_tm; - if (connect) - tv = &restore_tm; - wtm.tv_sec += tv->tv_sec; - wtm.tv_usec += tv->tv_usec; - if (wtm.tv_usec >= 1000000) { - wtm.tv_usec -= 1000000; - ++wtm.tv_sec; - } - - return OCI_SUCCESS; -} - - -static sword remap_status(ora_con_t* con, sword status) -{ - sword code; - - if ( status == OCI_ERROR - && OCIErrorGet(con->errhp, 1, NULL, &code, - NULL, 0, OCI_HTYPE_ERROR) == OCI_SUCCESS - && (code == 3123 /*|| code == 3127*/)) - { - status = OCI_STILL_EXECUTING; - } - return status; -} - - -/* - * check completion of timelimited operation (if work in synch mode return 0) - */ -int wait_timelimit(ora_con_t* con, sword status) -{ - struct timeval cur; - - if (!cur_asynch_mode) - return 0; - - if (remap_status(con, status) != OCI_STILL_EXECUTING) - return 0; - - gettimeofday(&cur, NULL); - return ( cur.tv_sec < wtm.tv_sec - || (cur.tv_sec == wtm.tv_sec && cur.tv_usec < wtm.tv_usec)); -} - - -/* - * close current timelimited operation and disconnect if timeout occured - * return true only if work in asynch mode and timeout detect - */ -int done_timelimit(ora_con_t* con, sword status) -{ - int ret = 0; - - if (!cur_asynch_mode) - return 0; - - if (remap_status(con, status) == OCI_STILL_EXECUTING) { - sword code; - - status = OCIBreak(con->svchp, con->errhp); - if (status != OCI_SUCCESS) - LM_ERR("driver: %s\n", - db_oracle_error(con, status)); - - status = OCIReset(con->svchp, con->errhp); - if ( status == OCI_ERROR - && OCIErrorGet(con->errhp, 1, NULL, &code, - NULL, 0, OCI_HTYPE_ERROR) == OCI_SUCCESS - && code == 1013) - { - status = OCI_SUCCESS; - } - if (status != OCI_SUCCESS) - LM_ERR("driver: %s\n", - db_oracle_error(con, status)); - db_oracle_disconnect(con); - ++ret; - } else { - status = change_mode(con); - if (status != OCI_SUCCESS) { - LM_ERR("driver: %s\n", db_oracle_error(con, status)); - ++ret; - } else { - cur_asynch_mode = 0; - } - } - return ret; -} diff --git a/modules/db_oracle/asynch.h b/modules/db_oracle/asynch.h deleted file mode 100644 index 9694088..0000000 --- a/modules/db_oracle/asynch.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * $Id$ - * - * Oracle module interface - * - * Copyright (C) 2007,2008 TRUNK MOBILE - * - * This file is part of opensips, a free SIP server. - * - * opensips is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version - * - * opensips is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * History: - * -------- - */ - -#ifndef ASYNCH_H -#define ASYNCH_H - -#include -#include "ora_con.h" - - -/* - * parse timeout value for operation in syntax: nnn.mmm (sec/ms) - */ -int set_timeout(unsigned type, const char* val); - -/* - * parse timeout value for reconnect in syntax: nnn.mmm (sec/ms) - */ -int set_reconnect(unsigned type, const char* val); - - -/* - * start timelimited operation (if work in synch mode return SUCCESS) - */ -sword begin_timelimit(ora_con_t* con, int connect); - -/* - * check completion of timelimited operation (if work in synch mode return 0) - */ -int wait_timelimit(ora_con_t* con, sword status); - -/* - * close current timelimited operation and disconnect if timeout occured - * return true only if work in asynch mode and timeout detect - */ -int done_timelimit(ora_con_t* con, sword status); - -#endif /* ASYNCH_H */ diff --git a/modules/db_oracle/db_oracle.c b/modules/db_oracle/db_oracle.c index 70cfe40..40c7692 100644 --- a/modules/db_oracle/db_oracle.c +++ b/modules/db_oracle/db_oracle.c @@ -31,7 +31,7 @@ #include "../../sr_module.h" #include "../../db/db.h" #include "dbase.h" -#include "asynch.h" +#include "timer.h" static int oracle_mod_init(void); static void destroy(void); diff --git a/modules/db_oracle/dbase.c b/modules/db_oracle/dbase.c index d129e11..be2352e 100644 --- a/modules/db_oracle/dbase.c +++ b/modules/db_oracle/dbase.c @@ -36,7 +36,7 @@ #include "val.h" #include "ora_con.h" #include "res.h" -#include "asynch.h" +#include "timer.h" #include "dbase.h" @@ -212,7 +212,6 @@ static int db_oracle_submit_query(const db_con_t* _h, const str* _s) OCIDate odt[sizeof(bind)/sizeof(bind[0])]; str tmps; sword status; - int pass; ora_con_t* con = CON_ORA(_h); query_data_t* pqd = con->pqdata; size_t hc = pqd->_n + pqd->_nw; @@ -223,32 +222,16 @@ static int db_oracle_submit_query(const db_con_t* _h, const str* _s) (unsigned)hc); return -1; } - - if (!pqd->_rs) { - /* - * This method is at ~25% faster as set OCI_COMMIT_ON_SUCCESS - * in StmtExecute - */ - tmps.len = snprintf(st_buf, sizeof(st_buf), - "begin %.*s; commit write batch nowait; end;", - _s->len, _s->s); - if ((unsigned)tmps.len >= sizeof(st_buf)) - return sql_buf_small(); - tmps.s = st_buf; - _s = &tmps; - } - pass = 1; - if (!con->connected) { + if (con->connected != 2) { status = db_oracle_reconnect(con); if (status != OCI_SUCCESS) { LM_ERR("can't restore connection: %s\n", db_oracle_error(con, status)); return -2; } LM_INFO("connection restored\n"); - --pass; } -repeat: + stmthp = NULL; status = OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&stmthp, OCI_HTYPE_STMT, 0, NULL); @@ -291,14 +274,10 @@ bind_err: } } - // timelimited operation - status = begin_timelimit(con, 0); - if (status != OCI_SUCCESS) goto ora_err; - do status = OCIStmtExecute(con->svchp, stmthp, con->errhp, - !pqd->_rs, 0, NULL, NULL, - pqd->_rs ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT); - while (wait_timelimit(con, status)); - if (done_timelimit(con, status)) goto stop_exec; + request_timer(); + status = OCIStmtExecute(con->svchp, stmthp, con->errhp, + !pqd->_rs, 0, NULL, NULL, pqd->_rs ? OCI_DEFAULT : OCI_COMMIT_ON_SUCCESS); + timer_stop(); switch (status) { case OCI_SUCCESS_WITH_INFO: LM_WARN("driver: %s\n", db_oracle_errorinfo(con)); @@ -310,8 +289,8 @@ bind_err: OCIHandleFree(stmthp, OCI_HTYPE_STMT); return 0; default: - pass = -pass; - break; + LM_ERR("timeout/not connected to oracle\n"); + break; } ora_err: @@ -319,15 +298,13 @@ ora_err: stop_exec: if (stmthp) OCIHandleFree(stmthp, OCI_HTYPE_STMT); - if (pass == -1 && !con->connected) { - /* Attemtp to reconnect */ - if (db_oracle_reconnect(con) == OCI_SUCCESS) { - LM_NOTICE("attempt repeat after reconnect\n"); - pass = 0; - goto repeat; - } + LM_INFO("reconnecting to oracle...\n"); + /* Attempt to reconnect */ + if (db_oracle_reconnect(con) == OCI_SUCCESS) + LM_INFO("connection restored\n"); + else LM_ERR("connection loss\n"); - } + return -4; } diff --git a/modules/db_oracle/ora_con.c b/modules/db_oracle/ora_con.c index 73ced27..f03f753 100644 --- a/modules/db_oracle/ora_con.c +++ b/modules/db_oracle/ora_con.c @@ -22,9 +22,10 @@ #include #include +#include #include "../../mem/mem.h" #include "../../dprint.h" -#include "asynch.h" +#include "timer.h" #include "ora_con.h" /*************************************************************************/ @@ -105,6 +106,12 @@ bad_param: status = OCIAttrSet(con->svchp, OCI_HTYPE_SVCCTX, con->authp, 0, OCI_ATTR_SESSION, con->errhp); if (status != OCI_SUCCESS) goto connect_err; + + if (init_ora_timer(con) != 0) { + LM_ERR("can't start oracle timer thread\n"); + goto drop_connection; + } + status = db_oracle_reconnect(con); if (status != OCI_SUCCESS) { connect_err: @@ -122,12 +129,11 @@ drop_connection: } // timelimited operation - status = begin_timelimit(con, 0); - if (status != OCI_SUCCESS) goto connect_err; - do status = OCIServerVersion(con->svchp, con->errhp, (OraText*)buf, + request_timer(); + status = OCIServerVersion(con->svchp, con->errhp, (OraText*)buf, (ub4)sizeof(buf), OCI_HTYPE_SVCCTX); - while (wait_timelimit(con, status)); - if (done_timelimit(con, status)) goto drop_connection; + timer_stop(); + if (status != OCI_SUCCESS) goto connect_err; LM_INFO("server version is %s\n", buf); return con; @@ -139,6 +145,7 @@ drop_connection: */ void db_oracle_free_connection(ora_con_t* con) { + destroy_ora_timer(con); if (!con) return; if (con->connected) @@ -164,20 +171,17 @@ void db_oracle_free_connection(ora_con_t* con) void db_oracle_disconnect(ora_con_t* con) { sword status; - - switch (con->connected) { - default: - status = OCISessionEnd(con->svchp, con->errhp, con->authp, - OCI_DEFAULT); - if (status != OCI_SUCCESS) - LM_ERR("driver: %s\n", db_oracle_error(con, status)); - case 1: + if (con->connected > 0) { + if (con->connected > 1) { + status = OCISessionEnd(con->svchp, con->errhp, con->authp, + OCI_DEFAULT); + if (status != OCI_SUCCESS) + LM_ERR("driver: %s\n", db_oracle_error(con, status)); + } status = OCIServerDetach(con->srvhp, con->errhp, OCI_DEFAULT); if (status != OCI_SUCCESS) LM_ERR("driver: %s\n", db_oracle_error(con, status)); con->connected = 0; - case 0: - break; } } @@ -192,48 +196,19 @@ sword db_oracle_reconnect(ora_con_t* con) if (con->connected) db_oracle_disconnect(con); - /* timelimited operation, but OCI tcp-network does not support it :( */ + restore_timer(); status = OCIServerAttach(con->srvhp, con->errhp, (OraText*)con->uri, con->uri_len, 0); + timer_stop(); if (status == OCI_SUCCESS) { ++con->connected; - /* - * timelimited operation, but OCI has BUG in asynch - * implementation of OCISessionBegin :(. - * - * Next code is 'empiric hack' that work (tested) in v10/v11. - */ - status = begin_timelimit(con, 1); - if (status != OCI_SUCCESS) goto done; + request_timer(); status = OCISessionBegin(con->svchp, con->errhp, con->authp, OCI_CRED_RDBMS, OCI_DEFAULT); - while (wait_timelimit(con, status)) { - sword code; - - status = OCIServerVersion(con->svchp, con->errhp, NULL, - 0, OCI_HTYPE_SVCCTX); - - if ( status != OCI_ERROR - || OCIErrorGet(con->errhp, 1, NULL, &code, NULL, 0, - OCI_HTYPE_ERROR) != OCI_SUCCESS) break; - switch (code) { - case 24909: /* other call in progress */ - status = OCI_STILL_EXECUTING; - continue; - - case 3127: /* no new operation until active ends */ - status = OCISessionBegin(con->svchp, con->errhp, - con->authp, OCI_CRED_RDBMS, OCI_DEFAULT); - default: - break; - } - break; - } - if (done_timelimit(con, status)) goto done; + timer_stop(); if (status == OCI_SUCCESS) ++con->connected; } -done: return status; } diff --git a/modules/db_oracle/ora_con.h b/modules/db_oracle/ora_con.h index 5835ffe..7267bee 100644 --- a/modules/db_oracle/ora_con.h +++ b/modules/db_oracle/ora_con.h @@ -50,7 +50,8 @@ struct ora_con { int connected; /* Authorized session started */ int bindpos; /* Last Bind handle position */ - + pthread_t timer; + query_data_t* pqdata; /* Temporary: cb data for submit_query/store_result */ int uri_len; diff --git a/modules/db_oracle/res.c b/modules/db_oracle/res.c index e9e6233..2c625f8 100644 --- a/modules/db_oracle/res.c +++ b/modules/db_oracle/res.c @@ -32,7 +32,7 @@ #include "../../dprint.h" #include "ora_con.h" #include "dbase.h" -#include "asynch.h" +#include "timer.h" #include "res.h" @@ -54,6 +54,10 @@ struct dmap { }; typedef struct dmap dmap_t; +typedef struct ora_row { + struct db_row hdr; + struct ora_row* next; +} ora_row_t; /* * Get and convert columns from a result. Define handlers and buffers @@ -362,66 +366,74 @@ static int convert_row(db_res_t* _res, db_row_t* _r, dmap_t* _d) */ static int get_rows(ora_con_t* con, db_res_t* _r, OCIStmt* _c, dmap_t* _d) { - ub4 rcnt; + ub4 i = 0, rcnt = 0; sword status; unsigned n = RES_COL_N(_r); - + // Since OCI have not "mysql_num_rows()", sequentialy fetch all rows into tmp area orow_list. + // Then call db_allocate_rows() and copy tmp to db module. + ora_row_t *orow_list = NULL, *orow_it, *orow_tail; + memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n); - - // timelimited operation - status = begin_timelimit(con, 0); - if (status != OCI_SUCCESS) goto ora_err; - do status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_NEXT, 0, - OCI_DEFAULT); - while (wait_timelimit(con, status)); - if (done_timelimit(con, status)) goto stop_load; - if (status != OCI_SUCCESS) { - if (status != OCI_NO_DATA) - goto ora_err; - - RES_ROW_N(_r) = 0; - RES_ROWS(_r) = NULL; - return 0; - } - - status = OCIAttrGet(_c, OCI_HTYPE_STMT, &rcnt, NULL, - OCI_ATTR_CURRENT_POSITION, con->errhp); - if (status != OCI_SUCCESS) goto ora_err; - if (!rcnt) { - LM_ERR("lastpos==0\n"); - goto stop_load; + + request_timer(); + while ((status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_NEXT, 0, + OCI_DEFAULT)) == OCI_SUCCESS) { + timer_stop(); + + orow_it = (ora_row_t*) pkg_malloc(sizeof(ora_row_t) + sizeof(db_val_t)*RES_COL_N(_r)); + if (orow_it == NULL) { + LM_ERR("no private memory left\n"); + goto stop_load; + } + memset(orow_it, 0, sizeof(ora_row_t) + sizeof(db_val_t)*RES_COL_N(_r)); + orow_it->hdr.values = (db_val_t*)(orow_it+1); + + if (orow_list == NULL) + orow_list = orow_it; + else + orow_tail->next = orow_it; + orow_tail = orow_it; + + if (convert_row(_r, &orow_it->hdr, _d) < 0) { + LM_ERR("erroc convert row\n"); + goto stop_load; + } + memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n); + ++rcnt; + request_timer(); } - + timer_stop(); + if (status != OCI_NO_DATA) + goto ora_err; + RES_ROW_N(_r) = rcnt; if (db_allocate_rows( _r, rcnt)!=0) { LM_ERR("no private memory left\n"); - return -1; + goto stop_load; } - - while ( 1 ) { - if (convert_row(_r, &RES_ROWS(_r)[--rcnt], _d) < 0) { - LM_ERR("error convert row\n"); - goto stop_load; - } - - if (!rcnt) - return 0; - - memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n); - // timelimited operation - status = begin_timelimit(con, 0); - if (status != OCI_SUCCESS) goto ora_err; - do status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_PRIOR, 0, - OCI_DEFAULT); - while (wait_timelimit(con, status)); - if (done_timelimit(con, status)) goto stop_load; - if (status != OCI_SUCCESS) break; + + for (orow_it = orow_list; orow_it; orow_it = orow_it->next) { + memcpy(ROW_VALUES(&RES_ROWS(_r)[i]), ROW_VALUES(&orow_it->hdr), sizeof(db_val_t)*RES_COL_N(_r)); + ROW_N(&RES_ROWS(_r)[i]) = ROW_N(&orow_it->hdr); + ++i; + } + + for (orow_it = orow_list; orow_it; orow_it = orow_list) { + orow_list = orow_it->next; + pkg_free(orow_it); + orow_it = NULL; } + return 0; + ora_err: LM_ERR("driver: %s\n", db_oracle_error(con, status)); stop_load: - db_free_rows(_r); - RES_ROW_N(_r) = 0; /* TODO: skipped in db_res.c :) */ + for (orow_it = orow_list; orow_it; orow_it = orow_list) { + orow_list = orow_it->next; + db_free_row(&orow_it->hdr); + pkg_free(orow_it); + orow_it = NULL; + } return -3; } diff --git a/modules/db_oracle/timer.c b/modules/db_oracle/timer.c new file mode 100644 index 0000000..50484f4 --- /dev/null +++ b/modules/db_oracle/timer.c @@ -0,0 +1,131 @@ +#include "timer.h" +#include "../../dprint.h" +#include "../../sr_module.h" + +#include +#include +#include +#include + +#define MAX_TIMEOUT_S 10 +#define MIN_TIMEOUT_MCS 100000 + +/* Default is 3.0 second */ +struct itimerval request_tm = {{0,0}, {3,0}}; +// unsigned request_tm; + +/* Default is 0.2 second */ +struct itimerval restore_tm = {{0,0}, {0,200000}}; + +struct itimerval stop_tm = {{0,0}, {0,0}}; + +/* Simple error handling functions */ + +#define handle_error_en(en, msg) \ + do { LM_ERR(msg": %s\n", strerror(en)); return 1; } while (0) + +static ora_con_t *g_con; + +static int set_tv(unsigned type, const char* val, struct timeval* tv) +{ + char *eptr; + struct itimerval tt; + unsigned long s, ms; + double dv; + + if (type != STR_PARAM) { + LM_ERR("type of parameter is no STR\n"); + return -1; + } + + if (!val || !*val) { + LM_ERR("empty parameter\n"); + return -1; + } + + errno = 0; + dv = strtod(val, &eptr); + + if (*eptr) { + LM_ERR("invalid parameter string\n"); + return -2; + } + + if ( errno + || dv > (double)MAX_TIMEOUT_S + || (dv < ((double)MIN_TIMEOUT_MCS)/100000)) + { + LM_ERR("value must be between 0.%.6u and %u.0\n", + MIN_TIMEOUT_MCS, MAX_TIMEOUT_S); + return -3; + } + + s = (unsigned)dv; + dv -= (double)s; + ms = (unsigned)(dv * 1000000); + tv->tv_sec = (time_t)s; + tv->tv_usec = (suseconds_t)ms; + return 0; +} + + +/* + * set operation timeout + */ +int set_timeout(unsigned type, const char* val) +{ + return set_tv(type, val, &request_tm.it_value); +} + + +/* + * set (re)connect timeout + */ +int set_reconnect(unsigned type, const char* val) +{ + return set_tv(type, val, &restore_tm.it_value); +} + +void ora_alarm_handle(int sig) { + LM_INFO("ora_alarm_handle\n"); + sword status; + status = OCIBreak(g_con->svchp, g_con->errhp); + if (status != OCI_SUCCESS) { + LM_ERR("OCIBreak: %s\n", db_oracle_error(g_con, status)); + } +} + +int init_ora_timer(ora_con_t* con) { + g_con = con; + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = ora_alarm_handle; + if (sigaction(SIGALRM, &sa, NULL) < -1) + handle_error_en(errno, "sigaction"); + + return 0; +} + +int destroy_ora_timer() +{ + timer_stop(); +} + +void request_timer() +{ + if (setitimer(ITIMER_REAL, &request_tm, NULL) < 0) + LM_ERR("setitimer: %s\n", strerror(errno)); +} + +void restore_timer() +{ + if (setitimer(ITIMER_REAL, &restore_tm, NULL) < 0) + LM_ERR("setitimer: %s\n", strerror(errno)); +} + +void timer_stop() +{ + if (setitimer(ITIMER_REAL, &stop_tm, NULL) < 0) + LM_ERR("setitimer: %s\n", strerror(errno)); +} + \ No newline at end of file diff --git a/modules/db_oracle/timer.h b/modules/db_oracle/timer.h new file mode 100644 index 0000000..24aa4a9 --- /dev/null +++ b/modules/db_oracle/timer.h @@ -0,0 +1,22 @@ +#ifndef ORA_TIMER_H +#define ORA_TIMER_H + +#include "ora_con.h" + +/* + * parse timeout value for operation in syntax: nnn.mmm (sec/ms) + */ +int set_timeout(unsigned type, const char* val); + +/* + * parse timeout value for reconnect in syntax: nnn.mmm (sec/ms) + */ +int set_reconnect(unsigned type, const char* val); + +int init_ora_timer(ora_con_t* con); +int destroy_ora_timer(); + +void request_timer(); +void restore_timer(); +void timer_stop(); +#endif // ORA_TIMER_H \ No newline at end of file