mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-10-31 15:57:31 +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