Commit 13e8eb78 authored by Kirill Smelkov's avatar Kirill Smelkov

X catch simultaneous invalidate vs unghostify

This continues https://github.com/zopefoundation/zodb/commit/1e285a3c

It caught the following race condition on zopenrace.py[1] in ZODB4
environment(*):

    Exception in thread Thread-25:
    Traceback (most recent call last):
      File "/srv/slapgrid/slappart7/srv/runner/software/c75bac561a367d3162cc44818372d123/parts/python2.7/lib/python2.7/threading.py", line 801, in __bootstrap_inner
        self.run()
      File "/srv/slapgrid/slappart7/srv/runner/software/c75bac561a367d3162cc44818372d123/parts/python2.7/lib/python2.7/threading.py", line 754, in run
        self.__target(*self.__args, **self.__kwargs)
      File "./zopenrace.py", line 160, in T1
        t1()
      File "./zopenrace.py", line 153, in t1
        raise AssertionError("T1: obj1.i (%d)  !=  obj2.i (%d)" % (i1, i2))
    AssertionError: T1: obj1.i (503)  !=  obj2.i (502)

    Exception in thread Thread-26:
    Traceback (most recent call last):
      File "/srv/slapgrid/slappart7/srv/runner/software/c75bac561a367d3162cc44818372d123/parts/python2.7/lib/python2.7/threading.py", line 801, in __bootstrap_inner
        self.run()
      File "/srv/slapgrid/slappart7/srv/runner/software/c75bac561a367d3162cc44818372d123/parts/python2.7/lib/python2.7/threading.py", line 754, in run
        self.__target(*self.__args, **self.__kwargs)
      File "./zopenrace.py", line 184, in T2
        t2()
      File "./zopenrace.py", line 179, in t2
        transaction.commit()
      File "/srv/slapgrid/slappart7/srv/runner/kirr/JZ3.venv/lib/python2.7/site-packages/transaction/_manager.py", line 123, in commit
        return self.get().commit()
      File "/srv/slapgrid/slappart7/srv/runner/kirr/JZ3.venv/lib/python2.7/site-packages/transaction/_transaction.py", line 285, in commit
        self._synchronizers.map(lambda s: s.afterCompletion(self))
      File "/srv/slapgrid/slappart7/srv/runner/kirr/JZ3.venv/lib/python2.7/site-packages/transaction/weakset.py", line 62, in map
        f(elt)
      File "/srv/slapgrid/slappart7/srv/runner/kirr/JZ3.venv/lib/python2.7/site-packages/transaction/_transaction.py", line 285, in <lambda>
        self._synchronizers.map(lambda s: s.afterCompletion(self))
      File "/srv/slapgrid/slappart7/srv/runner/kirr/ZODB/src/ZODB/Connection.py", line 871, in _storage_sync
        self._flush_invalidations()
      File "/srv/slapgrid/slappart7/srv/runner/kirr/ZODB/src/ZODB/Connection.py", line 549, in _flush_invalidations
        self._cache.invalidate(invalidated)
    SystemError: invalidate: object at 0x7fa0cf1375f0 with type PInt:  simultaneous unghostify is running

[1] https://github.com/zopefoundation/ZODB/issues/290
(*) ZODB-4.4.4 + PR136 + ping-on-newtxn
parent 0e231fd3
...@@ -95,6 +95,7 @@ fatal_1350(cPersistentObject *self, const char *caller, const char *detail) ...@@ -95,6 +95,7 @@ fatal_1350(cPersistentObject *self, const char *caller, const char *detail)
#endif #endif
static void ghostify(cPersistentObject*); static void ghostify(cPersistentObject*);
static int _unghostify(cPersistentObject*);
static PyObject * pickle_slotnames(PyTypeObject *cls); static PyObject * pickle_slotnames(PyTypeObject *cls);
static PyObject * convert_name(PyObject *name); static PyObject * convert_name(PyObject *name);
...@@ -105,7 +106,28 @@ static PyObject * convert_name(PyObject *name); ...@@ -105,7 +106,28 @@ static PyObject * convert_name(PyObject *name);
static int static int
unghostify(cPersistentObject *self) unghostify(cPersistentObject *self)
{ {
if (self->state < 0 && self->jar) int ret;
if (self->state >= 0 || self->jar == NULL)
return 1;
if (self->xxx_in_unghostify) {
PyErr_Format(PyExc_SystemError, "object at %p with type %.200s: "
"double ghostify", self, Py_TYPE(self)->tp_name);
return -1;
}
self->xxx_in_unghostify = 1;
ret = _unghostify(self);
self->xxx_in_unghostify = 0;
return ret;
}
static int
_unghostify(cPersistentObject *self)
{
// if (self->state < 0 && self->jar)
if (1)
{ {
PyObject *r; PyObject *r;
...@@ -366,6 +388,12 @@ Per__p_invalidate(cPersistentObject *self) ...@@ -366,6 +388,12 @@ Per__p_invalidate(cPersistentObject *self)
{ {
signed char old_state = self->state; signed char old_state = self->state;
if (self->xxx_in_unghostify) {
PyErr_Format(PyExc_SystemError, "invalidate: object at %p with type %.200s: "
" simultaneous unghostify is running", self, Py_TYPE(self)->tp_name);
return NULL;
}
if (old_state != cPersistent_GHOST_STATE) if (old_state != cPersistent_GHOST_STATE)
{ {
if (Per_set_changed(self, NULL) < 0) if (Per_set_changed(self, NULL) < 0)
......
...@@ -60,7 +60,8 @@ typedef struct ccobject_head_struct PerCache; ...@@ -60,7 +60,8 @@ typedef struct ccobject_head_struct PerCache;
PerCache *cache; \ PerCache *cache; \
CPersistentRing ring; \ CPersistentRing ring; \
char serial[8]; \ char serial[8]; \
signed state:8; \ signed state:7; \
unsigned xxx_in_unghostify:1; \
unsigned estimated_size:24; unsigned estimated_size:24;
/* We recently added estimated_size. We originally added it as a new /* We recently added estimated_size. We originally added it as a new
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment