From 41dc25c34cd03b9c761e49f44a9ecf6ff0198e77 Mon Sep 17 00:00:00 2001 From: Jeremy Hylton <jeremy@svn.zope.org> Date: Wed, 2 Apr 2003 16:50:49 +0000 Subject: [PATCH] Restore cache behavior for unreferenced by recently used objects. The implementation is to make the reference in the cache "ring" a new reference rather than a borrowed reference. It is the intent of the cache to keep N recently used objects in memory, regardless of whether they are currently referenced. The goal is to avoid the cost of recreating the objects, based on the assumption that they are likely to be used again soon. --- src/Persistence/cPersistence.c | 5 ++++- src/Persistence/cPickleCache.c | 21 +++++++++++++-------- src/ZODB/cPersistence.c | 5 ++++- src/ZODB/cPickleCache.c | 21 +++++++++++++-------- src/persistent/cPersistence.c | 5 ++++- src/persistent/cPickleCache.c | 21 +++++++++++++-------- 6 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/Persistence/cPersistence.c b/src/Persistence/cPersistence.c index 421d776b..323f87ad 100644 --- a/src/Persistence/cPersistence.c +++ b/src/Persistence/cPersistence.c @@ -14,7 +14,7 @@ static char cPersistence_doc_string[] = "Defines Persistent mixin class for persistent objects.\n" "\n" -"$Id: cPersistence.c,v 1.67 2003/04/01 17:33:23 jeremy Exp $\n"; +"$Id: cPersistence.c,v 1.68 2003/04/02 16:50:49 jeremy Exp $\n"; #include "cPersistence.h" @@ -131,6 +131,7 @@ unghostify(cPersistentObject *self) self->ring.prev = home->prev; home->prev->next = &self->ring; home->prev = &self->ring; + Py_INCREF(self); } self->state = cPersistent_CHANGED_STATE; /* Call the object's __setstate__() */ @@ -184,6 +185,8 @@ ghostify(cPersistentObject *self) self->ring.prev = NULL; self->ring.next = NULL; self->state = cPersistent_GHOST_STATE; + /* self->ring held a reference to the object. */ + Py_DECREF(self); } static void diff --git a/src/Persistence/cPickleCache.c b/src/Persistence/cPickleCache.c index fcda456d..b4a52b65 100644 --- a/src/Persistence/cPickleCache.c +++ b/src/Persistence/cPickleCache.c @@ -53,10 +53,12 @@ persistent classes (such as BTrees). Regime 3: Non-Ghost Objects -Non-ghost objects are stored in two data structures. Firstly, in the -dictionary along with everything else, with a *strong* reference. -Secondly, they are stored in a doubly-linked-list which encodes the -order in which these objects have been most recently used. +Non-ghost objects are stored in two data structures: the dictionary +mapping oids to objects and a doubly-linked list that encodes the +order in which the objects were accessed. The dictionary reference is +borrowed, as it is for ghosts. The list reference is a new reference; +the list stores recently used objects, even if they are otherwise +unreferenced, to avoid loading the object from the database again. The doubly-link-list nodes contain next and previous pointers linking together the cache and all non-ghost persistent objects. @@ -88,7 +90,7 @@ process must skip such objects, rather than deactivating them. static char cPickleCache_doc_string[] = "Defines the PickleCache used by ZODB Connection objects.\n" "\n" -"$Id: cPickleCache.c,v 1.79 2003/04/01 18:49:43 jeremy Exp $\n"; +"$Id: cPickleCache.c,v 1.80 2003/04/02 16:50:49 jeremy Exp $\n"; #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define UNLESS(E) if(!(E)) @@ -762,8 +764,7 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) if (PyDict_SetItem(self->data, key, v) < 0) return -1; - /* Remove the reference used by the dict. The cache should only - have borrowed references to objects. */ + /* the dict should have a borrowed reference */ Py_DECREF(v); p = (cPersistentObject *)v; @@ -771,12 +772,14 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) p->cache = (PerCache *)self; if (p->state >= 0) { /* insert this non-ghost object into the ring just - behind the home position */ + behind the home position. */ self->non_ghost_count++; p->ring.next = &self->ring_home; p->ring.prev = self->ring_home.prev; self->ring_home.prev->next = &p->ring; self->ring_home.prev = &p->ring; + /* this list should have a new reference to the object */ + Py_INCREF(v); } return 0; } @@ -802,6 +805,8 @@ cc_del_item(ccobject *self, PyObject *key) p->ring.prev->next = p->ring.next; p->ring.prev = NULL; p->ring.next = NULL; + /* The DelItem below will account for the reference + held by the list. */ } else { /* This is a ghost object, so we havent kept a reference count on it. For it have stayed alive this long diff --git a/src/ZODB/cPersistence.c b/src/ZODB/cPersistence.c index 421d776b..323f87ad 100644 --- a/src/ZODB/cPersistence.c +++ b/src/ZODB/cPersistence.c @@ -14,7 +14,7 @@ static char cPersistence_doc_string[] = "Defines Persistent mixin class for persistent objects.\n" "\n" -"$Id: cPersistence.c,v 1.67 2003/04/01 17:33:23 jeremy Exp $\n"; +"$Id: cPersistence.c,v 1.68 2003/04/02 16:50:49 jeremy Exp $\n"; #include "cPersistence.h" @@ -131,6 +131,7 @@ unghostify(cPersistentObject *self) self->ring.prev = home->prev; home->prev->next = &self->ring; home->prev = &self->ring; + Py_INCREF(self); } self->state = cPersistent_CHANGED_STATE; /* Call the object's __setstate__() */ @@ -184,6 +185,8 @@ ghostify(cPersistentObject *self) self->ring.prev = NULL; self->ring.next = NULL; self->state = cPersistent_GHOST_STATE; + /* self->ring held a reference to the object. */ + Py_DECREF(self); } static void diff --git a/src/ZODB/cPickleCache.c b/src/ZODB/cPickleCache.c index fcda456d..b4a52b65 100644 --- a/src/ZODB/cPickleCache.c +++ b/src/ZODB/cPickleCache.c @@ -53,10 +53,12 @@ persistent classes (such as BTrees). Regime 3: Non-Ghost Objects -Non-ghost objects are stored in two data structures. Firstly, in the -dictionary along with everything else, with a *strong* reference. -Secondly, they are stored in a doubly-linked-list which encodes the -order in which these objects have been most recently used. +Non-ghost objects are stored in two data structures: the dictionary +mapping oids to objects and a doubly-linked list that encodes the +order in which the objects were accessed. The dictionary reference is +borrowed, as it is for ghosts. The list reference is a new reference; +the list stores recently used objects, even if they are otherwise +unreferenced, to avoid loading the object from the database again. The doubly-link-list nodes contain next and previous pointers linking together the cache and all non-ghost persistent objects. @@ -88,7 +90,7 @@ process must skip such objects, rather than deactivating them. static char cPickleCache_doc_string[] = "Defines the PickleCache used by ZODB Connection objects.\n" "\n" -"$Id: cPickleCache.c,v 1.79 2003/04/01 18:49:43 jeremy Exp $\n"; +"$Id: cPickleCache.c,v 1.80 2003/04/02 16:50:49 jeremy Exp $\n"; #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define UNLESS(E) if(!(E)) @@ -762,8 +764,7 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) if (PyDict_SetItem(self->data, key, v) < 0) return -1; - /* Remove the reference used by the dict. The cache should only - have borrowed references to objects. */ + /* the dict should have a borrowed reference */ Py_DECREF(v); p = (cPersistentObject *)v; @@ -771,12 +772,14 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) p->cache = (PerCache *)self; if (p->state >= 0) { /* insert this non-ghost object into the ring just - behind the home position */ + behind the home position. */ self->non_ghost_count++; p->ring.next = &self->ring_home; p->ring.prev = self->ring_home.prev; self->ring_home.prev->next = &p->ring; self->ring_home.prev = &p->ring; + /* this list should have a new reference to the object */ + Py_INCREF(v); } return 0; } @@ -802,6 +805,8 @@ cc_del_item(ccobject *self, PyObject *key) p->ring.prev->next = p->ring.next; p->ring.prev = NULL; p->ring.next = NULL; + /* The DelItem below will account for the reference + held by the list. */ } else { /* This is a ghost object, so we havent kept a reference count on it. For it have stayed alive this long diff --git a/src/persistent/cPersistence.c b/src/persistent/cPersistence.c index 421d776b..323f87ad 100644 --- a/src/persistent/cPersistence.c +++ b/src/persistent/cPersistence.c @@ -14,7 +14,7 @@ static char cPersistence_doc_string[] = "Defines Persistent mixin class for persistent objects.\n" "\n" -"$Id: cPersistence.c,v 1.67 2003/04/01 17:33:23 jeremy Exp $\n"; +"$Id: cPersistence.c,v 1.68 2003/04/02 16:50:49 jeremy Exp $\n"; #include "cPersistence.h" @@ -131,6 +131,7 @@ unghostify(cPersistentObject *self) self->ring.prev = home->prev; home->prev->next = &self->ring; home->prev = &self->ring; + Py_INCREF(self); } self->state = cPersistent_CHANGED_STATE; /* Call the object's __setstate__() */ @@ -184,6 +185,8 @@ ghostify(cPersistentObject *self) self->ring.prev = NULL; self->ring.next = NULL; self->state = cPersistent_GHOST_STATE; + /* self->ring held a reference to the object. */ + Py_DECREF(self); } static void diff --git a/src/persistent/cPickleCache.c b/src/persistent/cPickleCache.c index fcda456d..b4a52b65 100644 --- a/src/persistent/cPickleCache.c +++ b/src/persistent/cPickleCache.c @@ -53,10 +53,12 @@ persistent classes (such as BTrees). Regime 3: Non-Ghost Objects -Non-ghost objects are stored in two data structures. Firstly, in the -dictionary along with everything else, with a *strong* reference. -Secondly, they are stored in a doubly-linked-list which encodes the -order in which these objects have been most recently used. +Non-ghost objects are stored in two data structures: the dictionary +mapping oids to objects and a doubly-linked list that encodes the +order in which the objects were accessed. The dictionary reference is +borrowed, as it is for ghosts. The list reference is a new reference; +the list stores recently used objects, even if they are otherwise +unreferenced, to avoid loading the object from the database again. The doubly-link-list nodes contain next and previous pointers linking together the cache and all non-ghost persistent objects. @@ -88,7 +90,7 @@ process must skip such objects, rather than deactivating them. static char cPickleCache_doc_string[] = "Defines the PickleCache used by ZODB Connection objects.\n" "\n" -"$Id: cPickleCache.c,v 1.79 2003/04/01 18:49:43 jeremy Exp $\n"; +"$Id: cPickleCache.c,v 1.80 2003/04/02 16:50:49 jeremy Exp $\n"; #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define UNLESS(E) if(!(E)) @@ -762,8 +764,7 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) if (PyDict_SetItem(self->data, key, v) < 0) return -1; - /* Remove the reference used by the dict. The cache should only - have borrowed references to objects. */ + /* the dict should have a borrowed reference */ Py_DECREF(v); p = (cPersistentObject *)v; @@ -771,12 +772,14 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) p->cache = (PerCache *)self; if (p->state >= 0) { /* insert this non-ghost object into the ring just - behind the home position */ + behind the home position. */ self->non_ghost_count++; p->ring.next = &self->ring_home; p->ring.prev = self->ring_home.prev; self->ring_home.prev->next = &p->ring; self->ring_home.prev = &p->ring; + /* this list should have a new reference to the object */ + Py_INCREF(v); } return 0; } @@ -802,6 +805,8 @@ cc_del_item(ccobject *self, PyObject *key) p->ring.prev->next = p->ring.next; p->ring.prev = NULL; p->ring.next = NULL; + /* The DelItem below will account for the reference + held by the list. */ } else { /* This is a ghost object, so we havent kept a reference count on it. For it have stayed alive this long -- 2.30.9