pg_send_query():无法设置阻塞模式的连接?

Fra*_*mer 12 php postgresql

我有一个长时间运行的脚本,似乎偶尔会报告以下NOTICE级错误:pg_send_query():无法设置连接到阻塞模式

它似乎继续发送查询,但不清楚它是否成功发送生成错误的查询.

这是什么症状?

编辑:错误发生时postgres日志中没有条目,这表明这只是一个连接错误,而不是postgres方面出错(例如可能不是postgres崩溃和重启的结果)

编辑:据我所知,当触发此错误时,我的INSERT语句会以某种方式成功.

编辑:看起来这可能已于2013年6月修复:https://bugs.php.net/bug.php?id = 65015

Hen*_*pel 24

这是pg_send_query()无法将连接成功切换回阻止模式的症状.查看PHPs pgsql.c中的源代码,您可以找到:

/* {{{ proto bool pg_send_query(resource connection, string query)
   Send asynchronous query */
PHP_FUNCTION(pg_send_query)
{

<... snipped function setup stuff ...>

 if (PQ_SETNONBLOCKING(pgsql, 1)) {
  php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to nonblocking mode");
  RETURN_FALSE;
 }

<... snipped main function execution stuff ...>

 if (PQ_SETNONBLOCKING(pgsql, 0)) {
  php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Cannot set connection to blocking mode");
 }
 RETURN_TRUE;
}
Run Code Online (Sandbox Code Playgroud)

因此,在主要工作完成后,在函数结束时会引发错误.这符合您的INSERT语句执行的观察结果.

这两个PQ_SETNONBLOCKING调用的全部目的是将连接置于非阻塞模式以允许异步执行,然后将其恢复为默认阻塞行为.从PQsetnonblocking文档 :( PQ_SETNONBLOCKING只是为该函数定义的别名):

设置连接的非阻塞状态.

int PQsetnonblocking(PGconn *conn, int arg);
Run Code Online (Sandbox Code Playgroud)

如果arg为1,则将连接的状态设置为非阻塞;如果arg为0,则设置阻塞.如果OK则返回0,如果错误则返回-1.

在非阻塞状态下,对PQsendQuery,PQputline,PQputnbytes和PQendcopy的调用不会阻塞,而是在需要再次调用时返回错误.

请注意,PQexec不支持非阻塞模式; 如果它被调用,它无论如何都将以阻止方式行事.

进一步研究PQsetnonblocking的来源(在PostgeSQLs fe-exec.c中),有两个可能的原因导致调用失败:

/* PQsetnonblocking:
 * sets the PGconn's database connection non-blocking if the arg is TRUE
 * or makes it non-blocking if the arg is FALSE, this will not protect
 * you from PQexec(), you'll only be safe when using the non-blocking API.
 * Needs to be called only on a connected database connection.
 */
int
PQsetnonblocking(PGconn *conn, int arg)
{
 bool  barg;

 if (!conn || conn->status == CONNECTION_BAD)
  return -1;

 barg = (arg ? TRUE : FALSE);

 /* early out if the socket is already in the state requested */
 if (barg == conn->nonblocking)
  return 0;

 /*
  * to guarantee constancy for flushing/query/result-polling behavior we
  * need to flush the send queue at this point in order to guarantee proper
  * behavior. this is ok because either they are making a transition _from_
  * or _to_ blocking mode, either way we can block them.
  */
 /* if we are going from blocking to non-blocking flush here */
 if (pqFlush(conn))
  return -1;

 conn->nonblocking = barg;

 return 0;
}
Run Code Online (Sandbox Code Playgroud)

所以要么连接以某种方式丢失,要么pqFlush没有成功完成,表明连接输出缓冲区中剩余的东西.

第一种情况是无害的,因为您的脚本肯定会注意到以后调用丢失的连接并对此作出反应(或者更明显地失败).

这留下了第二种情况,这意味着您在非默认的非阻塞状态下有连接.我不知道这是否会影响以后会重用此连接的调用.如果你想安全地玩它,你可以在这种情况下关闭连接并使用新的/另一个.

  • +1用于识别真实原因并提供实际建议.做得好! (4认同)
  • 如果你遇到这个问题并且没有尝试使用`pg_pconnect()`,可能的原因是PHP错误:https://bugs.php.net/bug.php?id = 65015 (2认同)