static int
Per_p_set_or_delattro(cPersistentObject *self, PyObject *name, PyObject *v)
{
    int result = -1;    /* guilty until proved innocent */
    PyObject *converted;
    char *s;

    converted = convert_name(name);
    if (!converted)
        goto Done;
    s = PyBytes_AS_STRING(converted);

    if (strncmp(s, "_p_", 3))
    {
        if (unghostify(self) < 0)
            goto Done;
        accessed(self);

        result = 0;
    }
    else
    {
        if (PyObject_GenericSetAttr((PyObject *)self, name, v) < 0)
            goto Done;
        result = 1;
    }

Done:
  Py_XDECREF(converted);
  return result;
}
/* Exposed as _p_getattr method.  Test whether base getattr should be used */
static PyObject *
Per__p_getattr(cPersistentObject *self, PyObject *name)
{
    PyObject *result = NULL;    /* guilty until proved innocent */
    PyObject *converted;
    char *s;

    converted = convert_name(name);
    if (!converted)
        goto Done;
    s = PyBytes_AS_STRING(converted);

    if (*s != '_' || unghost_getattr(s))
    {
        if (unghostify(self) < 0)
            goto Done;
        accessed(self);
        result = Py_False;
    }
    else
        result = Py_True;

    Py_INCREF(result);

Done:
    Py_XDECREF(converted);
    return result;
}
static int
Per_setattro(cPersistentObject *self, PyObject *name, PyObject *v)
{
    int result = -1;    /* guilty until proved innocent */
    PyObject *converted;
    char *s;

    converted = convert_name(name);
    if (!converted)
        goto Done;
    s = PyBytes_AS_STRING(converted);

    if (strncmp(s, "_p_", 3) != 0)
    {
        if (unghostify(self) < 0)
            goto Done;
        accessed(self);
        if (strncmp(s, "_v_", 3) != 0
            && self->state != cPersistent_CHANGED_STATE)
            {
            if (changed(self) < 0)
                goto Done;
            }
    }
    result = PyObject_GenericSetAttr((PyObject *)self, name, v);

Done:
    Py_XDECREF(converted);
    return result;
}
static PyObject *
Per_get_mtime(cPersistentObject *self)
{
    PyObject *t, *v;

    if (unghostify(self) < 0)
        return NULL;

    accessed(self);

    if (memcmp(self->serial, "\0\0\0\0\0\0\0\0", 8) == 0)
    {
        Py_INCREF(Py_None);
        return Py_None;
    }

#ifdef PY3K
    t = PyObject_CallFunction(TimeStamp, "y#", self->serial, 8);
#else
    t = PyObject_CallFunction(TimeStamp, "s#", self->serial, 8);
#endif
    if (!t)
    {
        return NULL;
    }
    v = PyObject_CallMethod(t, "timeTime", "");
    Py_DECREF(t);
    return v;
}
/* Load the object's state if necessary and become sticky */
static int
Per_setstate(cPersistentObject *self)
{
    if (unghostify(self) < 0)
        return -1;
    self->state = cPersistent_STICKY_STATE;
    return 0;
}
Beispiel #6
0
static PyObject *
Per__p_activate(cPersistentObject *self)
{
    if (unghostify(self) < 0)
        return NULL;

    Py_INCREF(Py_None);
    return Py_None;
}
static PyObject *
Per__getstate__(cPersistentObject *self)
{
    /* TODO:  Should it be an error to call __getstate__() on a ghost? */
    if (unghostify(self) < 0)
        return NULL;

    /* TODO:  should we increment stickyness?  Tim doesn't understand that
        question. S*/
    return pickle___getstate__((PyObject*)self);
}
static PyObject*
Per_getattro(cPersistentObject *self, PyObject *name)
{
    PyObject *result = NULL;    /* guilty until proved innocent */
    PyObject *converted;
    char *s;

    converted = convert_name(name);
    if (!converted)
        goto Done;
    s = PyBytes_AS_STRING(converted);

    if (unghost_getattr(s))
    {
        if (unghostify(self) < 0)
            goto Done;
        accessed(self);
    }
    result = PyObject_GenericGetAttr((PyObject *)self, name);

Done:
    Py_XDECREF(converted);
    return result;
}
static void
ghostify(cPersistentObject *self)
{
    PyObject **dictptr, *slotnames;

    /* are we already a ghost? */
    if (self->state == cPersistent_GHOST_STATE)
        return;

    /* Is it ever possible to not have a cache? */
    if (self->cache == NULL) 
    {
        self->state = cPersistent_GHOST_STATE;
        return;
    }

    if (self->ring.r_next == NULL)
    {
        /* There's no way to raise an error in this routine. */
#ifdef Py_DEBUG
        fatal_1350(self, "ghostify", "claims to be in a cache but isn't");
#else
        return;
#endif
    }

    /* If we're ghostifying an object, we better have some non-ghosts. */
    assert(self->cache->non_ghost_count > 0);
    self->cache->non_ghost_count--;
    self->cache->total_estimated_size -= 
        _estimated_size_in_bytes(self->estimated_size);
    ring_del(&self->ring);
    self->state = cPersistent_GHOST_STATE;

    /* clear __dict__ */
    dictptr = _PyObject_GetDictPtr((PyObject *)self);
    if (dictptr && *dictptr)
    {
        Py_DECREF(*dictptr);
        *dictptr = NULL;
    }

    /* clear all slots besides _p_*
     * ( for backward-compatibility reason we do this only if class does not
     *   override __new__ ) */
    if (Py_TYPE(self)->tp_new == Pertype.tp_new)
    {
        slotnames = pickle_slotnames(Py_TYPE(self));
        if (slotnames && slotnames != Py_None)
        {
            int i;

            for (i = 0; i < PyList_GET_SIZE(slotnames); i++)
            {
                PyObject *name;
                char *cname;
                int is_special;

                name = PyList_GET_ITEM(slotnames, i);
#ifdef PY3K
                if (PyUnicode_Check(name))
                {
                    PyObject *converted = convert_name(name);
                    cname = PyBytes_AS_STRING(converted);
#else
                if (PyBytes_Check(name))
                {
                    cname = PyBytes_AS_STRING(name);
#endif
                    is_special = !strncmp(cname, "_p_", 3);
#ifdef PY3K
                    Py_DECREF(converted);
#endif
                    if (is_special) /* skip persistent */
                    {
                        continue;
                    }
                }

                /* NOTE: this skips our delattr hook */
                if (PyObject_GenericSetAttr((PyObject *)self, name, NULL) < 0)
                    /* delattr of non-set slot will raise AttributeError - we
                     * simply ignore. */
                    PyErr_Clear();
            }
        }
        Py_XDECREF(slotnames);
    }

    /* We remove the reference to the just ghosted object that the ring
    * holds.  Note that the dictionary of oids->objects has an uncounted
    * reference, so if the ring's reference was the only one, this frees
    * the ghost object.  Note further that the object's dealloc knows to
    * inform the dictionary that it is going away.
    */
    Py_DECREF(self);
}

static int
changed(cPersistentObject *self)
{
    if ((self->state == cPersistent_UPTODATE_STATE ||
        self->state == cPersistent_STICKY_STATE)
        && self->jar)
    {
        PyObject *meth, *arg, *result;
        static PyObject *s_register;

        if (s_register == NULL)
            s_register = INTERN("register");
        meth = PyObject_GetAttr((PyObject *)self->jar, s_register);
        if (meth == NULL)
            return -1;
        arg = PyTuple_New(1);
        if (arg == NULL) 
        {
            Py_DECREF(meth);
            return -1;
        }
        Py_INCREF(self);
        PyTuple_SET_ITEM(arg, 0, (PyObject *)self);
        result = PyEval_CallObject(meth, arg);
        Py_DECREF(arg);
        Py_DECREF(meth);
        if (result == NULL)
            return -1;
        Py_DECREF(result);

        self->state = cPersistent_CHANGED_STATE;
    }

    return 0;
}

static int
readCurrent(cPersistentObject *self)
{
    if ((self->state == cPersistent_UPTODATE_STATE ||
        self->state == cPersistent_STICKY_STATE)
        && self->jar && self->oid)
    {
        static PyObject *s_readCurrent=NULL;
        PyObject *r;

        if (s_readCurrent == NULL)
            s_readCurrent = INTERN("readCurrent");

        r = PyObject_CallMethodObjArgs(self->jar, s_readCurrent, self, NULL);
        if (r == NULL)
            return -1;

        Py_DECREF(r);
    }

    return 0;
}

static PyObject *
Per__p_deactivate(cPersistentObject *self)
{
    if (self->state == cPersistent_UPTODATE_STATE && self->jar)
    {
        PyObject **dictptr = _PyObject_GetDictPtr((PyObject *)self);
        if (dictptr && *dictptr)
        {
            Py_DECREF(*dictptr);
            *dictptr = NULL;
        }
        /* Note that we need to set to ghost state unless we are
            called directly. Methods that override this need to
            do the same! */
        ghostify(self);
        if (PyErr_Occurred())
            return NULL;
    }

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
Per__p_activate(cPersistentObject *self)
{
    if (unghostify(self) < 0)
        return NULL;

    Py_INCREF(Py_None);
    return Py_None;
}

static int Per_set_changed(cPersistentObject *self, PyObject *v);

static PyObject *
Per__p_invalidate(cPersistentObject *self)
{
    signed char old_state = self->state;

    if (old_state != cPersistent_GHOST_STATE)
    {
        if (Per_set_changed(self, NULL) < 0)
            return NULL;
        ghostify(self);
        if (PyErr_Occurred())
            return NULL;
    }
    Py_INCREF(Py_None);
    return Py_None;
}
static int
Per_set_changed(cPersistentObject *self, PyObject *v)
{
    int deactivate = 0;
    int true;

    if (!v)
    {
        /* delattr is used to invalidate an object even if it has changed. */
        if (self->state != cPersistent_GHOST_STATE)
            self->state = cPersistent_UPTODATE_STATE;
        deactivate = 1;
    }
    else if (v == Py_None)
        deactivate = 1;

    if (deactivate)
    {
        PyObject *res, *meth;
        meth = PyObject_GetAttr((PyObject *)self, py__p_deactivate);
        if (meth == NULL)
            return -1;
        res = PyObject_CallObject(meth, NULL);
        if (res)
            Py_DECREF(res);
        else
        {
            /* an error occured in _p_deactivate().

                It's not clear what we should do here.  The code is
                obviously ignoring the exception, but it shouldn't return
                0 for a getattr and set an exception.  The simplest change
                is to clear the exception, but that simply masks the
                error.

                This prints an error to stderr just like exceptions in
                __del__().  It would probably be better to log it but that
                would be painful from C.
            */
            PyErr_WriteUnraisable(meth);
        }
        Py_DECREF(meth);
        return 0;
    }
    /* !deactivate.  If passed a true argument, mark self as changed (starting
    * with ZODB 3.6, that includes activating the object if it's a ghost).
    * If passed a false argument, and the object isn't a ghost, set the
    * state as up-to-date.
    */
    true = PyObject_IsTrue(v);
    if (true == -1)
        return -1;
    if (true)
    {
        if (self->state < 0)
        {
            if (unghostify(self) < 0)
                return -1;
        }
        return changed(self);
    }

    /* We were passed a false, non-None argument.  If we're not a ghost,
    * mark self as up-to-date.
    */
    if (self->state >= 0)
        self->state = cPersistent_UPTODATE_STATE;
    return 0;
}