|
1 | 1 | from itertools import cycle |
2 | | -from psycopg2.pool import ThreadedConnectionPool |
3 | 2 | from psycopg2.extras import register_hstore, register_json |
| 3 | +import psycopg2 |
4 | 4 | import threading |
5 | | -import ujson as json |
6 | | - |
7 | | - |
8 | | -class DatabaseCycleConnectionPool(object): |
9 | | - |
10 | | - """ |
11 | | - Maintains a psycopg2 ThreadedConnectionPool for each of the |
12 | | - given dbnames. When a client requests a set of connections, |
13 | | - all of those connections will come from the same database. |
14 | | - """ |
15 | | - |
16 | | - def __init__(self, min_conns_per_db, max_conns_per_db, dbnames, conn_info): |
17 | | - self._pools = [] |
18 | | - self._conns_to_pool = {} |
19 | | - |
20 | | - for dbname in dbnames: |
21 | | - pool = ThreadedConnectionPool( |
22 | | - min_conns_per_db, |
23 | | - max_conns_per_db, |
24 | | - dbname=dbname, |
25 | | - **conn_info |
26 | | - ) |
27 | | - self._pools.append(pool) |
28 | | - |
29 | | - self._pool_cycle = cycle(self._pools) |
30 | | - self._lock = threading.Lock() |
31 | | - |
32 | | - def get_conns(self, n_conns): |
33 | | - conns = [] |
34 | | - |
35 | | - try: |
36 | | - with self._lock: |
37 | | - pool_to_use = next(self._pool_cycle) |
38 | | - for _ in range(n_conns): |
39 | | - conn = pool_to_use.getconn() |
40 | | - self._conns_to_pool[id(conn)] = pool_to_use |
41 | | - conns.append(conn) |
42 | | - |
43 | | - conn.set_session(readonly=True, autocommit=True) |
44 | | - register_json(conn, loads=json.loads, globally=True) |
45 | | - register_hstore(conn, globally=True) |
46 | | - assert len(conns) == n_conns, \ |
47 | | - "Couldn't collect enough connections" |
48 | | - except: |
49 | | - if conns: |
50 | | - self.put_conns(conns) |
51 | | - conns = [] |
52 | | - raise |
53 | | - |
| 5 | +import ujson |
| 6 | + |
| 7 | + |
| 8 | +class DBAffinityConnectionsNoLimit(object): |
| 9 | + |
| 10 | + # Similar to the db affinity pool, but without keeping track of |
| 11 | + # the connections. It's the caller's responsibility to call us |
| 12 | + # back with the connection objects so that we can close them. |
| 13 | + |
| 14 | + def __init__(self, dbnames, conn_info): |
| 15 | + self.dbnames = cycle(dbnames) |
| 16 | + self.conn_info = conn_info |
| 17 | + self.conn_mapping = {} |
| 18 | + self.lock = threading.Lock() |
| 19 | + |
| 20 | + def _make_conn(self, conn_info): |
| 21 | + conn = psycopg2.connect(**conn_info) |
| 22 | + conn.set_session(readonly=True, autocommit=True) |
| 23 | + register_hstore(conn) |
| 24 | + register_json(conn, loads=ujson.loads) |
| 25 | + return conn |
| 26 | + |
| 27 | + def get_conns(self, n_conn): |
| 28 | + with self.lock: |
| 29 | + dbname = self.dbnames.next() |
| 30 | + conn_info_with_db = dict(self.conn_info, dbname=dbname) |
| 31 | + conns = [self._make_conn(conn_info_with_db) |
| 32 | + for i in range(n_conn)] |
54 | 33 | return conns |
55 | 34 |
|
56 | 35 | def put_conns(self, conns): |
57 | | - with self._lock: |
58 | | - for conn in conns: |
59 | | - pool = self._conns_to_pool.pop(id(conn), None) |
60 | | - assert pool is not None, \ |
61 | | - "Couldn't find the pool for connection" |
62 | | - pool.putconn(conn) |
| 36 | + for conn in conns: |
| 37 | + try: |
| 38 | + conn.close() |
| 39 | + except: |
| 40 | + pass |
63 | 41 |
|
64 | 42 | def closeall(self): |
65 | | - with self._lock: |
66 | | - for pool in self._pools: |
67 | | - pool.closeall() |
68 | | - self._conns_to_pool.clear() |
| 43 | + raise Exception('DBAffinityConnectionsNoLimit pool does not track ' |
| 44 | + 'connections') |
0 commit comments