Commit 19830020 authored by Jeremy Hylton's avatar Jeremy Hylton

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.
parent 5a861fda
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
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.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" #include "cPersistence.h"
...@@ -131,6 +131,7 @@ unghostify(cPersistentObject *self) ...@@ -131,6 +131,7 @@ unghostify(cPersistentObject *self)
self->ring.prev = home->prev; self->ring.prev = home->prev;
home->prev->next = &self->ring; home->prev->next = &self->ring;
home->prev = &self->ring; home->prev = &self->ring;
Py_INCREF(self);
} }
self->state = cPersistent_CHANGED_STATE; self->state = cPersistent_CHANGED_STATE;
/* Call the object's __setstate__() */ /* Call the object's __setstate__() */
...@@ -184,6 +185,8 @@ ghostify(cPersistentObject *self) ...@@ -184,6 +185,8 @@ ghostify(cPersistentObject *self)
self->ring.prev = NULL; self->ring.prev = NULL;
self->ring.next = NULL; self->ring.next = NULL;
self->state = cPersistent_GHOST_STATE; self->state = cPersistent_GHOST_STATE;
/* self->ring held a reference to the object. */
Py_DECREF(self);
} }
static void static void
......
...@@ -53,10 +53,12 @@ persistent classes (such as BTrees). ...@@ -53,10 +53,12 @@ persistent classes (such as BTrees).
Regime 3: Non-Ghost Objects Regime 3: Non-Ghost Objects
Non-ghost objects are stored in two data structures. Firstly, in the Non-ghost objects are stored in two data structures: the dictionary
dictionary along with everything else, with a *strong* reference. mapping oids to objects and a doubly-linked list that encodes the
Secondly, they are stored in a doubly-linked-list which encodes the order in which the objects were accessed. The dictionary reference is
order in which these objects have been most recently used. 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 The doubly-link-list nodes contain next and previous pointers linking
together the cache and all non-ghost persistent objects. together the cache and all non-ghost persistent objects.
...@@ -88,7 +90,7 @@ process must skip such objects, rather than deactivating them. ...@@ -88,7 +90,7 @@ process must skip such objects, rather than deactivating them.
static char cPickleCache_doc_string[] = static char cPickleCache_doc_string[] =
"Defines the PickleCache used by ZODB Connection objects.\n" "Defines the PickleCache used by ZODB Connection objects.\n"
"\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 ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
...@@ -762,8 +764,7 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) ...@@ -762,8 +764,7 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v)
if (PyDict_SetItem(self->data, key, v) < 0) if (PyDict_SetItem(self->data, key, v) < 0)
return -1; return -1;
/* Remove the reference used by the dict. The cache should only /* the dict should have a borrowed reference */
have borrowed references to objects. */
Py_DECREF(v); Py_DECREF(v);
p = (cPersistentObject *)v; p = (cPersistentObject *)v;
...@@ -771,12 +772,14 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) ...@@ -771,12 +772,14 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v)
p->cache = (PerCache *)self; p->cache = (PerCache *)self;
if (p->state >= 0) { if (p->state >= 0) {
/* insert this non-ghost object into the ring just /* insert this non-ghost object into the ring just
behind the home position */ behind the home position. */
self->non_ghost_count++; self->non_ghost_count++;
p->ring.next = &self->ring_home; p->ring.next = &self->ring_home;
p->ring.prev = self->ring_home.prev; p->ring.prev = self->ring_home.prev;
self->ring_home.prev->next = &p->ring; self->ring_home.prev->next = &p->ring;
self->ring_home.prev = &p->ring; self->ring_home.prev = &p->ring;
/* this list should have a new reference to the object */
Py_INCREF(v);
} }
return 0; return 0;
} }
...@@ -802,6 +805,8 @@ cc_del_item(ccobject *self, PyObject *key) ...@@ -802,6 +805,8 @@ cc_del_item(ccobject *self, PyObject *key)
p->ring.prev->next = p->ring.next; p->ring.prev->next = p->ring.next;
p->ring.prev = NULL; p->ring.prev = NULL;
p->ring.next = NULL; p->ring.next = NULL;
/* The DelItem below will account for the reference
held by the list. */
} else { } else {
/* This is a ghost object, so we havent kept a reference /* This is a ghost object, so we havent kept a reference
count on it. For it have stayed alive this long count on it. For it have stayed alive this long
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
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.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" #include "cPersistence.h"
...@@ -131,6 +131,7 @@ unghostify(cPersistentObject *self) ...@@ -131,6 +131,7 @@ unghostify(cPersistentObject *self)
self->ring.prev = home->prev; self->ring.prev = home->prev;
home->prev->next = &self->ring; home->prev->next = &self->ring;
home->prev = &self->ring; home->prev = &self->ring;
Py_INCREF(self);
} }
self->state = cPersistent_CHANGED_STATE; self->state = cPersistent_CHANGED_STATE;
/* Call the object's __setstate__() */ /* Call the object's __setstate__() */
...@@ -184,6 +185,8 @@ ghostify(cPersistentObject *self) ...@@ -184,6 +185,8 @@ ghostify(cPersistentObject *self)
self->ring.prev = NULL; self->ring.prev = NULL;
self->ring.next = NULL; self->ring.next = NULL;
self->state = cPersistent_GHOST_STATE; self->state = cPersistent_GHOST_STATE;
/* self->ring held a reference to the object. */
Py_DECREF(self);
} }
static void static void
......
...@@ -53,10 +53,12 @@ persistent classes (such as BTrees). ...@@ -53,10 +53,12 @@ persistent classes (such as BTrees).
Regime 3: Non-Ghost Objects Regime 3: Non-Ghost Objects
Non-ghost objects are stored in two data structures. Firstly, in the Non-ghost objects are stored in two data structures: the dictionary
dictionary along with everything else, with a *strong* reference. mapping oids to objects and a doubly-linked list that encodes the
Secondly, they are stored in a doubly-linked-list which encodes the order in which the objects were accessed. The dictionary reference is
order in which these objects have been most recently used. 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 The doubly-link-list nodes contain next and previous pointers linking
together the cache and all non-ghost persistent objects. together the cache and all non-ghost persistent objects.
...@@ -88,7 +90,7 @@ process must skip such objects, rather than deactivating them. ...@@ -88,7 +90,7 @@ process must skip such objects, rather than deactivating them.
static char cPickleCache_doc_string[] = static char cPickleCache_doc_string[] =
"Defines the PickleCache used by ZODB Connection objects.\n" "Defines the PickleCache used by ZODB Connection objects.\n"
"\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 ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
...@@ -762,8 +764,7 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) ...@@ -762,8 +764,7 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v)
if (PyDict_SetItem(self->data, key, v) < 0) if (PyDict_SetItem(self->data, key, v) < 0)
return -1; return -1;
/* Remove the reference used by the dict. The cache should only /* the dict should have a borrowed reference */
have borrowed references to objects. */
Py_DECREF(v); Py_DECREF(v);
p = (cPersistentObject *)v; p = (cPersistentObject *)v;
...@@ -771,12 +772,14 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) ...@@ -771,12 +772,14 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v)
p->cache = (PerCache *)self; p->cache = (PerCache *)self;
if (p->state >= 0) { if (p->state >= 0) {
/* insert this non-ghost object into the ring just /* insert this non-ghost object into the ring just
behind the home position */ behind the home position. */
self->non_ghost_count++; self->non_ghost_count++;
p->ring.next = &self->ring_home; p->ring.next = &self->ring_home;
p->ring.prev = self->ring_home.prev; p->ring.prev = self->ring_home.prev;
self->ring_home.prev->next = &p->ring; self->ring_home.prev->next = &p->ring;
self->ring_home.prev = &p->ring; self->ring_home.prev = &p->ring;
/* this list should have a new reference to the object */
Py_INCREF(v);
} }
return 0; return 0;
} }
...@@ -802,6 +805,8 @@ cc_del_item(ccobject *self, PyObject *key) ...@@ -802,6 +805,8 @@ cc_del_item(ccobject *self, PyObject *key)
p->ring.prev->next = p->ring.next; p->ring.prev->next = p->ring.next;
p->ring.prev = NULL; p->ring.prev = NULL;
p->ring.next = NULL; p->ring.next = NULL;
/* The DelItem below will account for the reference
held by the list. */
} else { } else {
/* This is a ghost object, so we havent kept a reference /* This is a ghost object, so we havent kept a reference
count on it. For it have stayed alive this long count on it. For it have stayed alive this long
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
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.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" #include "cPersistence.h"
...@@ -131,6 +131,7 @@ unghostify(cPersistentObject *self) ...@@ -131,6 +131,7 @@ unghostify(cPersistentObject *self)
self->ring.prev = home->prev; self->ring.prev = home->prev;
home->prev->next = &self->ring; home->prev->next = &self->ring;
home->prev = &self->ring; home->prev = &self->ring;
Py_INCREF(self);
} }
self->state = cPersistent_CHANGED_STATE; self->state = cPersistent_CHANGED_STATE;
/* Call the object's __setstate__() */ /* Call the object's __setstate__() */
...@@ -184,6 +185,8 @@ ghostify(cPersistentObject *self) ...@@ -184,6 +185,8 @@ ghostify(cPersistentObject *self)
self->ring.prev = NULL; self->ring.prev = NULL;
self->ring.next = NULL; self->ring.next = NULL;
self->state = cPersistent_GHOST_STATE; self->state = cPersistent_GHOST_STATE;
/* self->ring held a reference to the object. */
Py_DECREF(self);
} }
static void static void
......
...@@ -53,10 +53,12 @@ persistent classes (such as BTrees). ...@@ -53,10 +53,12 @@ persistent classes (such as BTrees).
Regime 3: Non-Ghost Objects Regime 3: Non-Ghost Objects
Non-ghost objects are stored in two data structures. Firstly, in the Non-ghost objects are stored in two data structures: the dictionary
dictionary along with everything else, with a *strong* reference. mapping oids to objects and a doubly-linked list that encodes the
Secondly, they are stored in a doubly-linked-list which encodes the order in which the objects were accessed. The dictionary reference is
order in which these objects have been most recently used. 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 The doubly-link-list nodes contain next and previous pointers linking
together the cache and all non-ghost persistent objects. together the cache and all non-ghost persistent objects.
...@@ -88,7 +90,7 @@ process must skip such objects, rather than deactivating them. ...@@ -88,7 +90,7 @@ process must skip such objects, rather than deactivating them.
static char cPickleCache_doc_string[] = static char cPickleCache_doc_string[] =
"Defines the PickleCache used by ZODB Connection objects.\n" "Defines the PickleCache used by ZODB Connection objects.\n"
"\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 ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
...@@ -762,8 +764,7 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) ...@@ -762,8 +764,7 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v)
if (PyDict_SetItem(self->data, key, v) < 0) if (PyDict_SetItem(self->data, key, v) < 0)
return -1; return -1;
/* Remove the reference used by the dict. The cache should only /* the dict should have a borrowed reference */
have borrowed references to objects. */
Py_DECREF(v); Py_DECREF(v);
p = (cPersistentObject *)v; p = (cPersistentObject *)v;
...@@ -771,12 +772,14 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v) ...@@ -771,12 +772,14 @@ cc_add_item(ccobject *self, PyObject *key, PyObject *v)
p->cache = (PerCache *)self; p->cache = (PerCache *)self;
if (p->state >= 0) { if (p->state >= 0) {
/* insert this non-ghost object into the ring just /* insert this non-ghost object into the ring just
behind the home position */ behind the home position. */
self->non_ghost_count++; self->non_ghost_count++;
p->ring.next = &self->ring_home; p->ring.next = &self->ring_home;
p->ring.prev = self->ring_home.prev; p->ring.prev = self->ring_home.prev;
self->ring_home.prev->next = &p->ring; self->ring_home.prev->next = &p->ring;
self->ring_home.prev = &p->ring; self->ring_home.prev = &p->ring;
/* this list should have a new reference to the object */
Py_INCREF(v);
} }
return 0; return 0;
} }
...@@ -802,6 +805,8 @@ cc_del_item(ccobject *self, PyObject *key) ...@@ -802,6 +805,8 @@ cc_del_item(ccobject *self, PyObject *key)
p->ring.prev->next = p->ring.next; p->ring.prev->next = p->ring.next;
p->ring.prev = NULL; p->ring.prev = NULL;
p->ring.next = NULL; p->ring.next = NULL;
/* The DelItem below will account for the reference
held by the list. */
} else { } else {
/* This is a ghost object, so we havent kept a reference /* This is a ghost object, so we havent kept a reference
count on it. For it have stayed alive this long count on it. For it have stayed alive this long
......
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