[Zope-Checkins] CVS: Zope3/lib/python/Persistence - __init__.py:1.1.40.10 cPersistence.c:1.1.2.14 cPersistence.h:1.1.2.6 cPersistenceAPI.h:1.1.2.6

Jeremy Hylton jeremy@zope.com
Tue, 4 Jun 2002 14:05:52 -0400


Update of /cvs-repository/Zope3/lib/python/Persistence
In directory cvs.zope.org:/tmp/cvs-serv12193

Modified Files:
      Tag: Zope-3x-branch
	__init__.py cPersistence.c cPersistence.h cPersistenceAPI.h 
Log Message:
Split Persistent into two C types, BasePersistent and Persistent.

BasePersistent is used by persistent objects implemented in C that do
not have an __dict__.  Persistent is the base class for persistent
objects implemented in Python.

BasePersistent is exposed to Python as an attribute of the Persistence
package.  (Just like Persistent.)

Other changes to the C API:

Expose both PyPersist_Type and PyPersistBase_Type.

The register, load, and accessed functions implemented in C now start
with underscores.  Extension modules that need to use these functions
should use the macro versions, which pull the functions from the C API
struct.

The PER_ACCESSED() macro can now be replaced with PyPersist_SetATime().



=== Zope3/lib/python/Persistence/__init__.py 1.1.40.9 => 1.1.40.10 ===
 """Provide access to Persistent and PersistentMapping"""
 
-from cPersistence import Persistent
+from cPersistence import Persistent, BasePersistent
 
 # XXX why do we hide the real organization of the package?
 
@@ -23,4 +23,4 @@
 from PersistentList import PersistentList
 PersistentList.__module__ = 'Persistence'
 
-__all__ = ["Persistent", "PersistentMapping"]
+__all__ = ["BasePersistent", "Persistent", "PersistentMapping"]


=== Zope3/lib/python/Persistence/cPersistence.c 1.1.2.13 => 1.1.2.14 ===
 "$Id$\n";
 
-staticforward PyTypeObject PyPersist_Type;
+/* cPersistence defines two Python types and a C API for them.
+
+   This table summarizes the stuff connected to each type.
+
+   PyTypeObject	   PyPersistBase_Type    	PyPersist_Type
+   supports        persistent objects in C 	persistent objects in Python
+   PyObject *      PyPersistBaseObject *        PyPersistObject *
+   C struct        PyPersist_HEAD		PyPersist_INSTANCE_HEAD
+   C API macro     PyPersist_BASE_TYPE          PyPersist_INSTANCE_TYPE       
+   Python object   Persistence.BasePersistent   Persistence.Persistent
+
+   The two types share many of the same tp_xxx implementations.  The
+   key difference between the base type and the instance type is that
+   the latter has room for an __dict__.  The Persistence.Persistent
+   object is used as a base class for peristent object classes written
+   in Python.
+
+   The functions that can operate on either type take a
+   PyPersistBaseObject * argument.  If the function needs to access
+   the po_dict slot, it must first check obj->ob_type->tp_dictoffset.
+   For a PyPersistBase_Type object, the dictoffset is 0.
+
+   The getstate and setstate implementations only work with
+   PyPersist_Type objects, because they depend on having an __dict__.
+
+   The base type exists to support C types that are also persistent.
+   The only examples of such types are in Persistence.BTrees.
+
+*/
 
 /* A helper for setstate that is more efficient than PyMapping_Keys().
  */
@@ -41,7 +69,7 @@
 static PyObject *s_register = NULL;
 
 PyObject *
