Skip to content

Commit 164b250

Browse files
committed
Port ATX to 9.6 EE branch
1 parent babdf37 commit 164b250

File tree

15 files changed

+1245
-0
lines changed

15 files changed

+1245
-0
lines changed

src/pl/plpython/plpy_atxobject.c

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* the PLyAutonomous class
3+
*
4+
* src/pl/plpython/plpy_atxobject.c
5+
*/
6+
7+
#include "postgres.h"
8+
9+
#include "access/xact.h"
10+
#include "executor/spi.h"
11+
#include "utils/memutils.h"
12+
13+
#include "plpython.h"
14+
15+
#include "plpy_atxobject.h"
16+
17+
#include "plpy_elog.h"
18+
19+
20+
static void PLy_atx_dealloc(PyObject *subxact);
21+
static PyObject *PLy_atx_enter(PyObject *self, PyObject *unused);
22+
static PyObject *PLy_atx_exit(PyObject *self, PyObject *args);
23+
24+
static char PLy_atx_doc[] = {
25+
"PostgreSQL autonomous transaction context manager"
26+
};
27+
28+
static PyMethodDef PLy_atx_methods[] = {
29+
{"__enter__", PLy_atx_enter, METH_VARARGS, NULL},
30+
{"__exit__", PLy_atx_exit, METH_VARARGS, NULL},
31+
/* user-friendly names for Python <2.6 */
32+
{"enter", PLy_atx_enter, METH_VARARGS, NULL},
33+
{"exit", PLy_atx_exit, METH_VARARGS, NULL},
34+
{NULL, NULL, 0, NULL}
35+
};
36+
37+
static PyTypeObject PLy_AtxType = {
38+
PyVarObject_HEAD_INIT(NULL, 0)
39+
"PLyAtx", /* tp_name */
40+
sizeof(PLyAtxObject), /* tp_size */
41+
0, /* tp_itemsize */
42+
43+
/*
44+
* methods
45+
*/
46+
PLy_atx_dealloc, /* tp_dealloc */
47+
0, /* tp_print */
48+
0, /* tp_getattr */
49+
0, /* tp_setattr */
50+
0, /* tp_compare */
51+
0, /* tp_repr */
52+
0, /* tp_as_number */
53+
0, /* tp_as_sequence */
54+
0, /* tp_as_mapping */
55+
0, /* tp_hash */
56+
0, /* tp_call */
57+
0, /* tp_str */
58+
0, /* tp_getattro */
59+
0, /* tp_setattro */
60+
0, /* tp_as_buffer */
61+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
62+
PLy_atx_doc, /* tp_doc */
63+
0, /* tp_traverse */
64+
0, /* tp_clear */
65+
0, /* tp_richcompare */
66+
0, /* tp_weaklistoffset */
67+
0, /* tp_iter */
68+
0, /* tp_iternext */
69+
PLy_atx_methods, /* tp_tpmethods */
70+
};
71+
72+
73+
void
74+
PLy_atx_init_type(void)
75+
{
76+
if (PyType_Ready(&PLy_AtxType) < 0)
77+
elog(ERROR, "could not initialize PLy_AtxType");
78+
}
79+
80+
/* s = plpy.atx() */
81+
PyObject *
82+
PLy_atx_new(PyObject *self, PyObject *unused)
83+
{
84+
PLyAtxObject *ob;
85+
86+
ob = PyObject_New(PLyAtxObject, &PLy_AtxType);
87+
88+
if (ob == NULL)
89+
return NULL;
90+
91+
return (PyObject *) ob;
92+
}
93+
94+
/* Python requires a dealloc function to be defined */
95+
static void
96+
PLy_atx_dealloc(PyObject *atx)
97+
{
98+
}
99+
100+
/*
101+
* atx.__enter__() or atx.enter()
102+
*
103+
* Start an atx.
104+
*/
105+
static PyObject *
106+
PLy_atx_enter(PyObject *self, PyObject *unused)
107+
{
108+
PLyAtxObject *atx = (PLyAtxObject *) self;
109+
110+
SuspendTransaction();
111+
112+
Py_INCREF(self);
113+
return self;
114+
}
115+
116+
/*
117+
* atx.__exit__(exc_type, exc, tb) or atx.exit(exc_type, exc, tb)
118+
*
119+
* Exit an autonomous transaction. exc_type is an exception type, exc
120+
* is the exception object, tb is the traceback. If exc_type is None,
121+
* commit the atx, if not abort it.
122+
*
123+
* The method signature is chosen to allow atx objects to
124+
* be used as context managers as described in
125+
* <http://www.python.org/dev/peps/pep-0343/>.
126+
*/
127+
static PyObject *
128+
PLy_atx_exit(PyObject *self, PyObject *args)
129+
{
130+
PyObject *type;
131+
PyObject *value;
132+
PyObject *traceback;
133+
PLyAtxObject *atx = (PLyAtxObject *) self;
134+
135+
if (!PyArg_ParseTuple(args, "OOO", &type, &value, &traceback))
136+
return NULL;
137+
138+
if (type != Py_None)
139+
{
140+
AbortCurrentTransaction();
141+
}
142+
else
143+
{
144+
CommitTransactionCommand();
145+
}
146+
147+
Py_INCREF(Py_None);
148+
return Py_None;
149+
}

