Commit 226ee421 authored by Toby Dickenson's avatar Toby Dickenson

merged toby-stiff-cache-branch and toby-unicode-branch

parent 87c6d4a6
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
****************************************************************************/ ****************************************************************************/
#define BTREETEMPLATE_C "$Id: BTreeTemplate.c,v 1.25 2002/03/08 18:33:01 jeremy Exp $\n" #define BTREETEMPLATE_C "$Id: BTreeTemplate.c,v 1.26 2002/03/27 10:14:01 htrd Exp $\n"
/* /*
** _BTree_get ** _BTree_get
...@@ -540,7 +540,7 @@ _BTree_clear(BTree *self) ...@@ -540,7 +540,7 @@ _BTree_clear(BTree *self)
if (self->firstbucket) if (self->firstbucket)
{ {
ASSERT(self->firstbucket->ob_refcnt > 1, ASSERT(self->firstbucket->ob_refcnt > 0,
"Invalid firstbucket pointer", -1); "Invalid firstbucket pointer", -1);
Py_DECREF(self->firstbucket); Py_DECREF(self->firstbucket);
self->firstbucket=NULL; self->firstbucket=NULL;
...@@ -573,7 +573,7 @@ BTree__p_deactivate(BTree *self, PyObject *args) ...@@ -573,7 +573,7 @@ BTree__p_deactivate(BTree *self, PyObject *args)
if (self->state==cPersistent_UPTODATE_STATE && self->jar) if (self->state==cPersistent_UPTODATE_STATE && self->jar)
{ {
if (_BTree_clear(self) < 0) return NULL; if (_BTree_clear(self) < 0) return NULL;
self->state=cPersistent_GHOST_STATE; PER_GHOSTIFY(self);
} }
Py_INCREF(Py_None); Py_INCREF(Py_None);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
****************************************************************************/ ****************************************************************************/
#define BUCKETTEMPLATE_C "$Id: BucketTemplate.c,v 1.28 2002/03/08 18:33:01 jeremy Exp $\n" #define BUCKETTEMPLATE_C "$Id: BucketTemplate.c,v 1.29 2002/03/27 10:14:01 htrd Exp $\n"
/* /*
** _bucket_get ** _bucket_get
...@@ -809,7 +809,7 @@ bucket__p_deactivate(Bucket *self, PyObject *args) ...@@ -809,7 +809,7 @@ bucket__p_deactivate(Bucket *self, PyObject *args)
if (self->state==cPersistent_UPTODATE_STATE && self->jar) if (self->state==cPersistent_UPTODATE_STATE && self->jar)
{ {
if (_bucket_clear(self) < 0) return NULL; if (_bucket_clear(self) < 0) return NULL;
self->state=cPersistent_GHOST_STATE; PER_GHOSTIFY(self);
} }
Py_INCREF(Py_None); Py_INCREF(Py_None);
......
...@@ -14,11 +14,21 @@ ...@@ -14,11 +14,21 @@
static char cPersistence_doc_string[] = static char cPersistence_doc_string[] =
"Defines Persistent mixin class for persistent objects.\n" "Defines Persistent mixin class for persistent objects.\n"
"\n" "\n"
"$Id: cPersistence.c,v 1.50 2002/03/08 18:36:13 jeremy Exp $\n"; "$Id: cPersistence.c,v 1.51 2002/03/27 10:14:04 htrd Exp $\n";
#include <string.h> #include <string.h>
#include "cPersistence.h" #include "cPersistence.h"
/* the layout of this struct is the same as the start of ccobject in cPickleCache.c */
struct ccobject_head_struct {
PyObject_HEAD
CPersistentRing ring_home;
int non_ghost_count;
};
#define HOME(O) ((!((O)->cache))?(NULL): (&(((struct ccobject_head_struct *)((O)->cache))->ring_home)) )
#define NON_GHOST_COUNT(O) ((!((O)->cache))?(NULL): (&(((struct ccobject_head_struct *)((O)->cache))->non_ghost_count)) )
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V) #define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
...@@ -112,21 +122,82 @@ if(self->state < 0 && self->jar) \ ...@@ -112,21 +122,82 @@ if(self->state < 0 && self->jar) \
{ \ { \
PyObject *r; \ PyObject *r; \
\ \
int *count = NON_GHOST_COUNT(self); \
if(count) \
{ \
(*count)++; \
self->ring.next = HOME(self); \
self->ring.prev = HOME(self)->prev; \
HOME(self)->prev->next = &self->ring; \
HOME(self)->prev = &self->ring; \
Py_INCREF(self); \
} \
self->state=cPersistent_CHANGED_STATE; \ self->state=cPersistent_CHANGED_STATE; \
UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self)) \ UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self)) \
{ \ { \
self->state=cPersistent_GHOST_STATE; \ ghostify(self); \
return ER; \ return ER; \
} \ } \
self->state=cPersistent_UPTODATE_STATE; \ self->state=cPersistent_UPTODATE_STATE; \
Py_DECREF(r); \ Py_DECREF(r); \
} }
#define KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self) \
if(HOME(self) && self->state>=0) { \
self->ring.prev->next = self->ring.next; \
self->ring.next->prev = self->ring.prev; \
self->ring.next = HOME(self); \
self->ring.prev = HOME(self)->prev; \
HOME(self)->prev->next = &self->ring; \
HOME(self)->prev = &self->ring; }
/****************************************************************************/ /****************************************************************************/
staticforward PyExtensionClass Pertype; staticforward PyExtensionClass Pertype;
static void
accessed(cPersistentObject *self)
{
KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
}
static void
ghostify(cPersistentObject *self)
{
int *count;
count = NON_GHOST_COUNT(self);
if(count && (self->state>=0))
{
(*count)--;
self->ring.next->prev = self->ring.prev;
self->ring.prev->next = self->ring.next;
self->ring.prev = NULL;
self->ring.next = NULL;
self->state = cPersistent_GHOST_STATE;
Py_DECREF(self);
}
else
{
self->state = cPersistent_GHOST_STATE;
}
}
static void
deallocated(cPersistentObject *self)
{
if(self->state>=0) ghostify(self);
if(self->cache)
{
PyObject *v=PyObject_CallMethod(self->cache,"_oid_unreferenced","O",self->oid);
if(!v) PyErr_Clear(); /* and explode later */
Py_XDECREF(v);
}
Py_XDECREF(self->jar);
Py_XDECREF(self->oid);
}
static int static int
changed(cPersistentObject *self) changed(cPersistentObject *self)
{ {
...@@ -185,7 +256,7 @@ Per___changed__(cPersistentObject *self, PyObject *args) ...@@ -185,7 +256,7 @@ Per___changed__(cPersistentObject *self, PyObject *args)
static PyObject * static PyObject *
Per__p_deactivate(cPersistentObject *self, PyObject *args) Per__p_deactivate(cPersistentObject *self, PyObject *args)
{ {
PyObject *dict; PyObject *dict,*dict2=NULL;
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
if (idebug_log < 0) call_debug("reinit",self); if (idebug_log < 0) call_debug("reinit",self);
...@@ -197,13 +268,22 @@ Per__p_deactivate(cPersistentObject *self, PyObject *args) ...@@ -197,13 +268,22 @@ Per__p_deactivate(cPersistentObject *self, PyObject *args)
if (self->state==cPersistent_UPTODATE_STATE && self->jar && if (self->state==cPersistent_UPTODATE_STATE && self->jar &&
HasInstDict(self) && (dict=INSTANCE_DICT(self))) HasInstDict(self) && (dict=INSTANCE_DICT(self)))
{ {
dict2 = PyDict_Copy(dict);
PyDict_Clear(dict); PyDict_Clear(dict);
/* Note that we need to set to ghost state unless we are /* Note that we need to set to ghost state unless we are
called directly. Methods that override this need to called directly. Methods that override this need to
do the same! */ do the same! */
self->state=cPersistent_GHOST_STATE; ghostify(self);
} }
/* need to delay releasing the last reference on instance attributes
until after we have finished accounting for losing our state */
if(dict2)
{
PyDict_Clear(dict2);
Py_DECREF(dict2);
}
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -333,8 +413,8 @@ Per_dealloc(cPersistentObject *self) ...@@ -333,8 +413,8 @@ Per_dealloc(cPersistentObject *self)
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
if(idebug_log < 0) call_debug("del",self); if(idebug_log < 0) call_debug("del",self);
#endif #endif
Py_XDECREF(self->jar); deallocated(self);
Py_XDECREF(self->oid); Py_XDECREF(self->cache);
Py_DECREF(self->ob_type); Py_DECREF(self->ob_type);
PyObject_DEL(self); PyObject_DEL(self);
} }
...@@ -387,7 +467,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name, ...@@ -387,7 +467,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
{ {
UPDATE_STATE_IF_NECESSARY(self, NULL); UPDATE_STATE_IF_NECESSARY(self, NULL);
self->atime=((long)(time(NULL)/3))%65536; KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
if (self->serial[7]=='\0' && self->serial[6]=='\0' && if (self->serial[7]=='\0' && self->serial[6]=='\0' &&
self->serial[5]=='\0' && self->serial[4]=='\0' && self->serial[5]=='\0' && self->serial[4]=='\0' &&
...@@ -419,7 +499,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name, ...@@ -419,7 +499,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
{ {
UPDATE_STATE_IF_NECESSARY(self, NULL); UPDATE_STATE_IF_NECESSARY(self, NULL);
self->atime=((long)(time(NULL)/3))%65536; KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
} }
return getattrf((PyObject *)self, oname); return getattrf((PyObject *)self, oname);
...@@ -466,6 +546,21 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -466,6 +546,21 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
{ {
if(name[3]=='o' && name[4]=='i' && name[5]=='d' && ! name[6]) if(name[3]=='o' && name[4]=='i' && name[5]=='d' && ! name[6])
{ {
if(HOME(self))
{
int result;
if(!v)
{
PyErr_SetString(PyExc_ValueError,"can not delete the oid of a cached object");
return -1;
}
if(PyObject_Cmp(self->oid,v,&result)<0) return -1;
if(result)
{
PyErr_SetString(PyExc_ValueError,"can not change the oid of a cached object");
return -1;
}
}
Py_XINCREF(v); Py_XINCREF(v);
ASSIGN(self->oid, v); ASSIGN(self->oid, v);
return 0; return 0;
...@@ -509,7 +604,6 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -509,7 +604,6 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
v=PyObject_GetAttr(OBJECT(self), py__p_deactivate); v=PyObject_GetAttr(OBJECT(self), py__p_deactivate);
if (v) { ASSIGN(v, PyObject_CallObject(v, NULL)); } if (v) { ASSIGN(v, PyObject_CallObject(v, NULL)); }
if (v) { Py_DECREF(v); } if (v) { Py_DECREF(v); }
self->state=cPersistent_GHOST_STATE;
return 0; return 0;
} }
if (PyObject_IsTrue(v)) return changed(self); if (PyObject_IsTrue(v)) return changed(self);
...@@ -521,8 +615,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -521,8 +615,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
{ {
UPDATE_STATE_IF_NECESSARY(self, -1); UPDATE_STATE_IF_NECESSARY(self, -1);
/* Record access times */ KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
self->atime=((long)(time(NULL)/3))%65536;
if((! (*name=='_' && name[1]=='v' && name[2]=='_')) if((! (*name=='_' && name[1]=='v' && name[2]=='_'))
&& (self->state != cPersistent_CHANGED_STATE && self->jar) && (self->state != cPersistent_CHANGED_STATE && self->jar)
...@@ -680,9 +773,11 @@ truecPersistenceCAPI = { ...@@ -680,9 +773,11 @@ truecPersistenceCAPI = {
(getattrofunc)Per_getattro, /*tp_getattr with object key*/ (getattrofunc)Per_getattro, /*tp_getattr with object key*/
(setattrofunc)Per_setattro, /*tp_setattr with object key*/ (setattrofunc)Per_setattro, /*tp_setattr with object key*/
changed, changed,
accessed,
ghostify,
deallocated,
(intfunctionwithpythonarg)Per_setstate, (intfunctionwithpythonarg)Per_setstate,
(pergetattr)Per_getattr, (pergetattr)Per_getattr,
(persetattr)_setattro,
}; };
void void
......
...@@ -18,12 +18,21 @@ ...@@ -18,12 +18,21 @@
#include "ExtensionClass.h" #include "ExtensionClass.h"
#include <time.h> #include <time.h>
#define cPersistent_HEAD PyObject_HEAD PyObject *jar, *oid; char serial[8]; unsigned short atime; signed char state; unsigned char reserved;
#define cPersistent_HEAD PyObject_HEAD PyObject *jar, *oid, *cache; CPersistentRing ring; char serial[8]; signed char state; unsigned char reserved[3];
#define cPersistent_GHOST_STATE -1 #define cPersistent_GHOST_STATE -1
#define cPersistent_UPTODATE_STATE 0 #define cPersistent_UPTODATE_STATE 0
#define cPersistent_CHANGED_STATE 1 #define cPersistent_CHANGED_STATE 1
#define cPersistent_STICKY_STATE 2 #define cPersistent_STICKY_STATE 2
struct ccobject_head_struct;
typedef struct CPersistentRing_struct
{
struct CPersistentRing_struct *prev;
struct CPersistentRing_struct *next;
} CPersistentRing;
typedef struct { typedef struct {
cPersistent_HEAD cPersistent_HEAD
} cPersistentObject; } cPersistentObject;
...@@ -36,6 +45,9 @@ typedef struct { ...@@ -36,6 +45,9 @@ typedef struct {
getattrofunc getattro; getattrofunc getattro;
setattrofunc setattro; setattrofunc setattro;
int (*changed)(cPersistentObject*); int (*changed)(cPersistentObject*);
void (*accessed)(cPersistentObject*);
void (*ghostify)(cPersistentObject*);
void (*deallocated)(cPersistentObject*);
int (*setstate)(PyObject*); int (*setstate)(PyObject*);
pergetattr pergetattro; pergetattr pergetattro;
persetattr persetattro; persetattr persetattro;
...@@ -59,11 +71,13 @@ static cPersistenceCAPIstruct *cPersistenceCAPI; ...@@ -59,11 +71,13 @@ static cPersistenceCAPIstruct *cPersistenceCAPI;
#define PER_CHANGED(O) (cPersistenceCAPI->changed((cPersistentObject*)(O))) #define PER_CHANGED(O) (cPersistenceCAPI->changed((cPersistentObject*)(O)))
#define PER_ALLOW_DEACTIVATION(O) ((O)->state==cPersistent_STICKY_STATE && ((O)->state=cPersistent_UPTODATE_STATE)) #define PER_GHOSTIFY(O) (cPersistenceCAPI->ghostify((cPersistentObject*)(O)))
#define PER_ALLOW_DEACTIVATION(O) ((O)->state==cPersistent_STICKY_STATE && ((O)->state=cPersistent_UPTODATE_STATE))
#define PER_PREVENT_DEACTIVATION(O) ((O)->state==cPersistent_UPTODATE_STATE && ((O)->state=cPersistent_STICKY_STATE)) #define PER_PREVENT_DEACTIVATION(O) ((O)->state==cPersistent_UPTODATE_STATE && ((O)->state=cPersistent_STICKY_STATE))
#define PER_DEL(O) Py_XDECREF((O)->jar); Py_XDECREF((O)->oid); #define PER_DEL(O) (cPersistenceCAPI->deallocated((cPersistentObject*)(O)))
#define PER_USE(O) \ #define PER_USE(O) \
(((O)->state != cPersistent_GHOST_STATE \ (((O)->state != cPersistent_GHOST_STATE \
...@@ -71,7 +85,7 @@ static cPersistenceCAPIstruct *cPersistenceCAPI; ...@@ -71,7 +85,7 @@ static cPersistenceCAPIstruct *cPersistenceCAPI;
? (((O)->state==cPersistent_UPTODATE_STATE) \ ? (((O)->state==cPersistent_UPTODATE_STATE) \
? ((O)->state=cPersistent_STICKY_STATE) : 1) : 0) ? ((O)->state=cPersistent_STICKY_STATE) : 1) : 0)
#define PER_ACCESSED(O) ((O)->atime=((long)(time(NULL)/3))%65536) #define PER_ACCESSED(O) (cPersistenceCAPI->accessed((cPersistentObject*)(O)))
#endif #endif
......
This diff is collapsed.
...@@ -13,14 +13,14 @@ ...@@ -13,14 +13,14 @@
############################################################################## ##############################################################################
"""Database connection support """Database connection support
$Id: Connection.py,v 1.63 2002/02/11 23:40:42 gvanrossum Exp $""" $Id: Connection.py,v 1.64 2002/03/27 10:14:03 htrd Exp $"""
__version__='$Revision: 1.63 $'[11:-2] __version__='$Revision: 1.64 $'[11:-2]
from cPickleCache import PickleCache from cPickleCache import PickleCache, MUCH_RING_CHECKING
from POSException import ConflictError, ReadConflictError from POSException import ConflictError, ReadConflictError
from ExtensionClass import Base from ExtensionClass import Base
import ExportImport, TmpStore import ExportImport, TmpStore
from zLOG import LOG, ERROR, BLATHER from zLOG import LOG, ERROR, BLATHER, WARNING
from coptimizations import new_persistent_id from coptimizations import new_persistent_id
from ConflictResolution import ResolvedSerial from ConflictResolution import ResolvedSerial
...@@ -32,6 +32,11 @@ from types import StringType, ClassType ...@@ -32,6 +32,11 @@ from types import StringType, ClassType
global_code_timestamp = 0 global_code_timestamp = 0
if MUCH_RING_CHECKING:
# To get rid of this warning, change the define inside cPickleCache.c and recompile.
LOG('ZODB',WARNING, 'Using cPickleCache with low performance (but extra debugging checks)')
del MUCH_RING_CHECKING
def updateCodeTimestamp(): def updateCodeTimestamp():
''' '''
Called after changes are made to persistence-based classes. Called after changes are made to persistence-based classes.
...@@ -65,12 +70,35 @@ class Connection(ExportImport.ExportImport): ...@@ -65,12 +70,35 @@ class Connection(ExportImport.ExportImport):
"""Create a new Connection""" """Create a new Connection"""
self._version=version self._version=version
self._cache=cache=PickleCache(self, cache_size, cache_deactivate_after) self._cache=cache=PickleCache(self, cache_size, cache_deactivate_after)
if version:
# Caches for versions end up empty if the version
# is not used for a while. Non-version caches
# keep their content indefinitely.
self._cache.cache_drain_resistance = 100
self._incrgc=self.cacheGC=cache.incrgc self._incrgc=self.cacheGC=cache.incrgc
self._invalidated=d={} self._invalidated=d={}
self._invalid=d.has_key self._invalid=d.has_key
self._committed=[] self._committed=[]
self._code_timestamp = global_code_timestamp self._code_timestamp = global_code_timestamp
def _cache_items(self):
# find all items on the lru list
items = self._cache.lru_items()
# fine everything. some on the lru list, some not
everything = self._cache.cache_data
# remove those items that are on the lru list
for k,v in items:
del everything[k]
# return a list of [ghosts....not recently used.....recently used]
return everything.items() + items
def __repr__(self):
if self._version:
ver = ' (in version %s)' % `self._version`
else:
ver = ''
return '<Connection at %08x%s>' % (id(self),ver)
def _breakcr(self): def _breakcr(self):
try: del self._cache try: del self._cache
except: pass except: pass
...@@ -414,9 +442,9 @@ class Connection(ExportImport.ExportImport): ...@@ -414,9 +442,9 @@ class Connection(ExportImport.ExportImport):
for oid in creating: for oid in creating:
o=cache_get(oid, None) o=cache_get(oid, None)
if o is not None: if o is not None:
del cache[oid]
del o._p_jar del o._p_jar
del o._p_oid del o._p_oid
del cache[oid]
#XXX #XXX
...@@ -441,9 +469,14 @@ class Connection(ExportImport.ExportImport): ...@@ -441,9 +469,14 @@ class Connection(ExportImport.ExportImport):
def root(self): return self['\0\0\0\0\0\0\0\0'] def root(self): return self['\0\0\0\0\0\0\0\0']
def setstate(self, object): def setstate(self, object):
oid=object._p_oid
if self._storage is None:
msg = "Shouldn't load state for %s when the connection is closed" % `oid`
LOG('ZODB',ERROR, msg)
raise RuntimeError(msg)
try: try:
oid=object._p_oid
p, serial = self._storage.load(oid, self._version) p, serial = self._storage.load(oid, self._version)
# XXX this is quite conservative! # XXX this is quite conservative!
......
...@@ -13,8 +13,8 @@ ...@@ -13,8 +13,8 @@
############################################################################## ##############################################################################
"""Database objects """Database objects
$Id: DB.py,v 1.39 2002/02/11 23:40:42 gvanrossum Exp $""" $Id: DB.py,v 1.40 2002/03/27 10:14:04 htrd Exp $"""
__version__='$Revision: 1.39 $'[11:-2] __version__='$Revision: 1.40 $'[11:-2]
import cPickle, cStringIO, sys, POSException, UndoLogCompatible import cPickle, cStringIO, sys, POSException, UndoLogCompatible
from Connection import Connection from Connection import Connection
...@@ -177,7 +177,7 @@ class DB(UndoLogCompatible.UndoLogCompatible): ...@@ -177,7 +177,7 @@ class DB(UndoLogCompatible.UndoLogCompatible):
def f(con, detail=detail, rc=sys.getrefcount, conn_no=conn_no): def f(con, detail=detail, rc=sys.getrefcount, conn_no=conn_no):
conn_no[0] = conn_no[0] + 1 conn_no[0] = conn_no[0] + 1
cn = conn_no[0] cn = conn_no[0]
for oid, ob in con._cache.items(): for oid, ob in con._cache_items():
id='' id=''
if hasattr(ob,'__dict__'): if hasattr(ob,'__dict__'):
d=ob.__dict__ d=ob.__dict__
...@@ -224,11 +224,21 @@ class DB(UndoLogCompatible.UndoLogCompatible): ...@@ -224,11 +224,21 @@ class DB(UndoLogCompatible.UndoLogCompatible):
def cacheSize(self): def cacheSize(self):
m=[0] m=[0]
def f(con, m=m): def f(con, m=m):
m[0]=m[0]+len(con._cache) m[0]=m[0]+con._cache.cache_non_ghost_count
self._connectionMap(f) self._connectionMap(f)
return m[0] return m[0]
def cacheDetailSize(self):
m=[]
def f(con, m=m):
m.append({'connection':repr(con),
'ngsize':con._cache.cache_non_ghost_count,
'size':len(con._cache)})
self._connectionMap(f)
m.sort()
return m
def close(self): self._storage.close() def close(self): self._storage.close()
def commitVersion(self, source, destination=''): def commitVersion(self, source, destination=''):
......
...@@ -14,11 +14,21 @@ ...@@ -14,11 +14,21 @@
static char cPersistence_doc_string[] = static char cPersistence_doc_string[] =
"Defines Persistent mixin class for persistent objects.\n" "Defines Persistent mixin class for persistent objects.\n"
"\n" "\n"
"$Id: cPersistence.c,v 1.50 2002/03/08 18:36:13 jeremy Exp $\n"; "$Id: cPersistence.c,v 1.51 2002/03/27 10:14:04 htrd Exp $\n";
#include <string.h> #include <string.h>
#include "cPersistence.h" #include "cPersistence.h"
/* the layout of this struct is the same as the start of ccobject in cPickleCache.c */
struct ccobject_head_struct {
PyObject_HEAD
CPersistentRing ring_home;
int non_ghost_count;
};
#define HOME(O) ((!((O)->cache))?(NULL): (&(((struct ccobject_head_struct *)((O)->cache))->ring_home)) )
#define NON_GHOST_COUNT(O) ((!((O)->cache))?(NULL): (&(((struct ccobject_head_struct *)((O)->cache))->non_ghost_count)) )
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V) #define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
...@@ -112,21 +122,82 @@ if(self->state < 0 && self->jar) \ ...@@ -112,21 +122,82 @@ if(self->state < 0 && self->jar) \
{ \ { \
PyObject *r; \ PyObject *r; \
\ \
int *count = NON_GHOST_COUNT(self); \
if(count) \
{ \
(*count)++; \
self->ring.next = HOME(self); \
self->ring.prev = HOME(self)->prev; \
HOME(self)->prev->next = &self->ring; \
HOME(self)->prev = &self->ring; \
Py_INCREF(self); \
} \
self->state=cPersistent_CHANGED_STATE; \ self->state=cPersistent_CHANGED_STATE; \
UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self)) \ UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self)) \
{ \ { \
self->state=cPersistent_GHOST_STATE; \ ghostify(self); \
return ER; \ return ER; \
} \ } \
self->state=cPersistent_UPTODATE_STATE; \ self->state=cPersistent_UPTODATE_STATE; \
Py_DECREF(r); \ Py_DECREF(r); \
} }
#define KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self) \
if(HOME(self) && self->state>=0) { \
self->ring.prev->next = self->ring.next; \
self->ring.next->prev = self->ring.prev; \
self->ring.next = HOME(self); \
self->ring.prev = HOME(self)->prev; \
HOME(self)->prev->next = &self->ring; \
HOME(self)->prev = &self->ring; }
/****************************************************************************/ /****************************************************************************/
staticforward PyExtensionClass Pertype; staticforward PyExtensionClass Pertype;
static void
accessed(cPersistentObject *self)
{
KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
}
static void
ghostify(cPersistentObject *self)
{
int *count;
count = NON_GHOST_COUNT(self);
if(count && (self->state>=0))
{
(*count)--;
self->ring.next->prev = self->ring.prev;
self->ring.prev->next = self->ring.next;
self->ring.prev = NULL;
self->ring.next = NULL;
self->state = cPersistent_GHOST_STATE;
Py_DECREF(self);
}
else
{
self->state = cPersistent_GHOST_STATE;
}
}
static void
deallocated(cPersistentObject *self)
{
if(self->state>=0) ghostify(self);
if(self->cache)
{
PyObject *v=PyObject_CallMethod(self->cache,"_oid_unreferenced","O",self->oid);
if(!v) PyErr_Clear(); /* and explode later */
Py_XDECREF(v);
}
Py_XDECREF(self->jar);
Py_XDECREF(self->oid);
}
static int static int
changed(cPersistentObject *self) changed(cPersistentObject *self)
{ {
...@@ -185,7 +256,7 @@ Per___changed__(cPersistentObject *self, PyObject *args) ...@@ -185,7 +256,7 @@ Per___changed__(cPersistentObject *self, PyObject *args)
static PyObject * static PyObject *
Per__p_deactivate(cPersistentObject *self, PyObject *args) Per__p_deactivate(cPersistentObject *self, PyObject *args)
{ {
PyObject *dict; PyObject *dict,*dict2=NULL;
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
if (idebug_log < 0) call_debug("reinit",self); if (idebug_log < 0) call_debug("reinit",self);
...@@ -197,13 +268,22 @@ Per__p_deactivate(cPersistentObject *self, PyObject *args) ...@@ -197,13 +268,22 @@ Per__p_deactivate(cPersistentObject *self, PyObject *args)
if (self->state==cPersistent_UPTODATE_STATE && self->jar && if (self->state==cPersistent_UPTODATE_STATE && self->jar &&
HasInstDict(self) && (dict=INSTANCE_DICT(self))) HasInstDict(self) && (dict=INSTANCE_DICT(self)))
{ {
dict2 = PyDict_Copy(dict);
PyDict_Clear(dict); PyDict_Clear(dict);
/* Note that we need to set to ghost state unless we are /* Note that we need to set to ghost state unless we are
called directly. Methods that override this need to called directly. Methods that override this need to
do the same! */ do the same! */
self->state=cPersistent_GHOST_STATE; ghostify(self);
} }
/* need to delay releasing the last reference on instance attributes
until after we have finished accounting for losing our state */
if(dict2)
{
PyDict_Clear(dict2);
Py_DECREF(dict2);
}
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -333,8 +413,8 @@ Per_dealloc(cPersistentObject *self) ...@@ -333,8 +413,8 @@ Per_dealloc(cPersistentObject *self)
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
if(idebug_log < 0) call_debug("del",self); if(idebug_log < 0) call_debug("del",self);
#endif #endif
Py_XDECREF(self->jar); deallocated(self);
Py_XDECREF(self->oid); Py_XDECREF(self->cache);
Py_DECREF(self->ob_type); Py_DECREF(self->ob_type);
PyObject_DEL(self); PyObject_DEL(self);
} }
...@@ -387,7 +467,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name, ...@@ -387,7 +467,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
{ {
UPDATE_STATE_IF_NECESSARY(self, NULL); UPDATE_STATE_IF_NECESSARY(self, NULL);
self->atime=((long)(time(NULL)/3))%65536; KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
if (self->serial[7]=='\0' && self->serial[6]=='\0' && if (self->serial[7]=='\0' && self->serial[6]=='\0' &&
self->serial[5]=='\0' && self->serial[4]=='\0' && self->serial[5]=='\0' && self->serial[4]=='\0' &&
...@@ -419,7 +499,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name, ...@@ -419,7 +499,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
{ {
UPDATE_STATE_IF_NECESSARY(self, NULL); UPDATE_STATE_IF_NECESSARY(self, NULL);
self->atime=((long)(time(NULL)/3))%65536; KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
} }
return getattrf((PyObject *)self, oname); return getattrf((PyObject *)self, oname);
...@@ -466,6 +546,21 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -466,6 +546,21 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
{ {
if(name[3]=='o' && name[4]=='i' && name[5]=='d' && ! name[6]) if(name[3]=='o' && name[4]=='i' && name[5]=='d' && ! name[6])
{ {
if(HOME(self))
{
int result;
if(!v)
{
PyErr_SetString(PyExc_ValueError,"can not delete the oid of a cached object");
return -1;
}
if(PyObject_Cmp(self->oid,v,&result)<0) return -1;
if(result)
{
PyErr_SetString(PyExc_ValueError,"can not change the oid of a cached object");
return -1;
}
}
Py_XINCREF(v); Py_XINCREF(v);
ASSIGN(self->oid, v); ASSIGN(self->oid, v);
return 0; return 0;
...@@ -509,7 +604,6 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -509,7 +604,6 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
v=PyObject_GetAttr(OBJECT(self), py__p_deactivate); v=PyObject_GetAttr(OBJECT(self), py__p_deactivate);
if (v) { ASSIGN(v, PyObject_CallObject(v, NULL)); } if (v) { ASSIGN(v, PyObject_CallObject(v, NULL)); }
if (v) { Py_DECREF(v); } if (v) { Py_DECREF(v); }
self->state=cPersistent_GHOST_STATE;
return 0; return 0;
} }
if (PyObject_IsTrue(v)) return changed(self); if (PyObject_IsTrue(v)) return changed(self);
...@@ -521,8 +615,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -521,8 +615,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
{ {
UPDATE_STATE_IF_NECESSARY(self, -1); UPDATE_STATE_IF_NECESSARY(self, -1);
/* Record access times */ KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
self->atime=((long)(time(NULL)/3))%65536;
if((! (*name=='_' && name[1]=='v' && name[2]=='_')) if((! (*name=='_' && name[1]=='v' && name[2]=='_'))
&& (self->state != cPersistent_CHANGED_STATE && self->jar) && (self->state != cPersistent_CHANGED_STATE && self->jar)
...@@ -680,9 +773,11 @@ truecPersistenceCAPI = { ...@@ -680,9 +773,11 @@ truecPersistenceCAPI = {
(getattrofunc)Per_getattro, /*tp_getattr with object key*/ (getattrofunc)Per_getattro, /*tp_getattr with object key*/
(setattrofunc)Per_setattro, /*tp_setattr with object key*/ (setattrofunc)Per_setattro, /*tp_setattr with object key*/
changed, changed,
accessed,
ghostify,
deallocated,
(intfunctionwithpythonarg)Per_setstate, (intfunctionwithpythonarg)Per_setstate,
(pergetattr)Per_getattr, (pergetattr)Per_getattr,
(persetattr)_setattro,
}; };
void void
......
...@@ -18,12 +18,21 @@ ...@@ -18,12 +18,21 @@
#include "ExtensionClass.h" #include "ExtensionClass.h"
#include <time.h> #include <time.h>
#define cPersistent_HEAD PyObject_HEAD PyObject *jar, *oid; char serial[8]; unsigned short atime; signed char state; unsigned char reserved;
#define cPersistent_HEAD PyObject_HEAD PyObject *jar, *oid, *cache; CPersistentRing ring; char serial[8]; signed char state; unsigned char reserved[3];
#define cPersistent_GHOST_STATE -1 #define cPersistent_GHOST_STATE -1
#define cPersistent_UPTODATE_STATE 0 #define cPersistent_UPTODATE_STATE 0
#define cPersistent_CHANGED_STATE 1 #define cPersistent_CHANGED_STATE 1
#define cPersistent_STICKY_STATE 2 #define cPersistent_STICKY_STATE 2
struct ccobject_head_struct;
typedef struct CPersistentRing_struct
{
struct CPersistentRing_struct *prev;
struct CPersistentRing_struct *next;
} CPersistentRing;
typedef struct { typedef struct {
cPersistent_HEAD cPersistent_HEAD
} cPersistentObject; } cPersistentObject;
...@@ -36,6 +45,9 @@ typedef struct { ...@@ -36,6 +45,9 @@ typedef struct {
getattrofunc getattro; getattrofunc getattro;
setattrofunc setattro; setattrofunc setattro;
int (*changed)(cPersistentObject*); int (*changed)(cPersistentObject*);
void (*accessed)(cPersistentObject*);
void (*ghostify)(cPersistentObject*);
void (*deallocated)(cPersistentObject*);
int (*setstate)(PyObject*); int (*setstate)(PyObject*);
pergetattr pergetattro; pergetattr pergetattro;
persetattr persetattro; persetattr persetattro;
...@@ -59,11 +71,13 @@ static cPersistenceCAPIstruct *cPersistenceCAPI; ...@@ -59,11 +71,13 @@ static cPersistenceCAPIstruct *cPersistenceCAPI;
#define PER_CHANGED(O) (cPersistenceCAPI->changed((cPersistentObject*)(O))) #define PER_CHANGED(O) (cPersistenceCAPI->changed((cPersistentObject*)(O)))
#define PER_ALLOW_DEACTIVATION(O) ((O)->state==cPersistent_STICKY_STATE && ((O)->state=cPersistent_UPTODATE_STATE)) #define PER_GHOSTIFY(O) (cPersistenceCAPI->ghostify((cPersistentObject*)(O)))
#define PER_ALLOW_DEACTIVATION(O) ((O)->state==cPersistent_STICKY_STATE && ((O)->state=cPersistent_UPTODATE_STATE))
#define PER_PREVENT_DEACTIVATION(O) ((O)->state==cPersistent_UPTODATE_STATE && ((O)->state=cPersistent_STICKY_STATE)) #define PER_PREVENT_DEACTIVATION(O) ((O)->state==cPersistent_UPTODATE_STATE && ((O)->state=cPersistent_STICKY_STATE))
#define PER_DEL(O) Py_XDECREF((O)->jar); Py_XDECREF((O)->oid); #define PER_DEL(O) (cPersistenceCAPI->deallocated((cPersistentObject*)(O)))
#define PER_USE(O) \ #define PER_USE(O) \
(((O)->state != cPersistent_GHOST_STATE \ (((O)->state != cPersistent_GHOST_STATE \
...@@ -71,7 +85,7 @@ static cPersistenceCAPIstruct *cPersistenceCAPI; ...@@ -71,7 +85,7 @@ static cPersistenceCAPIstruct *cPersistenceCAPI;
? (((O)->state==cPersistent_UPTODATE_STATE) \ ? (((O)->state==cPersistent_UPTODATE_STATE) \
? ((O)->state=cPersistent_STICKY_STATE) : 1) : 0) ? ((O)->state=cPersistent_STICKY_STATE) : 1) : 0)
#define PER_ACCESSED(O) ((O)->atime=((long)(time(NULL)/3))%65536) #define PER_ACCESSED(O) (cPersistenceCAPI->accessed((cPersistentObject*)(O)))
#endif #endif
......
This diff is collapsed.
...@@ -14,11 +14,21 @@ ...@@ -14,11 +14,21 @@
static char cPersistence_doc_string[] = static char cPersistence_doc_string[] =
"Defines Persistent mixin class for persistent objects.\n" "Defines Persistent mixin class for persistent objects.\n"
"\n" "\n"
"$Id: cPersistence.c,v 1.50 2002/03/08 18:36:13 jeremy Exp $\n"; "$Id: cPersistence.c,v 1.51 2002/03/27 10:14:04 htrd Exp $\n";
#include <string.h> #include <string.h>
#include "cPersistence.h" #include "cPersistence.h"
/* the layout of this struct is the same as the start of ccobject in cPickleCache.c */
struct ccobject_head_struct {
PyObject_HEAD
CPersistentRing ring_home;
int non_ghost_count;
};
#define HOME(O) ((!((O)->cache))?(NULL): (&(((struct ccobject_head_struct *)((O)->cache))->ring_home)) )
#define NON_GHOST_COUNT(O) ((!((O)->cache))?(NULL): (&(((struct ccobject_head_struct *)((O)->cache))->non_ghost_count)) )
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V) #define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
...@@ -112,21 +122,82 @@ if(self->state < 0 && self->jar) \ ...@@ -112,21 +122,82 @@ if(self->state < 0 && self->jar) \
{ \ { \
PyObject *r; \ PyObject *r; \
\ \
int *count = NON_GHOST_COUNT(self); \
if(count) \
{ \
(*count)++; \
self->ring.next = HOME(self); \
self->ring.prev = HOME(self)->prev; \
HOME(self)->prev->next = &self->ring; \
HOME(self)->prev = &self->ring; \
Py_INCREF(self); \
} \
self->state=cPersistent_CHANGED_STATE; \ self->state=cPersistent_CHANGED_STATE; \
UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self)) \ UNLESS(r=callmethod1(self->jar,py_setstate,(PyObject*)self)) \
{ \ { \
self->state=cPersistent_GHOST_STATE; \ ghostify(self); \
return ER; \ return ER; \
} \ } \
self->state=cPersistent_UPTODATE_STATE; \ self->state=cPersistent_UPTODATE_STATE; \
Py_DECREF(r); \ Py_DECREF(r); \
} }
#define KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self) \
if(HOME(self) && self->state>=0) { \
self->ring.prev->next = self->ring.next; \
self->ring.next->prev = self->ring.prev; \
self->ring.next = HOME(self); \
self->ring.prev = HOME(self)->prev; \
HOME(self)->prev->next = &self->ring; \
HOME(self)->prev = &self->ring; }
/****************************************************************************/ /****************************************************************************/
staticforward PyExtensionClass Pertype; staticforward PyExtensionClass Pertype;
static void
accessed(cPersistentObject *self)
{
KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
}
static void
ghostify(cPersistentObject *self)
{
int *count;
count = NON_GHOST_COUNT(self);
if(count && (self->state>=0))
{
(*count)--;
self->ring.next->prev = self->ring.prev;
self->ring.prev->next = self->ring.next;
self->ring.prev = NULL;
self->ring.next = NULL;
self->state = cPersistent_GHOST_STATE;
Py_DECREF(self);
}
else
{
self->state = cPersistent_GHOST_STATE;
}
}
static void
deallocated(cPersistentObject *self)
{
if(self->state>=0) ghostify(self);
if(self->cache)
{
PyObject *v=PyObject_CallMethod(self->cache,"_oid_unreferenced","O",self->oid);
if(!v) PyErr_Clear(); /* and explode later */
Py_XDECREF(v);
}
Py_XDECREF(self->jar);
Py_XDECREF(self->oid);
}
static int static int
changed(cPersistentObject *self) changed(cPersistentObject *self)
{ {
...@@ -185,7 +256,7 @@ Per___changed__(cPersistentObject *self, PyObject *args) ...@@ -185,7 +256,7 @@ Per___changed__(cPersistentObject *self, PyObject *args)
static PyObject * static PyObject *
Per__p_deactivate(cPersistentObject *self, PyObject *args) Per__p_deactivate(cPersistentObject *self, PyObject *args)
{ {
PyObject *dict; PyObject *dict,*dict2=NULL;
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
if (idebug_log < 0) call_debug("reinit",self); if (idebug_log < 0) call_debug("reinit",self);
...@@ -197,13 +268,22 @@ Per__p_deactivate(cPersistentObject *self, PyObject *args) ...@@ -197,13 +268,22 @@ Per__p_deactivate(cPersistentObject *self, PyObject *args)
if (self->state==cPersistent_UPTODATE_STATE && self->jar && if (self->state==cPersistent_UPTODATE_STATE && self->jar &&
HasInstDict(self) && (dict=INSTANCE_DICT(self))) HasInstDict(self) && (dict=INSTANCE_DICT(self)))
{ {
dict2 = PyDict_Copy(dict);
PyDict_Clear(dict); PyDict_Clear(dict);
/* Note that we need to set to ghost state unless we are /* Note that we need to set to ghost state unless we are
called directly. Methods that override this need to called directly. Methods that override this need to
do the same! */ do the same! */
self->state=cPersistent_GHOST_STATE; ghostify(self);
} }
/* need to delay releasing the last reference on instance attributes
until after we have finished accounting for losing our state */
if(dict2)
{
PyDict_Clear(dict2);
Py_DECREF(dict2);
}
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -333,8 +413,8 @@ Per_dealloc(cPersistentObject *self) ...@@ -333,8 +413,8 @@ Per_dealloc(cPersistentObject *self)
#ifdef DEBUG_LOG #ifdef DEBUG_LOG
if(idebug_log < 0) call_debug("del",self); if(idebug_log < 0) call_debug("del",self);
#endif #endif
Py_XDECREF(self->jar); deallocated(self);
Py_XDECREF(self->oid); Py_XDECREF(self->cache);
Py_DECREF(self->ob_type); Py_DECREF(self->ob_type);
PyObject_DEL(self); PyObject_DEL(self);
} }
...@@ -387,7 +467,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name, ...@@ -387,7 +467,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
{ {
UPDATE_STATE_IF_NECESSARY(self, NULL); UPDATE_STATE_IF_NECESSARY(self, NULL);
self->atime=((long)(time(NULL)/3))%65536; KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
if (self->serial[7]=='\0' && self->serial[6]=='\0' && if (self->serial[7]=='\0' && self->serial[6]=='\0' &&
self->serial[5]=='\0' && self->serial[4]=='\0' && self->serial[5]=='\0' && self->serial[4]=='\0' &&
...@@ -419,7 +499,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name, ...@@ -419,7 +499,7 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
{ {
UPDATE_STATE_IF_NECESSARY(self, NULL); UPDATE_STATE_IF_NECESSARY(self, NULL);
self->atime=((long)(time(NULL)/3))%65536; KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
} }
return getattrf((PyObject *)self, oname); return getattrf((PyObject *)self, oname);
...@@ -466,6 +546,21 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -466,6 +546,21 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
{ {
if(name[3]=='o' && name[4]=='i' && name[5]=='d' && ! name[6]) if(name[3]=='o' && name[4]=='i' && name[5]=='d' && ! name[6])
{ {
if(HOME(self))
{
int result;
if(!v)
{
PyErr_SetString(PyExc_ValueError,"can not delete the oid of a cached object");
return -1;
}
if(PyObject_Cmp(self->oid,v,&result)<0) return -1;
if(result)
{
PyErr_SetString(PyExc_ValueError,"can not change the oid of a cached object");
return -1;
}
}
Py_XINCREF(v); Py_XINCREF(v);
ASSIGN(self->oid, v); ASSIGN(self->oid, v);
return 0; return 0;
...@@ -509,7 +604,6 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -509,7 +604,6 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
v=PyObject_GetAttr(OBJECT(self), py__p_deactivate); v=PyObject_GetAttr(OBJECT(self), py__p_deactivate);
if (v) { ASSIGN(v, PyObject_CallObject(v, NULL)); } if (v) { ASSIGN(v, PyObject_CallObject(v, NULL)); }
if (v) { Py_DECREF(v); } if (v) { Py_DECREF(v); }
self->state=cPersistent_GHOST_STATE;
return 0; return 0;
} }
if (PyObject_IsTrue(v)) return changed(self); if (PyObject_IsTrue(v)) return changed(self);
...@@ -521,8 +615,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -521,8 +615,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
{ {
UPDATE_STATE_IF_NECESSARY(self, -1); UPDATE_STATE_IF_NECESSARY(self, -1);
/* Record access times */ KEEP_THIS_ONE_AROUND_FOR_A_WHILE(self);
self->atime=((long)(time(NULL)/3))%65536;
if((! (*name=='_' && name[1]=='v' && name[2]=='_')) if((! (*name=='_' && name[1]=='v' && name[2]=='_'))
&& (self->state != cPersistent_CHANGED_STATE && self->jar) && (self->state != cPersistent_CHANGED_STATE && self->jar)
...@@ -680,9 +773,11 @@ truecPersistenceCAPI = { ...@@ -680,9 +773,11 @@ truecPersistenceCAPI = {
(getattrofunc)Per_getattro, /*tp_getattr with object key*/ (getattrofunc)Per_getattro, /*tp_getattr with object key*/
(setattrofunc)Per_setattro, /*tp_setattr with object key*/ (setattrofunc)Per_setattro, /*tp_setattr with object key*/
changed, changed,
accessed,
ghostify,
deallocated,
(intfunctionwithpythonarg)Per_setstate, (intfunctionwithpythonarg)Per_setstate,
(pergetattr)Per_getattr, (pergetattr)Per_getattr,
(persetattr)_setattro,
}; };
void void
......
...@@ -18,12 +18,21 @@ ...@@ -18,12 +18,21 @@
#include "ExtensionClass.h" #include "ExtensionClass.h"
#include <time.h> #include <time.h>
#define cPersistent_HEAD PyObject_HEAD PyObject *jar, *oid; char serial[8]; unsigned short atime; signed char state; unsigned char reserved;
#define cPersistent_HEAD PyObject_HEAD PyObject *jar, *oid, *cache; CPersistentRing ring; char serial[8]; signed char state; unsigned char reserved[3];
#define cPersistent_GHOST_STATE -1 #define cPersistent_GHOST_STATE -1
#define cPersistent_UPTODATE_STATE 0 #define cPersistent_UPTODATE_STATE 0
#define cPersistent_CHANGED_STATE 1 #define cPersistent_CHANGED_STATE 1
#define cPersistent_STICKY_STATE 2 #define cPersistent_STICKY_STATE 2
struct ccobject_head_struct;
typedef struct CPersistentRing_struct
{
struct CPersistentRing_struct *prev;
struct CPersistentRing_struct *next;
} CPersistentRing;
typedef struct { typedef struct {
cPersistent_HEAD cPersistent_HEAD
} cPersistentObject; } cPersistentObject;
...@@ -36,6 +45,9 @@ typedef struct { ...@@ -36,6 +45,9 @@ typedef struct {
getattrofunc getattro; getattrofunc getattro;
setattrofunc setattro; setattrofunc setattro;
int (*changed)(cPersistentObject*); int (*changed)(cPersistentObject*);
void (*accessed)(cPersistentObject*);
void (*ghostify)(cPersistentObject*);
void (*deallocated)(cPersistentObject*);
int (*setstate)(PyObject*); int (*setstate)(PyObject*);
pergetattr pergetattro; pergetattr pergetattro;
persetattr persetattro; persetattr persetattro;
...@@ -59,11 +71,13 @@ static cPersistenceCAPIstruct *cPersistenceCAPI; ...@@ -59,11 +71,13 @@ static cPersistenceCAPIstruct *cPersistenceCAPI;
#define PER_CHANGED(O) (cPersistenceCAPI->changed((cPersistentObject*)(O))) #define PER_CHANGED(O) (cPersistenceCAPI->changed((cPersistentObject*)(O)))
#define PER_ALLOW_DEACTIVATION(O) ((O)->state==cPersistent_STICKY_STATE && ((O)->state=cPersistent_UPTODATE_STATE)) #define PER_GHOSTIFY(O) (cPersistenceCAPI->ghostify((cPersistentObject*)(O)))
#define PER_ALLOW_DEACTIVATION(O) ((O)->state==cPersistent_STICKY_STATE && ((O)->state=cPersistent_UPTODATE_STATE))
#define PER_PREVENT_DEACTIVATION(O) ((O)->state==cPersistent_UPTODATE_STATE && ((O)->state=cPersistent_STICKY_STATE)) #define PER_PREVENT_DEACTIVATION(O) ((O)->state==cPersistent_UPTODATE_STATE && ((O)->state=cPersistent_STICKY_STATE))
#define PER_DEL(O) Py_XDECREF((O)->jar); Py_XDECREF((O)->oid); #define PER_DEL(O) (cPersistenceCAPI->deallocated((cPersistentObject*)(O)))
#define PER_USE(O) \ #define PER_USE(O) \
(((O)->state != cPersistent_GHOST_STATE \ (((O)->state != cPersistent_GHOST_STATE \
...@@ -71,7 +85,7 @@ static cPersistenceCAPIstruct *cPersistenceCAPI; ...@@ -71,7 +85,7 @@ static cPersistenceCAPIstruct *cPersistenceCAPI;
? (((O)->state==cPersistent_UPTODATE_STATE) \ ? (((O)->state==cPersistent_UPTODATE_STATE) \
? ((O)->state=cPersistent_STICKY_STATE) : 1) : 0) ? ((O)->state=cPersistent_STICKY_STATE) : 1) : 0)
#define PER_ACCESSED(O) ((O)->atime=((long)(time(NULL)/3))%65536) #define PER_ACCESSED(O) (cPersistenceCAPI->accessed((cPersistentObject*)(O)))
#endif #endif
......
This diff is collapsed.
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