Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions modules/db_postgres/README
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ db_postgres Module
1.3.2. max_db_queries (integer)
1.3.3. timeout (integer)
1.3.4. use_tls (integer)
1.3.5. lazy_connect (integer)

1.4. Exported Functions
1.5. Installation and Running
Expand All @@ -43,6 +44,7 @@ db_postgres Module
1.2. Set max_db_queries parameter
1.3. Set timeout parameter
1.4. Set the use_tls parameter
1.5. Set lazy_connect parameter

Chapter 1. Admin Guide

Expand Down Expand Up @@ -165,6 +167,23 @@ modparam("usrloc", "db_url", "postgres://root:1234@localhost/opensips?tl
s_domain=dom1")
...

1.3.5. lazy_connect (integer)

If set to 1, db_init() only allocates the connection handle.
PQconnectdbParams() runs on the first query (including
PQescapeStringConn while SQL text is built) or on async
connection setup. SIP worker processes that never query
PostgreSQL therefore keep no idle backend sockets. The
db_virtual probe timer still issues SELECT 1 on a temporary
handle so a down URL is not marked up without a real connect.

Default value is 0 (connect at init, historic behaviour).

Example 1.5. Set lazy_connect parameter
...
modparam("db_postgres", "lazy_connect", 1)
...

1.4. Exported Functions

NONE
Expand Down
2 changes: 2 additions & 0 deletions modules/db_postgres/db_postgres.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ int db_postgres_exec_query_threshold = 0; /* Warning in case DB query
takes too long disabled by default*/
int max_db_queries = 2;
int pq_timeout = DEFAULT_PSQL_TIMEOUT;
int pg_lazy_connect = 0; /* Don't be lazy, connect on start */

int db_postgres_bind_api(const str* mod, db_func_t *dbb);

Expand All @@ -64,6 +65,7 @@ static const param_export_t params[] = {
{"max_db_queries", INT_PARAM, &max_db_queries},
{"timeout", INT_PARAM, &pq_timeout},
{"use_tls", INT_PARAM, &use_tls},
{"lazy_connect", INT_PARAM, &pg_lazy_connect},
{0, 0, 0}
};

Expand Down
2 changes: 2 additions & 0 deletions modules/db_postgres/db_postgres.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ extern int pq_timeout;

extern int use_tls;

extern int pg_lazy_connect;

extern struct tls_mgm_binds tls_api;

#endif /* DB_POSTGRES_H */
6 changes: 6 additions & 0 deletions modules/db_postgres/dbase.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ static int db_postgres_submit_query(const db_con_t* _con, const str* _s)
return(-1);
}

if (db_postgres_ensure_connected((struct pg_con *)_con->tail) != 0)
return -1;

submit_func_called = 1;

/* this bit of nonsense in case our connection get screwed up */
Expand Down Expand Up @@ -245,6 +248,9 @@ static int db_postgres_submit_async_query(const db_con_t* _con, const str* _s)
return(-1);
}

if (db_postgres_ensure_connected((struct pg_con *)_con->tail) != 0)
return -1;

submit_func_called = 1;

/* this bit of nonsense in case our connection get screwed up */
Expand Down
27 changes: 27 additions & 0 deletions modules/db_postgres/doc/db_postgres_admin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,33 @@ modparam("db_postgres", "use_tls", 1)
...
modparam("usrloc", "db_url", "postgres://root:1234@localhost/opensips?tls_domain=dom1")
...
</programlisting>
</example>
</section>

<section id="param_lazy_connect" xreflabel="lazy_connect">
<title><varname>lazy_connect</varname> (integer)</title>
<para>
If set to 1, the module only allocates the connection handle at
init. The PostgreSQL socket is opened on the first query
(including string escaping via PQescapeStringConn, which
runs while the SQL text is built) or when an async
connection is created. Worker processes that never query
the database therefore keep no idle backend sockets. The <emphasis>db_virtual</emphasis> probe timer still
issues <emphasis>SELECT 1</emphasis> on a temporary handle so a
down URL is not marked up without a real connect.
</para>
<para>
<emphasis>
Default value is 0 (connect at init).
</emphasis>
</para>
<example>
<title>Set <varname>lazy_connect</varname> parameter</title>
<programlisting format="linespecific">
...
modparam("db_postgres", "lazy_connect", 1)
...
</programlisting>
</example>
</section>
Expand Down
34 changes: 32 additions & 2 deletions modules/db_postgres/pg_con.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ int db_postgres_connect(struct pg_con* ptr)
{
LM_ERR("PQconnectdbParams: %s\n", PQerrorMessage(ptr->con));
PQfinish(ptr->con);
ptr->con = 0;
ptr->connected = 0;
return -1;
}

Expand Down Expand Up @@ -293,6 +295,12 @@ struct pg_con* db_postgres_new_connection(struct db_id* id)
ptr->ref = 1;
ptr->id = id;

if (pg_lazy_connect) {
LM_DBG("lazy_connect enabled, deferring PQconnect ptr=%p db_id=%p\n",
ptr, ptr->id);
return ptr;
}

LM_DBG("calling db_postgres_connect ptr = %p, db_id = %p\n", ptr, ptr->id);

if (db_postgres_connect(ptr)!=0) {
Expand All @@ -306,6 +314,21 @@ struct pg_con* db_postgres_new_connection(struct db_id* id)
return ptr;
}