-PyPersist_RegisterDataManager(PyPersistBaseObject *self) 
+_PyPersist_RegisterDataManager(PyPersistBaseObject *self) 
 {
     PyObject *meth, *arg, *result;
 
@@ -71,7 +99,7 @@
 */
 
 PyObject *
-PyPersist_Load(PyPersistBaseObject *self) 
+_PyPersist_Load(PyPersistBaseObject *self) 
 {
     static PyObject *s_setstate = NULL;
     PyObject *meth, *arg, *result;
@@ -105,7 +133,7 @@
 */
 
 int
-PyPersist_RegisterTransaction(PyPersistBaseObject *self)
+_PyPersist_RegisterTransaction(PyPersistBaseObject *self)
 {
     static PyObject *get_transaction = NULL;
     PyObject *mainmod = NULL, *builtins = NULL;
@@ -182,7 +210,7 @@
  */
 
 void
-PyPersist_SetATime(PyPersistBaseObject *self)
+_PyPersist_SetATime(PyPersistBaseObject *self)
 {
     time_t t = time(NULL);
     self->po_atime = t % 86400;
@@ -238,7 +266,7 @@
 	Py_INCREF(Py_None);
 	return Py_None;
     }
-    
+
     pdict = _PyObject_GetDictPtr(self);
     if ((*pdict) == NULL) {
 	*pdict = PyDict_New();
@@ -378,7 +406,7 @@
 	if (newstate == CHANGED_TRUE || newstate == CHANGED_FALSE) {
 	    /* Turn a ghost into a real object. */
 	    self->po_state = CHANGED;
-	    if (PyPersist_Load((PyPersistBaseObject *)self) == NULL)
+	    if (_PyPersist_Load((PyPersistBaseObject *)self) == NULL)
 		return -1;
 	    if (newstate == CHANGED_TRUE)
 		self->po_state = CHANGED;
@@ -389,7 +417,7 @@
 	/* Mark an up-to-date object as changed. */
 	if (self->po_state == UPTODATE) {
 	    self->po_state = CHANGED;
-	    if (!PyPersist_RegisterDataManager((PyPersistBaseObject *)self))
+	    if (!_PyPersist_RegisterDataManager((PyPersistBaseObject *)self))
 		return -1;
 	}
     } else if (newstate == CHANGED_FALSE) {
@@ -427,6 +455,12 @@
     return self->po_dict;
 }
 
+
+static PyGetSetDef base_persist_getsets[] = {
+    {"_p_changed", (getter)persist_get_state, (setter)persist_set_state},
+    {NULL}
+};
+
 static PyGetSetDef persist_getsets[] = {
     {"_p_changed", (getter)persist_get_state, (setter)persist_set_state},
     {"__dict__", (getter)persist_get_dict},
@@ -491,14 +525,14 @@
 	    && (strcmp(s_name, "__dict__") != 0))) {
 	if (self->po_state == GHOST) {
 	    self->po_state = CHANGED;
-	    if (PyPersist_Load((PyPersistBaseObject *)self) == NULL) {
+	    if (_PyPersist_Load((PyPersistBaseObject *)self) == NULL) {
 		persist_deactivate(self);
 		self->po_state = GHOST;
 		return NULL;
 	    } else
 		self->po_state = UPTODATE;
 	}
-	PyPersist_SetATime((PyPersistBaseObject *)self);
+	_PyPersist_SetATime((PyPersistBaseObject *)self);
     }
 
     attr = PyObject_GenericGetAttr((PyObject *)self, name);
@@ -547,15 +581,15 @@
 				"attempt to modify unrevivable ghost");
 		return -1;
 	    }
-	    if (PyPersist_Load((PyPersistBaseObject *)self) == NULL)
+	    if (_PyPersist_Load((PyPersistBaseObject *)self) == NULL)
 		return -1;
 	} else if (self->po_state == UPTODATE && self->po_dm)
-	    if (!PyPersist_RegisterDataManager((PyPersistBaseObject *)self))
+	    if (!_PyPersist_RegisterDataManager((PyPersistBaseObject *)self))
 		return -1;
 
 	if (self->po_dm && self->po_oid) {
 	    self->po_state = CHANGED;
-	    PyPersist_SetATime((PyPersistBaseObject *)self);
+	    _PyPersist_SetATime((PyPersistBaseObject *)self);
 	}
     }
 
@@ -574,7 +608,9 @@
     Py_XDECREF(self->po_dm);
     Py_XDECREF(self->po_oid);
     Py_XDECREF(self->po_serial);
-    Py_XDECREF(self->po_dict);
+    if (self->ob_type->tp_dictoffset) {
+	Py_XDECREF(self->po_dict);
+    }
     PyObject_GC_Del(self);
 }
 
@@ -592,7 +628,9 @@
     VISIT(self->po_dm);
     VISIT(self->po_oid);
     VISIT(self->po_serial);
-    VISIT(self->po_dict);
+    if (self->ob_type->tp_dictoffset) {
+	VISIT(self->po_dict);
+    }
 #undef VISIT
     return 0;
 }
@@ -603,11 +641,13 @@
     Py_XDECREF(self->po_dm);
     Py_XDECREF(self->po_oid);
     Py_XDECREF(self->po_serial);
-    Py_XDECREF(self->po_dict);
     self->po_dm = NULL;
     self->po_oid = NULL;
     self->po_serial = NULL;
-    self->po_dict = NULL;
+    if (self->ob_type->tp_dictoffset) {
+	Py_XDECREF(self->po_dict);
+	self->po_dict = NULL;
+    }
     return 0;
 }
 
@@ -620,6 +660,54 @@
 */
 #define DEFERRED_ADDRESS(ADDR) 0
 
