mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-01-31 09:24:07 +03:00
Added wait callback and functions to deal with it.
This commit is contained in:
parent
02a28ff028
commit
1446f046e9
|
@ -60,6 +60,11 @@ from _psycopg import ISQLQuote
|
||||||
|
|
||||||
from _psycopg import QueryCanceledError, TransactionRollbackError
|
from _psycopg import QueryCanceledError, TransactionRollbackError
|
||||||
|
|
||||||
|
try:
|
||||||
|
from _psycopg import set_wait_callback
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
"""Isolation level values."""
|
"""Isolation level values."""
|
||||||
ISOLATION_LEVEL_AUTOCOMMIT = 0
|
ISOLATION_LEVEL_AUTOCOMMIT = 0
|
||||||
ISOLATION_LEVEL_READ_COMMITTED = 1
|
ISOLATION_LEVEL_READ_COMMITTED = 1
|
||||||
|
@ -83,6 +88,7 @@ STATUS_IN_TRANSACTION = STATUS_BEGIN
|
||||||
POLL_OK = 0
|
POLL_OK = 0
|
||||||
POLL_READ = 1
|
POLL_READ = 1
|
||||||
POLL_WRITE = 2
|
POLL_WRITE = 2
|
||||||
|
POLL_ERROR = 3
|
||||||
|
|
||||||
"""Backend transaction status values."""
|
"""Backend transaction status values."""
|
||||||
TRANSACTION_STATUS_IDLE = 0
|
TRANSACTION_STATUS_IDLE = 0
|
||||||
|
|
|
@ -484,4 +484,28 @@ def register_tstz_w_secs(oids=None, conn_or_curs=None):
|
||||||
return _ext.TSTZ_W_SECS
|
return _ext.TSTZ_W_SECS
|
||||||
|
|
||||||
|
|
||||||
|
import select
|
||||||
|
from psycopg2.extensions import POLL_OK, POLL_READ, POLL_WRITE
|
||||||
|
from psycopg2 import OperationalError
|
||||||
|
|
||||||
|
def wait_select(conn, curs=None):
|
||||||
|
"""Wait until a connection or cursor has data available.
|
||||||
|
|
||||||
|
The function is an example of a wait callback to be registered with
|
||||||
|
`~psycopg2.extensions.set_wait_callback()`. This function uses `!select()`
|
||||||
|
to wait for data available.
|
||||||
|
"""
|
||||||
|
poll = (curs or conn).poll
|
||||||
|
while 1:
|
||||||
|
state = poll()
|
||||||
|
if state == POLL_OK:
|
||||||
|
break
|
||||||
|
elif state == POLL_READ:
|
||||||
|
select.select([conn.fileno()], [], [])
|
||||||
|
elif state == POLL_WRITE:
|
||||||
|
select.select([], [conn.fileno()], [])
|
||||||
|
else:
|
||||||
|
raise OperationalError("bad state from poll: %s" % state)
|
||||||
|
|
||||||
|
|
||||||
__all__ = filter(lambda k: not k.startswith('_'), locals().keys())
|
__all__ = filter(lambda k: not k.startswith('_'), locals().keys())
|
||||||
|
|
94
psycopg/green.c
Normal file
94
psycopg/green.c
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/* green.c - cooperation with coroutine libraries.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Daniele Varrazzo <daniele.varrazzo@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of psycopg.
|
||||||
|
*
|
||||||
|
* psycopg2 is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link this program with the OpenSSL library (or with
|
||||||
|
* modified versions of OpenSSL that use the same license as OpenSSL),
|
||||||
|
* and distribute linked combinations including the two.
|
||||||
|
*
|
||||||
|
* You must obey the GNU Lesser General Public License in all respects for
|
||||||
|
* all of the code used other than OpenSSL.
|
||||||
|
*
|
||||||
|
* psycopg2 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 Lesser General Public
|
||||||
|
* License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PSYCOPG_MODULE
|
||||||
|
#include "psycopg/config.h"
|
||||||
|
#include "psycopg/python.h"
|
||||||
|
#include "psycopg/psycopg.h"
|
||||||
|
#include "psycopg/green.h"
|
||||||
|
|
||||||
|
HIDDEN PyObject *wait_callback = NULL;
|
||||||
|
|
||||||
|
/* Register a callback function to block waiting for data.
|
||||||
|
*
|
||||||
|
* The function is exported by the _psycopg module.
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psyco_set_wait_callback(PyObject *self, PyObject *obj)
|
||||||
|
{
|
||||||
|
Py_XDECREF(wait_callback);
|
||||||
|
|
||||||
|
if (obj != Py_None) {
|
||||||
|
wait_callback = obj;
|
||||||
|
Py_INCREF(obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wait_callback = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return nonzero if a wait callback should be called. */
|
||||||
|
int
|
||||||
|
psyco_green()
|
||||||
|
{
|
||||||
|
#ifdef PSYCOPG_EXTENSIONS
|
||||||
|
return (NULL != wait_callback);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Block waiting for data available in an async connection.
|
||||||
|
*
|
||||||
|
* This function assumes `wait_callback` to be available:
|
||||||
|
* raise `InterfaceError` if it is not. Use `psyco_green()` to check if
|
||||||
|
* the function is to be called.
|
||||||
|
*
|
||||||
|
* The function returns the return value of the called function.
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psyco_wait(PyObject *conn, PyObject *curs)
|
||||||
|
{
|
||||||
|
PyObject *rv;
|
||||||
|
PyObject *cb;
|
||||||
|
|
||||||
|
Dprintf("psyco_wait");
|
||||||
|
cb = wait_callback;
|
||||||
|
if (!cb) {
|
||||||
|
PyErr_SetString(OperationalError, "wait callback not available");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_INCREF(cb);
|
||||||
|
rv = PyObject_CallFunctionObjArgs(cb, conn, curs, NULL);
|
||||||
|
Py_DECREF(cb);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
58
psycopg/green.h
Normal file
58
psycopg/green.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/* green.c - cooperation with coroutine libraries.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Daniele Varrazzo <daniele.varrazzo@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of psycopg.
|
||||||
|
*
|
||||||
|
* psycopg2 is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link this program with the OpenSSL library (or with
|
||||||
|
* modified versions of OpenSSL that use the same license as OpenSSL),
|
||||||
|
* and distribute linked combinations including the two.
|
||||||
|
*
|
||||||
|
* You must obey the GNU Lesser General Public License in all respects for
|
||||||
|
* all of the code used other than OpenSSL.
|
||||||
|
*
|
||||||
|
* psycopg2 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 Lesser General Public
|
||||||
|
* License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PSYCOPG_GREEN_H
|
||||||
|
#define PSYCOPG_GREEN_H 1
|
||||||
|
|
||||||
|
struct PyObject;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define psyco_set_wait_callback_doc \
|
||||||
|
"set_wait_callback(f) -- Register a callback function to block waiting for data.\n" \
|
||||||
|
"\n" \
|
||||||
|
"The callback must should signature :samp:`fun({conn}, {cur}=None)` and\n" \
|
||||||
|
"is called to wait for data available whenever a blocking function from the\n" \
|
||||||
|
"libpq is called. Use `!register_wait_function(None)` to revert to the\n" \
|
||||||
|
"original behaviour (using blocking libpq functions).\n" \
|
||||||
|
"\n" \
|
||||||
|
"The function is an hook to allow coroutine-based libraries (such as\n" \
|
||||||
|
"eventlet_ or gevent_) to switch when Psycopg is blocked, allowing\n" \
|
||||||
|
"other coroutines to run concurrently.\n" \
|
||||||
|
"\n" \
|
||||||
|
"See `~psycopg2.extras.wait_select()` for an example of a wait callback\n" \
|
||||||
|
"implementation.\n"
|
||||||
|
|
||||||
|
HIDDEN PyObject *psyco_set_wait_callback(PyObject *self, PyObject *obj);
|
||||||
|
HIDDEN int psyco_green(void);
|
||||||
|
HIDDEN PyObject *psyco_wait(PyObject *conn, PyObject *curs);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined(PSYCOPG_GREEN_H) */
|
|
@ -32,6 +32,7 @@
|
||||||
#include "psycopg/psycopg.h"
|
#include "psycopg/psycopg.h"
|
||||||
#include "psycopg/connection.h"
|
#include "psycopg/connection.h"
|
||||||
#include "psycopg/cursor.h"
|
#include "psycopg/cursor.h"
|
||||||
|
#include "psycopg/green.h"
|
||||||
#include "psycopg/lobject.h"
|
#include "psycopg/lobject.h"
|
||||||
#include "psycopg/typecast.h"
|
#include "psycopg/typecast.h"
|
||||||
#include "psycopg/microprotocols.h"
|
#include "psycopg/microprotocols.h"
|
||||||
|
@ -693,6 +694,11 @@ static PyMethodDef psycopgMethods[] = {
|
||||||
METH_VARARGS, psyco_IntervalFromMx_doc},
|
METH_VARARGS, psyco_IntervalFromMx_doc},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PSYCOPG_EXTENSIONS
|
||||||
|
{"set_wait_callback", (PyCFunction)psyco_set_wait_callback,
|
||||||
|
METH_O, psyco_set_wait_callback_doc},
|
||||||
|
#endif
|
||||||
|
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -343,7 +343,7 @@ sources = [
|
||||||
'adapter_qstring.c', 'adapter_pboolean.c', 'adapter_binary.c',
|
'adapter_qstring.c', 'adapter_pboolean.c', 'adapter_binary.c',
|
||||||
'adapter_asis.c', 'adapter_list.c', 'adapter_datetime.c',
|
'adapter_asis.c', 'adapter_list.c', 'adapter_datetime.c',
|
||||||
'adapter_pfloat.c', 'adapter_pdecimal.c',
|
'adapter_pfloat.c', 'adapter_pdecimal.c',
|
||||||
'utils.c']
|
'green.c', 'utils.c']
|
||||||
|
|
||||||
parser = ConfigParser.ConfigParser()
|
parser = ConfigParser.ConfigParser()
|
||||||
parser.read('setup.cfg')
|
parser.read('setup.cfg')
|
||||||
|
|
Loading…
Reference in New Issue
Block a user