int db_postgres_ensure_connected(struct pg_con* ptr)
{
if (!ptr) {
LM_ERR("invalid connection parameter value\n");
return -1;
}

if (ptr->con)
return 0;

LM_DBG("opening deferred postgres connection ptr=%p db_id=%p\n",
ptr, ptr->id);
return db_postgres_connect(ptr);
}

/*
* Create a new async connection structure,
* open the PostgreSQL connection and set reference count to 1
Expand All @@ -322,11 +345,18 @@ struct pg_con* db_postgres_new_async_connection(struct db_id* id)
}

ptr = db_postgres_new_connection(id);
if (!ptr)
return 0;

if (ptr) {
PQsetnonblocking(ptr->con, 1);
/* async queries need a live socket even when lazy_connect is set */
if (db_postgres_ensure_connected(ptr) != 0) {
LM_ERR("async connect failed, cleaning up %p=pkg_free()\n", ptr);
pkg_free(ptr);
return 0;
}

PQsetnonblocking(ptr->con, 1);

return ptr;
}

Expand Down
3 changes: 3 additions & 0 deletions modules/db_postgres/pg_con.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ struct pg_con {
* Create a new connection structure,
* open the PostgreSQL connection and set reference count to 1
*/
int db_postgres_connect(struct pg_con* ptr);
int db_postgres_ensure_connected(struct pg_con* ptr);

struct pg_con* db_postgres_new_connection(struct db_id* id);

/*
Expand Down
10 changes: 10 additions & 0 deletions modules/db_postgres/val.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ int db_postgres_val2str(const db_con_t* _con, const db_val_t* _v,
return 0;
}

/* PQescapeStringConn / PQescapeByteaConn need a live PGconn.
* Query text is built (dispatcher version check, WHERE clauses)
* before submit_query(), so lazy_connect must open here. */

switch(VAL_TYPE(_v)) {
case DB_INT:
if (db_int2str(VAL_INT(_v), _s, _len) < 0) {
Expand Down Expand Up @@ -242,6 +246,8 @@ int db_postgres_val2str(const db_con_t* _con, const db_val_t* _v,
*_len, l * 2 + 3);
return -4;
} else {
if (db_postgres_ensure_connected((struct pg_con *)_con->tail) != 0)
return -4;
old_s = _s;
*_s++ = '\'';
ret = PQescapeStringConn(CON_CONNECTION(_con), _s, VAL_STRING(_v),
Expand All @@ -268,6 +274,8 @@ int db_postgres_val2str(const db_con_t* _con, const db_val_t* _v,
*_len, l * 2 + 3);
return -5;
} else {
if (db_postgres_ensure_connected((struct pg_con *)_con->tail) != 0)
return -5;
old_s = _s;
*_s++ = '\'';
ret = PQescapeStringConn(CON_CONNECTION(_con), _s, VAL_STR(_v).s,
Expand Down Expand Up @@ -303,6 +311,8 @@ int db_postgres_val2str(const db_con_t* _con, const db_val_t* _v,
*_len, l * 2 + 3);
return -7;
} else {
if (db_postgres_ensure_connected((struct pg_con *)_con->tail) != 0)
return -7;
*_s++ = '\'';
tmp_s = (char*)PQescapeByteaConn(CON_CONNECTION(_con), (unsigned char*)VAL_STRING(_v),
(size_t)l, (size_t*)&tmp_len);
Expand Down
36 changes: 30 additions & 6 deletions modules/db_virtual/db_virtual.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,31 +336,55 @@ int init_private_handles(void){
return -1;
}

static str db_virtual_probe_sql = str_init("SELECT 1");

/* Real reachability check. db_postgres lazy_connect makes init() a
* handle alloc only; this ping forces PQconnect on the probe handle.
* Do not call this from db_virtual_init() — that would open sockets
* in every SIP worker. */
static int db_virtual_ping(db_func_t *f, db_con_t *con)
{
db_res_t *res = NULL;
int rc;

if (!f || !con)
return -1;

if (!f->raw_query)
return 0;

rc = f->raw_query(con, &db_virtual_probe_sql, &res);
if (res && f->free_result)
f->free_result(con, res);
return rc;
}

static void reconnect_timer(unsigned int ticks, void *data)
{
LM_DBG("reconnect with timer\n");
int i,j;

db_con_t * con;
db_func_t * f;

for(i=0; i < global-> size; i++){
for(j=0; j < global->set_list[i].size; j++){
/* if CAN DOWN */
if(!(global->set_list[i].db_list[j].flags & CAN_USE)){
con =
global->set_list[i].db_list[j].dbf.init(
&global->set_list[i].db_list[j].db_url);
if(!con){
f = &global->set_list[i].db_list[j].dbf;
con = f->init(&global->set_list[i].db_list[j].db_url);
if(!con || db_virtual_ping(f, con) != 0){
LM_DBG("Cant reconnect on timer to db %.*s, %i\n",
global->set_list[i].db_list[j].db_url.len,
global->set_list[i].db_list[j].db_url.s,
global->set_list[i].db_list[j].flags);

if (con)
f->close(con);
}else{
LM_DBG("Can reconnect on timer to db %.*s\n",
global->set_list[i].db_list[j].db_url.len,
global->set_list[i].db_list[j].db_url.s);
global->set_list[i].db_list[j].dbf.close(con);
f->close(con);
global->set_list[i].db_list[j].flags |= CAN_USE;
}
}
Expand Down
Loading