+/* XXX Not sure how much functionality the base persistent type should
+   provide.  It is currently used only by the BTrees.
+*/
+   
+
+static PyTypeObject PyPersistBase_Type = {
+    PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
+    0,					/* ob_size */
+    "Persistence.BasePersistent",	/* tp_name */
+    sizeof(PyPersistBaseObject),	/* tp_basicsize */
+    0,					/* tp_itemsize */
+    (destructor)persist_dealloc,	/* tp_dealloc */
+    0,					/* tp_print */
+    0,					/* tp_getattr */
+    0,					/* tp_setattr */
+    0,					/* tp_compare */
+    0,					/* tp_repr */
+    0,					/* tp_as_number */
+    0,					/* tp_as_sequence */
+    0,					/* tp_as_mapping */
+    0,					/* tp_hash */
+    0,					/* tp_call */
+    0,					/* tp_str */
+    (getattrofunc)persist_getattro,	/* tp_getattro */
+    (setattrofunc)persist_setattro,	/* tp_setattro */
+    0,					/* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+    Py_TPFLAGS_BASETYPE, 		/* tp_flags */
+    0,					/* tp_doc */
+    (traverseproc)persist_traverse,	/* tp_traverse */
+    (inquiry)persist_clear,		/* tp_clear */
+    0,					/* tp_richcompare */
+    0,					/* tp_weaklistoffset */
+    0,					/* tp_iter */
+    0,					/* tp_iternext */
+    0,					/* tp_methods */
+    persist_members,			/* tp_members */
+    base_persist_getsets,		/* tp_getset */
+    0,					/* tp_base */
+    0,					/* tp_dict */
+    0,					/* tp_descr_get */
+    0,					/* tp_descr_set */
+    0,					/* tp_dictoffset */
+    0,					/* tp_init */
+    0,					/* tp_alloc */
+    PyType_GenericNew,			/* tp_new */
+};
+
 static PyTypeObject PyPersist_Type = {
     PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
     0,					/* ob_size */
@@ -668,10 +756,11 @@
 };
 
 static PyPersist_C_API_struct c_api = {
+    &PyPersistBase_Type,
     &PyPersist_Type,
-    PyPersist_Load,
-    PyPersist_RegisterTransaction,
-    PyPersist_SetATime
+    _PyPersist_Load,
+    _PyPersist_RegisterTransaction,
+    _PyPersist_SetATime
 };
 
 static int
@@ -704,9 +793,14 @@
 {
     PyObject *m, *d, *v;
 
+    PyPersistBase_Type.ob_type = &PyType_Type;
     PyPersist_Type.ob_type = &PyType_Type;
+    if (PyType_Ready(&PyPersistBase_Type) < 0)
+	return;
     if (PyType_Ready(&PyPersist_Type) < 0)
 	return;
+    if (persist_set_interface(&PyPersistBase_Type) < 0)
+	return;
     if (persist_set_interface(&PyPersist_Type) < 0)
 	return;
 
@@ -720,6 +814,11 @@
 
     Py_INCREF(&PyPersist_Type);
     if (PyDict_SetItemString(d, "Persistent", (PyObject *)&PyPersist_Type) < 0)
+	return;
+
+    Py_INCREF(&PyPersistBase_Type);
+    if (PyDict_SetItemString(d, "BasePersistent", 
+			     (PyObject *)&PyPersistBase_Type) < 0)
 	return;
 
     v = PyCObject_FromVoidPtr(&c_api, NULL);


=== Zope3/lib/python/Persistence/cPersistence.h 1.1.2.5 => 1.1.2.6 ===
 } PyPersistObject;
 
-/* XXX need to make these macros in cPersistenceAPI.h */
-extern PyObject *PyPersist_Load(PyPersistBaseObject *);
-extern PyObject *PyPersist_RegisterDataManager(PyPersistBaseObject *);
-extern int PyPersist_RegisterTransaction(PyPersistBaseObject *);
-extern void PyPersist_SetATime(PyPersistBaseObject *);
+extern PyObject *_PyPersist_Load(PyPersistBaseObject *);
+extern PyObject *_PyPersist_RegisterDataManager(PyPersistBaseObject *);
+extern int _PyPersist_RegisterTransaction(PyPersistBaseObject *);
+extern void _PyPersist_SetATime(PyPersistBaseObject *);
 
 /* A struct to encapsulation the PyPersist C API for use by other
    dynamically load extensions.
 */
 
 typedef struct {
-    PyTypeObject *type;
+    PyTypeObject *base_type;
+    PyTypeObject *instance_type;
     PyObject *(*load)(PyPersistBaseObject *);
     int (*reg_trans)(PyPersistBaseObject *);
     void (*set_atime)(PyPersistBaseObject *);


=== Zope3/lib/python/Persistence/cPersistenceAPI.h 1.1.2.5 => 1.1.2.6 ===
 static PyPersist_C_API_struct *PyPersist_C_API;
 
-#define PyPersist_TYPE PyPersist_C_API->type
+#define PyPersist_BASE_TYPE PyPersist_C_API->base_type
+#define PyPersist_INSTANCE_TYPE PyPersist_C_API->instance_type
 
 #define PyPersist_INCREF(O) \
     if (((O)->po_state == UPTODATE) \
@@ -29,6 +30,9 @@
 
 #define PyPersist_CHANGED(O) \
     PyPersist_C_API->reg_trans((PyPersistBaseObject *)(O))
+
+#define PyPersist_SetATime(O) \
+    PyPersist_C_API->set_atime((PyPersistBaseObject *)(O))
 
 /* Macros for compatibility with ZODB 3 C extensions. */