From 1352777b98595914b1f4c4981acc3149b98caff7 Mon Sep 17 00:00:00 2001
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?= <samusenko@msm.ru>
Date: Mon, 25 Jun 2012 17:54:27 +0400
Subject: [PATCH 3/8] Removed all async Oracle operations - they didn't work
well anyway
---
modules/db_oracle/asynch.c | 270 ------------------------------------------
modules/db_oracle/asynch.h | 62 ----------
modules/db_oracle/db_oracle.c | 2 +-
modules/db_oracle/dbase.c | 53 +++------
modules/db_oracle/ora_con.c | 73 ++++--------
modules/db_oracle/ora_con.h | 3 +-
modules/db_oracle/res.c | 110 +++++++++--------
modules/db_oracle/timer.c | 131 ++++++++++++++++++++
modules/db_oracle/timer.h | 22 ++++
9 files changed, 256 insertions(+), 470 deletions(-)
delete mode 100644 modules/db_oracle/asynch.c
delete mode 100644 modules/db_oracle/asynch.h
create mode 100644 modules/db_oracle/timer.c
create mode 100644 modules/db_oracle/timer.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 <string.h>
#include <stdio.h>
+#include <errno.h>
#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 <signal.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#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
--
1.8.3.1