src/pl/plpython/plpy_atxobject.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* src/pl/plpython/plpy_atxobject.h
3+
*/
4+
5+
#ifndef PLPY_ATXOBJECT
6+
#define PLPY_ATXOBJECT
7+
8+
#include "nodes/pg_list.h"
9+
10+
typedef struct PLyAtxObject
11+
{
12+
PyObject_HEAD
13+
} PLyAtxObject;
14+
15+
extern void PLy_atx_init_type(void);
16+
extern PyObject *PLy_atx_new(PyObject *self, PyObject *unused);
17+
18+
#endif /* PLPY_ATXOBJECT */

src/test/isolation/atx_schedule

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
test: atx-deadlock-0
2+
test: atx-deadlock-1
3+
test: atx-deadlock-2
4+
test: atx-iso-0
5+
test: atx-iso-1
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Parsed test spec with 1 sessions
2+
3+
starting permutation: s1la s1atxb s1lb s1atxc s1c
4+
step s1la: lock table a in access exclusive mode;
5+
step s1atxb: begin autonomous;
6+
step s1lb: lock table a in access exclusive mode;
7+
ERROR: lockmode 8:AccessExclusiveLock conflicts with itself, acquiring the same lock in that mode again in an autonomous transaction will lead to a sure deadlock
8+
step s1atxc: commit;
9+
step s1c: commit;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Parsed test spec with 2 sessions
2+
3+
starting permutation: s1la s2lb s1atxb s2la s1lb s1atxc s1c s2c
4+
step s1la: lock table a in access exclusive mode;
5+
step s2lb: lock table b in access exclusive mode;
6+
step s1atxb: begin autonomous;
7+
step s2la: lock table a in access exclusive mode; <waiting ...>
8+
step s1lb: lock table b in access exclusive mode; <waiting ...>
9+
step s1lb: <... completed>
10+
step s2la: <... completed>
11+
error in steps s1lb s2la: ERROR: deadlock detected
12+
step s1atxc: commit;
13+
step s1c: commit;
14+
step s2c: commit;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Parsed test spec with 2 sessions
2+
3+
starting permutation: s1u1 s2u2 s1atxb s2u1 s1u2 s1atxc s1c s2c
4+
step s1u1: update t set b = 11 where a = 1;
5+
step s2u2: update t set b = 22 where a = 2;
6+
step s1atxb: begin autonomous;
7+
step s2u1: update t set b = 11 where a = 1; <waiting ...>
8+
step s1u2: update t set b = 21 where a = 2; <waiting ...>
9+
step s1u2: <... completed>
10+
step s2u1: <... completed>
11+
error in steps s1u2 s2u1: ERROR: deadlock detected
12+
step s1atxc: commit;
13+
step s1c: commit;
14+
step s2c: commit;

0 commit comments

Comments
 (0)