Commit 5c0bad8d authored by Jeremy Hylton's avatar Jeremy Hylton

Major reformatting of code along with a few sundry changes.

Summary of changes:

- Add function gc_all_items() to call gc_item() on everything in
  dict.  This factors out common code in all the gc methods.

- Add check_size() function that factors out code to check cache size
  before starting a gc.

- Simplify argument processing in cc_invalidate(), avoiding a second
  call to PyArg_ParseTuple() when argument is a sequence instead of a
  dictionary.

- Chance code to reflect belief that NULL return from PyDict_GetItem()
  does not set exception, except in cases that don't apply for the
  pickle cache like comparing a string with high-order bit set to a
  Unicode object.

- Use if (!expr) instead of UNLESS().

- Remove all statements from conditionals.

- Reformat to 4 spaces and Python-style brace placement.

- Put whitespace around operators and after commas.
parent d6750225
...@@ -13,12 +13,7 @@ ...@@ -13,12 +13,7 @@
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.38 2002/01/25 14:51:55 gvanrossum Exp $\n"; "$Id: cPickleCache.c,v 1.39 2002/02/11 19:43:55 jeremy Exp $\n";
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
#define OBJECT(O) ((PyObject*)O)
/* Compute the current time in the units and range used for peristent /* Compute the current time in the units and range used for peristent
objects. */ objects. */
...@@ -33,23 +28,23 @@ static char cPickleCache_doc_string[] = ...@@ -33,23 +28,23 @@ static char cPickleCache_doc_string[] =
static PyObject *py_reload, *py__p_jar, *py__p_changed; static PyObject *py_reload, *py__p_jar, *py__p_changed;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *data; PyObject *data;
PyObject *jar; PyObject *jar;
PyObject *setklassstate; PyObject *setklassstate;
int position; int position;
int cache_size; int cache_size;
int cache_age; int cache_age;
/* Cache statistics */ /* Cache statistics */
int sum_deal; int sum_deal;
int sum_deac; int sum_deac;
double sum_age; double sum_age;
int n, na; int n, na;
time_t last_check; /* Time of last gc */ time_t last_check; /* Time of last gc */
double mean_age; double mean_age;
double mean_deal; double mean_deal;
double mean_deac; double mean_deac;
double df, dfa; /* Degees of freedom for above stats */ double df, dfa; /* Degees of freedom for above stats */
} ccobject; } ccobject;
#define WEIGHTING_PERIOD 600 #define WEIGHTING_PERIOD 600
...@@ -74,102 +69,116 @@ staticforward PyTypeObject Cctype; ...@@ -74,102 +69,116 @@ staticforward PyTypeObject Cctype;
static int static int
gc_item(ccobject *self, PyObject *key, PyObject *v, long now, int dt) gc_item(ccobject *self, PyObject *key, PyObject *v, long now, int dt)
{ {
if (v && key) if (!(v && key))
{ return 0;
self->n++; self->n++;
if(v->ob_refcnt <= 1)
{ /* If there is at most one reference to this object, then the
self->sum_deal++; cache has the only reference. It can be removed. */
/* XXX The fact that this works will iterating over if (v->ob_refcnt <= 1) {
self->data with PyDict_Next() is an accident of the self->sum_deal++;
current Python dictionary implementation. */ /* XXX The fact that this works will iterating over
return PyDict_DelItem(self->data, key); self->data with PyDict_Next() is an accident of the
} current Python dictionary implementation. */
return PyDict_DelItem(self->data, key);
}
if (dt >= 0 && if (dt >= 0 &&
(! PyExtensionClass_Check(v)) && (!PyExtensionClass_Check(v)) &&
((cPersistentObject*)v)->jar == self->jar /* I'm paranoid */ && ((cPersistentObject*)v)->jar == self->jar /* I'm paranoid */ &&
((cPersistentObject*)v)->state == cPersistent_UPTODATE_STATE ((cPersistentObject*)v)->state == cPersistent_UPTODATE_STATE) {
) now -= ((cPersistentObject*)v)->atime;
{ if (now < 0)
now -= ((cPersistentObject*)v)->atime; now += 65536;
if (now < 0) self->na++;
now += 65536; self->sum_age += now;
self->na++; if (now > dt) {
self->sum_age += now; /* We have a cPersistent object that hasn't been used in
if (now > dt) a while. Reinitialize it, hopefully freeing it's
{ state.
/* We have a cPersistent object that hasn't been used in */
a while. Reinitialize it, hopefully freeing it's self->sum_deac++;
state. if (PyObject_SetAttr(v, py__p_changed, Py_None) < 0)
*/
self->sum_deac++;
if (PyObject_SetAttr(v, py__p_changed, Py_None) < 0)
PyErr_Clear(); PyErr_Clear();
}
} }
} }
return 0; return 0;
} }
static void static void
update_stats(ccobject *self, time_t now) update_stats(ccobject *self, time_t now)
{ {
double d, deal, deac; double d, deal, deac;
d=now-self->last_check; d = now - self->last_check;
if(d < 1) return; if(d < 1)
return;
self->df *= WEIGHTING_PERIOD/(WEIGHTING_PERIOD+d);
self->dfa *= WEIGHTING_PERIOD/(WEIGHTING_PERIOD+d); self->df *= WEIGHTING_PERIOD / (WEIGHTING_PERIOD + d);
self->dfa *= WEIGHTING_PERIOD / (WEIGHTING_PERIOD + d);
self->mean_age=((self->mean_age*self->dfa+self->sum_age)/
(self->dfa+self->na))*3; self->mean_age = ((self->mean_age * self->dfa + self->sum_age)/
self->sum_age=0; (self->dfa + self->na)) * 3;
self->sum_age = 0;
deac=self->sum_deac/d;
self->sum_deac=0; deac = self->sum_deac / d;
self->mean_deac=((self->mean_deac*self->dfa+deac)/ self->sum_deac = 0;
(self->dfa+self->na)); self->mean_deac = ((self->mean_deac * self->dfa+deac)/
self->sum_deac=0; (self->dfa + self->na));
self->sum_deac = 0;
self->dfa += self->na;
self->na=0; self->dfa += self->na;
self->na = 0;
deal=self->sum_deal/d;
self->sum_deal = 0;
self->mean_deal = ((self->mean_deal * self->df + deal)/
(self->df +self->n));
self->sum_deal = 0;
self->df += self->n;
self->n = 0;
self->last_check = now;
}
deal=self->sum_deal/d; static int
self->sum_deal=0; check_size(ccobject *self)
self->mean_deal=((self->mean_deal*self->df +deal)/ {
(self->df +self->n)); if (self->cache_size < 1)
self->sum_deal=0; return 0;
return PyDict_Size(self->data);
}
self->df += self->n; static int
self->n=0; gc_all_items(ccobject *self, int now, int dt)
{
PyObject *key, *v;
int i;
self->last_check=now; for(i = 0; PyDict_Next(self->data, &i, &key, &v); )
if (gc_item(self, key, v, now, dt) < 0)
return -1;
return 0;
} }
static int static int
fullgc(ccobject *self, int dt) fullgc(ccobject *self, int dt)
{ {
PyObject *key, *v; long now;
int i;
long now;
if (self->cache_size < 1) if (check_size(self) <= 0)
return 0; return 0;
if ((i=PyDict_Size(self->data)) < 1)
return 0;
now = PER_TIME(); now = PER_TIME();
if (dt > 0) dt /= 3;
dt /= 3;
for(i=0; PyDict_Next(self->data, &i, &key, &v); ) if (gc_all_items(self, now, dt) < 0)
if (gc_item(self, key, v, now, dt) < 0)
return -1; return -1;
self->position=0; self->position = 0;
if(now-self->last_check > 1) update_stats(self, now); if (now - self->last_check > 1)
update_stats(self, now);
return 0; return 0;
} }
...@@ -177,139 +186,135 @@ fullgc(ccobject *self, int dt) ...@@ -177,139 +186,135 @@ fullgc(ccobject *self, int dt)
static int static int
reallyfullgc(ccobject *self, int dt) reallyfullgc(ccobject *self, int dt)
{ {
PyObject *key, *v; int l, last;
int i, l, last; time_t now;
time_t now;
if (self->cache_size < 1)
return 0;
last = PyDict_Size(self->data);
if (last < 0)
return -1;
now = PER_TIME(); last = check_size(self);
if (dt > 0) if (last <= 0)
dt /= 3; return 0;
/* First time through should get refcounts to 1 */ now = PER_TIME();
for(i=0; PyDict_Next(self->data, &i, &key, &v); ) /* Units are 3 seconds */
if (gc_item(self, key, v, now, dt) < 0) dt /= 3;
return -1;
l = PyDict_Size(self->data); /* First time through should get refcounts to 1 */
if (gc_all_items(self, now, dt) < 0)
return -1;
if (l < 0) l = PyDict_Size(self->data);
return -1; if (l < 0)
return -1;
while (l < last) /* Now continue to collect until the size of the cache stops
{ decreasing. */
for (i=0; PyDict_Next(self->data, &i, &key, &v); ) while (l < last) {
if (gc_item(self, key, v, now, dt) < 0) if (gc_all_items(self, now, dt) < 0)
return -1; return -1;
last = l; last = l;
l = PyDict_Size(self->data); l = PyDict_Size(self->data);
if (l < 0) if (l < 0)
return -1; return -1;
} }
if(now-self->last_check > 1) update_stats(self, now); if (now - self->last_check > 1)
update_stats(self, now);
self->position=0;
return 0; self->position = 0;
return 0;
} }
static int static int
maybegc(ccobject *self, PyObject *thisv) maybegc(ccobject *self, PyObject *thisv)
{ {
int n, s, size, dt; int n, s, size, dt;
long now; long now;
PyObject *key=0, *v=0; PyObject *key=0, *v=0;
if (self->cache_size < 1) return 0; s = check_size(self);
s=PyDict_Size(self->data); if (s <= 0)
if (s < 1) return s; return 0;
now = PER_TIME(); now = PER_TIME();
size=self->cache_size; size = self->cache_size;
self->cache_size=0; self->cache_size = 0;
/* Decide how many objects to look at */ /* Decide how many objects to look at */
n=(s-size)/10; n = (s - size) / 10;
if (n < 3) n=3; if (n < 3)
n = 3;
/* Decide how much time to give them before deactivating them */
s=8*size/s; /* Decide how much time to give them before deactivating them */
if (s > 100) s=100; s = 8 * size / s;
dt=(long)(self->cache_age*(0.2+0.1*s)); if (s > 100)
s = 100;
/* Units are 3 seconds */ dt = (long)(self->cache_age * (0.2 + 0.1 * s));
dt /= 3;
/* Units are 3 seconds */
if (dt < 1) dt=1; dt /= 3;
while (--n >= 0) while (--n >= 0) {
{ if (PyDict_Next(self->data, &(self->position), &key, &v)) {
if (PyDict_Next(self->data, &(self->position), &key, &v)) if (v != thisv && gc_item(self, key, v, now, dt) < 0) {
{ self->cache_size=size;
if (v != thisv && gc_item(self,key,v,now,dt) < 0) return -1;
{
self->cache_size=size;
return -1;
} }
} }
else else
self->position=0; self->position = 0;
} }
self->cache_size=size; self->cache_size = size;
if (now-self->last_check > 1) update_stats(self, now); if (now - self->last_check > 1)
update_stats(self, now);
return 0; return 0;
} }
static PyObject * static PyObject *
cc_full_sweep(ccobject *self, PyObject *args) cc_full_sweep(ccobject *self, PyObject *args)
{ {
int dt = self->cache_age; int dt = self->cache_age;
UNLESS(PyArg_ParseTuple(args, "|i:full_sweep", &dt)) return NULL; if (!PyArg_ParseTuple(args, "|i:full_sweep", &dt))
if (dt < -1) return NULL;
{ if (dt < -1) {
PyErr_SetString(PyExc_ValueError, "age must be >= -1"); PyErr_SetString(PyExc_ValueError, "age must be >= -1");
return NULL; return NULL;
} }
if (fullgc(self, dt) == -1) if (fullgc(self, dt) == -1)
return NULL; return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
static PyObject * static PyObject *
cc_reallyfull_sweep(ccobject *self, PyObject *args) cc_reallyfull_sweep(ccobject *self, PyObject *args)
{ {
int dt = self->cache_age; int dt = self->cache_age;
UNLESS(PyArg_ParseTuple(args, "|i:minimize", &dt)) return NULL; if (!PyArg_ParseTuple(args, "|i:minimize", &dt))
if (dt < -1) return NULL;
{ if (dt < -1) {
PyErr_SetString(PyExc_ValueError, "age must be >= -1"); PyErr_SetString(PyExc_ValueError, "age must be >= -1");
return NULL; return NULL;
} }
if (reallyfullgc(self, dt) == -1) if (reallyfullgc(self, dt) == -1)
return NULL; return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
static PyObject * static PyObject *
cc_incrgc(ccobject *self, PyObject *args) cc_incrgc(ccobject *self, PyObject *args)
{ {
int n=1; int n = 1;
UNLESS (PyArg_ParseTuple(args, "|i:incrgr",&n)) return NULL; if (!PyArg_ParseTuple(args, "|i:incrgr", &n))
return NULL;
for (; --n >= 0;) for (; --n >= 0;)
if(maybegc(self,NULL) < 0) return NULL; if (maybegc(self, NULL) < 0)
return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -317,114 +322,108 @@ cc_incrgc(ccobject *self, PyObject *args) ...@@ -317,114 +322,108 @@ cc_incrgc(ccobject *self, PyObject *args)
static void static void
_invalidate(ccobject *self, PyObject *key) _invalidate(ccobject *self, PyObject *key)
{ {
PyObject *v; PyObject *v = PyDict_GetItem(self->data, key);
if ((v=PyDict_GetItem(self->data, key))) if (!v)
{ return;
if (PyExtensionClass_Check(v)) if (PyExtensionClass_Check(v))
if(v->ob_refcnt <= 1) if (v->ob_refcnt <= 1) {
{
self->sum_deal++; self->sum_deal++;
if (PyDict_DelItem(self->data, key) < 0) if (PyDict_DelItem(self->data, key) < 0)
PyErr_Clear(); PyErr_Clear();
} } else {
else
{
PyObject *t = PyTuple_New(1); PyObject *t = PyTuple_New(1);
if (t) if (t) {
{
PyTuple_SET_ITEM(t, 0, v); PyTuple_SET_ITEM(t, 0, v);
v = PyObject_CallObject(self->setklassstate, t); v = PyObject_CallObject(self->setklassstate, t);
/* Set tuple element to NULL so that deallocating the
tuple does not decref t.
*/
PyTuple_SET_ITEM(t, 0, NULL); PyTuple_SET_ITEM(t, 0, NULL);
Py_DECREF(t); Py_DECREF(t);
} } else
else
{
v = t; v = t;
} if (v)
if (v) Py_DECREF(v); Py_DECREF(v);
else PyErr_Clear(); else
} PyErr_Clear();
else if (PyObject_DelAttr(v,py__p_changed) < 0) }
PyErr_Clear(); else if (PyObject_DelAttr(v, py__p_changed) < 0)
}
else
{
if (PyErr_Occurred())
PyErr_Clear(); PyErr_Clear();
} }
static void
_invalidate_all(ccobject *self)
{
PyObject *key, *v;
int i;
for (i = 0; PyDict_Next(self->data, &i, &key, &v); )
_invalidate(self, key);
} }
static PyObject * static PyObject *
cc_invalidate(ccobject *self, PyObject *args) cc_invalidate(ccobject *self, PyObject *args)
{ {
PyObject *inv, *key, *v; PyObject *inv, *key, *v;
int i; int i;
if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) { if (!PyArg_ParseTuple(args, "O:invalidate", &inv))
for (i=0; PyDict_Next(inv, &i, &key, &v); ) return NULL;
if (key==Py_None) if (PyDict_Check(inv)) {
{ /* Eek some nitwit invalidated everything! */ for (i = 0; PyDict_Next(inv, &i, &key, &v); )
for (i=0; PyDict_Next(self->data, &i, &key, &v); ) if (key == Py_None) {
_invalidate(self, key); /* Eek some nitwit invalidated everything! */
break; _invalidate_all(self);
} break;
else }
_invalidate(self, key); else
PyDict_Clear(inv); _invalidate(self, key);
} PyDict_Clear(inv);
else { } else if (PyString_Check(inv))
PyErr_Clear(); _invalidate(self, inv);
UNLESS (PyArg_ParseTuple(args, "O:invalidate", &inv)) return NULL; else if (inv == Py_None) /* All */
if (PyString_Check(inv)) _invalidate_all(self);
_invalidate(self, inv);
else if (inv==Py_None) /* All */
for (i=0; PyDict_Next(self->data, &i, &key, &v); )
_invalidate(self, key);
else { else {
int l; int l = PyObject_Length(inv);
PyErr_Clear(); if (l < 0)
if ((l=PyObject_Length(inv)) < 0) return NULL; return NULL;
for(i=l; --i >= 0; ) for (i = l; --i >= 0; ) {
{ key = PySequence_GetItem(inv, i);
UNLESS (key=PySequence_GetItem(inv, i)) return NULL; if (!key)
_invalidate(self, key); return NULL;
Py_DECREF(key); _invalidate(self, key);
Py_DECREF(key);
} }
PySequence_DelSlice(inv, 0, l); PySequence_DelSlice(inv, 0, l);
} }
}
Py_INCREF(Py_None);
Py_INCREF(Py_None); return Py_None;
return Py_None;
} }
static PyObject * static PyObject *
cc_get(ccobject *self, PyObject *args) cc_get(ccobject *self, PyObject *args)
{ {
PyObject *r, *key, *d=0; PyObject *r, *key, *d = NULL;
UNLESS (PyArg_ParseTuple(args, "O|O:get", &key, &d)) return NULL;
UNLESS (r=PyDict_GetItem(self->data, key)) if (!PyArg_ParseTuple(args, "O|O:get", &key, &d))
{ return NULL;
if (d)
{ r = PyDict_GetItem(self->data, key);
if (PyErr_Occurred()) if (!r) {
PyErr_Clear(); if (d)
r=d; r = d;
} else {
else PyErr_SetObject(PyExc_KeyError, key);
{ return NULL;
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
} }
} }
Py_INCREF(r); Py_INCREF(r);
return r; return r;
} }
...@@ -454,107 +453,115 @@ static struct PyMethodDef cc_methods[] = { ...@@ -454,107 +453,115 @@ static struct PyMethodDef cc_methods[] = {
static ccobject * static ccobject *
newccobject(PyObject *jar, int cache_size, int cache_age) newccobject(PyObject *jar, int cache_size, int cache_age)
{ {
ccobject *self; ccobject *self;
UNLESS(self = PyObject_NEW(ccobject, &Cctype)) return NULL; self = PyObject_NEW(ccobject, &Cctype);
self->setklassstate=self->jar=NULL; if (!self)
if((self->data=PyDict_New()))
{
self->jar=jar;
Py_INCREF(jar);
UNLESS (self->setklassstate=PyObject_GetAttrString(jar, "setklassstate"))
return NULL; return NULL;
self->position=0; self->setklassstate = self->jar = NULL;
self->cache_size=cache_size; self->data = PyDict_New();
self->cache_age=cache_age < 1 ? 1 : cache_age; if (self->data) {
self->sum_deal=0; self->jar=jar;
self->sum_deac=0; Py_INCREF(jar);
self->sum_age=0; self->setklassstate = PyObject_GetAttrString(jar, "setklassstate");
self->mean_deal=0; if (!self->setklassstate) {
self->mean_deac=0; Py_DECREF(jar);
self->mean_age=0; Py_DECREF(self->data);
self->df=1; goto error;
self->dfa=1; }
self->n=0; self->position = 0;
self->na=0; self->cache_size = cache_size;
self->last_check=time(NULL); self->cache_age = cache_age < 1 ? 1 : cache_age;
return self; self->sum_deal = 0;
self->sum_deac = 0;
self->sum_age = 0;
self->mean_deal = 0;
self->mean_deac = 0;
self->mean_age = 0;
self->df = 1;
self->dfa = 1;
self->n = 0;
self->na = 0;
self->last_check = time(NULL);
return self;
} }
Py_DECREF(self); error:
return NULL; Py_DECREF(self);
return NULL;
} }
static void static void
cc_dealloc(ccobject *self) cc_dealloc(ccobject *self)
{ {
Py_XDECREF(self->data); Py_XDECREF(self->data);
Py_XDECREF(self->jar); Py_XDECREF(self->jar);
Py_XDECREF(self->setklassstate); Py_XDECREF(self->setklassstate);
PyMem_DEL(self); PyMem_DEL(self);
} }
static PyObject * static PyObject *
cc_getattr(ccobject *self, char *name) cc_getattr(ccobject *self, char *name)
{ {
PyObject *r; PyObject *r;
if(*name=='c') if (*name == 'c') {
{ if(strcmp(name, "cache_age") == 0)
if(strcmp(name,"cache_age")==0) return PyInt_FromLong(self->cache_age);
return PyInt_FromLong(self->cache_age); if(strcmp(name, "cache_size") == 0)
if(strcmp(name,"cache_size")==0) return PyInt_FromLong(self->cache_size);
return PyInt_FromLong(self->cache_size); if(strcmp(name, "cache_mean_age") == 0)
if(strcmp(name,"cache_mean_age")==0) return PyFloat_FromDouble(self->mean_age);
return PyFloat_FromDouble(self->mean_age); if(strcmp(name, "cache_mean_deal") == 0)
if(strcmp(name,"cache_mean_deal")==0) return PyFloat_FromDouble(self->mean_deal);
return PyFloat_FromDouble(self->mean_deal); if(strcmp(name, "cache_mean_deac") == 0)
if(strcmp(name,"cache_mean_deac")==0) return PyFloat_FromDouble(self->mean_deac);
return PyFloat_FromDouble(self->mean_deac); if(strcmp(name, "cache_df") == 0)
if(strcmp(name,"cache_df")==0) return PyFloat_FromDouble(self->df);
return PyFloat_FromDouble(self->df); if(strcmp(name, "cache_dfa") == 0)
if(strcmp(name,"cache_dfa")==0) return PyFloat_FromDouble(self->dfa);
return PyFloat_FromDouble(self->dfa); if(strcmp(name, "cache_last_gc_time") == 0)
if(strcmp(name,"cache_last_gc_time")==0) return PyFloat_FromDouble(self->last_check);
return PyFloat_FromDouble(self->last_check); if(strcmp(name, "cache_data") == 0) {
if(strcmp(name,"cache_data")==0) Py_INCREF(self->data);
{ return self->data;
Py_INCREF(self->data);
return self->data;
} }
} }
if((*name=='h' && strcmp(name, "has_key")==0) || if ((strcmp(name, "has_key") == 0)
(*name=='i' && strcmp(name, "items")==0) || || (strcmp(name, "items") == 0)
(*name=='k' && strcmp(name, "keys")==0) || (strcmp(name, "keys") == 0))
) return PyObject_GetAttrString(self->data, name);
return PyObject_GetAttrString(self->data, name);
r = Py_FindMethod(cc_methods, (PyObject *)self, name);
if((r=Py_FindMethod(cc_methods, (PyObject *)self, name))) if (!r) {
PyErr_Clear();
return PyObject_GetAttrString(self->data, name);
}
return r; return r;
PyErr_Clear();
return PyObject_GetAttrString(self->data, name);
} }
static int static int
cc_setattr(ccobject *self, char *name, PyObject *value) cc_setattr(ccobject *self, char *name, PyObject *value)
{ {
if(value) if (value) {
{
int v; int v;
if(strcmp(name,"cache_age")==0) if (strcmp(name, "cache_age") == 0) {
{ v = PyInt_AsLong(value);
UNLESS(PyArg_Parse(value,"i",&v)) return -1; if (v == -1 && PyErr_Occurred())
if(v > 0)self->cache_age=v; return -1;
if (v > 0)
self->cache_age = v;
return 0; return 0;
} }
if(strcmp(name,"cache_size")==0) if (strcmp(name, "cache_size") == 0) {
{ v = PyInt_AsLong(value);
UNLESS(PyArg_Parse(value,"i",&v)) return -1; if (v == -1 && PyErr_Occurred())
self->cache_size=v; return -1;
self->cache_size = v;
return 0; return 0;
} }
} }
PyErr_SetString(PyExc_AttributeError, name); PyErr_SetString(PyExc_AttributeError, name);
return -1; return -1;
} }
...@@ -562,7 +569,7 @@ cc_setattr(ccobject *self, char *name, PyObject *value) ...@@ -562,7 +569,7 @@ cc_setattr(ccobject *self, char *name, PyObject *value)
static int static int
cc_length(ccobject *self) cc_length(ccobject *self)
{ {
return PyObject_Length(self->data); return PyDict_Size(self->data);
} }
static PyObject * static PyObject *
...@@ -570,10 +577,10 @@ cc_subscript(ccobject *self, PyObject *key) ...@@ -570,10 +577,10 @@ cc_subscript(ccobject *self, PyObject *key)
{ {
PyObject *r; PyObject *r;
UNLESS (r=PyDict_GetItem(self->data, key)) r = PyDict_GetItem(self->data, key);
{ if (!r) {
PyErr_SetObject(PyExc_KeyError, key); PyErr_SetObject(PyExc_KeyError, key);
return NULL; return NULL;
} }
Py_INCREF(r); Py_INCREF(r);
...@@ -583,8 +590,7 @@ cc_subscript(ccobject *self, PyObject *key) ...@@ -583,8 +590,7 @@ cc_subscript(ccobject *self, PyObject *key)
static int static int
cc_ass_sub(ccobject *self, PyObject *key, PyObject *v) cc_ass_sub(ccobject *self, PyObject *key, PyObject *v)
{ {
if(v) if (v) {
{
if (PyExtensionClass_Check(v) if (PyExtensionClass_Check(v)
|| ||
(PyExtensionInstance_Check(v) (PyExtensionInstance_Check(v)
...@@ -629,10 +635,6 @@ static PyTypeObject Cctype = { ...@@ -629,10 +635,6 @@ static PyTypeObject Cctype = {
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/ (ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
/* Space for future expansion */
0L,0L,0L,0L,
""
}; };
static PyObject * static PyObject *
...@@ -641,9 +643,9 @@ cCM_new(PyObject *self, PyObject *args) ...@@ -641,9 +643,9 @@ cCM_new(PyObject *self, PyObject *args)
int cache_size=100, cache_age=1000; int cache_size=100, cache_age=1000;
PyObject *jar; PyObject *jar;
UNLESS(PyArg_ParseTuple(args, "O|ii", &jar, &cache_size, &cache_age)) if (!PyArg_ParseTuple(args, "O|ii", &jar, &cache_size, &cache_age))
return NULL; return NULL;
return (PyObject*)newccobject(jar, cache_size,cache_age); return (PyObject *)newccobject(jar, cache_size, cache_age);
} }
static struct PyMethodDef cCM_methods[] = { static struct PyMethodDef cCM_methods[] = {
...@@ -654,22 +656,17 @@ static struct PyMethodDef cCM_methods[] = { ...@@ -654,22 +656,17 @@ static struct PyMethodDef cCM_methods[] = {
void void
initcPickleCache(void) initcPickleCache(void)
{ {
PyObject *m, *d; PyObject *m;
Cctype.ob_type=&PyType_Type; Cctype.ob_type = &PyType_Type;
UNLESS(ExtensionClassImported) return; if (!ExtensionClassImported)
return;
m = Py_InitModule4("cPickleCache", cCM_methods, cPickleCache_doc_string, m = Py_InitModule4("cPickleCache", cCM_methods, cPickleCache_doc_string,
(PyObject*)NULL, PYTHON_API_VERSION); (PyObject*)NULL, PYTHON_API_VERSION);
d = PyModule_GetDict(m); py_reload = PyString_InternFromString("reload");
py__p_jar = PyString_InternFromString("_p_jar");
py_reload=PyString_FromString("reload"); py__p_changed = PyString_InternFromString("_p_changed");
py__p_jar=PyString_FromString("_p_jar");
py__p_changed=PyString_FromString("_p_changed");
/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module cPickleCache");
} }
...@@ -13,12 +13,7 @@ ...@@ -13,12 +13,7 @@
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.38 2002/01/25 14:51:55 gvanrossum Exp $\n"; "$Id: cPickleCache.c,v 1.39 2002/02/11 19:43:55 jeremy Exp $\n";
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
#define OBJECT(O) ((PyObject*)O)
/* Compute the current time in the units and range used for peristent /* Compute the current time in the units and range used for peristent
objects. */ objects. */
...@@ -33,23 +28,23 @@ static char cPickleCache_doc_string[] = ...@@ -33,23 +28,23 @@ static char cPickleCache_doc_string[] =
static PyObject *py_reload, *py__p_jar, *py__p_changed; static PyObject *py_reload, *py__p_jar, *py__p_changed;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *data; PyObject *data;
PyObject *jar; PyObject *jar;
PyObject *setklassstate; PyObject *setklassstate;
int position; int position;
int cache_size; int cache_size;
int cache_age; int cache_age;
/* Cache statistics */ /* Cache statistics */
int sum_deal; int sum_deal;
int sum_deac; int sum_deac;
double sum_age; double sum_age;
int n, na; int n, na;
time_t last_check; /* Time of last gc */ time_t last_check; /* Time of last gc */
double mean_age; double mean_age;
double mean_deal; double mean_deal;
double mean_deac; double mean_deac;
double df, dfa; /* Degees of freedom for above stats */ double df, dfa; /* Degees of freedom for above stats */
} ccobject; } ccobject;
#define WEIGHTING_PERIOD 600 #define WEIGHTING_PERIOD 600
...@@ -74,102 +69,116 @@ staticforward PyTypeObject Cctype; ...@@ -74,102 +69,116 @@ staticforward PyTypeObject Cctype;
static int static int
gc_item(ccobject *self, PyObject *key, PyObject *v, long now, int dt) gc_item(ccobject *self, PyObject *key, PyObject *v, long now, int dt)
{ {
if (v && key) if (!(v && key))
{ return 0;
self->n++; self->n++;
if(v->ob_refcnt <= 1)
{ /* If there is at most one reference to this object, then the
self->sum_deal++; cache has the only reference. It can be removed. */
/* XXX The fact that this works will iterating over if (v->ob_refcnt <= 1) {
self->data with PyDict_Next() is an accident of the self->sum_deal++;
current Python dictionary implementation. */ /* XXX The fact that this works will iterating over
return PyDict_DelItem(self->data, key); self->data with PyDict_Next() is an accident of the
} current Python dictionary implementation. */
return PyDict_DelItem(self->data, key);
}
if (dt >= 0 && if (dt >= 0 &&
(! PyExtensionClass_Check(v)) && (!PyExtensionClass_Check(v)) &&
((cPersistentObject*)v)->jar == self->jar /* I'm paranoid */ && ((cPersistentObject*)v)->jar == self->jar /* I'm paranoid */ &&
((cPersistentObject*)v)->state == cPersistent_UPTODATE_STATE ((cPersistentObject*)v)->state == cPersistent_UPTODATE_STATE) {
) now -= ((cPersistentObject*)v)->atime;
{ if (now < 0)
now -= ((cPersistentObject*)v)->atime; now += 65536;
if (now < 0) self->na++;
now += 65536; self->sum_age += now;
self->na++; if (now > dt) {
self->sum_age += now; /* We have a cPersistent object that hasn't been used in
if (now > dt) a while. Reinitialize it, hopefully freeing it's
{ state.
/* We have a cPersistent object that hasn't been used in */
a while. Reinitialize it, hopefully freeing it's self->sum_deac++;
state. if (PyObject_SetAttr(v, py__p_changed, Py_None) < 0)
*/
self->sum_deac++;
if (PyObject_SetAttr(v, py__p_changed, Py_None) < 0)
PyErr_Clear(); PyErr_Clear();
}
} }
} }
return 0; return 0;
} }
static void static void
update_stats(ccobject *self, time_t now) update_stats(ccobject *self, time_t now)
{ {
double d, deal, deac; double d, deal, deac;
d=now-self->last_check; d = now - self->last_check;
if(d < 1) return; if(d < 1)
return;
self->df *= WEIGHTING_PERIOD/(WEIGHTING_PERIOD+d);
self->dfa *= WEIGHTING_PERIOD/(WEIGHTING_PERIOD+d); self->df *= WEIGHTING_PERIOD / (WEIGHTING_PERIOD + d);
self->dfa *= WEIGHTING_PERIOD / (WEIGHTING_PERIOD + d);
self->mean_age=((self->mean_age*self->dfa+self->sum_age)/
(self->dfa+self->na))*3; self->mean_age = ((self->mean_age * self->dfa + self->sum_age)/
self->sum_age=0; (self->dfa + self->na)) * 3;
self->sum_age = 0;
deac=self->sum_deac/d;
self->sum_deac=0; deac = self->sum_deac / d;
self->mean_deac=((self->mean_deac*self->dfa+deac)/ self->sum_deac = 0;
(self->dfa+self->na)); self->mean_deac = ((self->mean_deac * self->dfa+deac)/
self->sum_deac=0; (self->dfa + self->na));
self->sum_deac = 0;
self->dfa += self->na;
self->na=0; self->dfa += self->na;
self->na = 0;
deal=self->sum_deal/d;
self->sum_deal = 0;
self->mean_deal = ((self->mean_deal * self->df + deal)/
(self->df +self->n));
self->sum_deal = 0;
self->df += self->n;
self->n = 0;
self->last_check = now;
}
deal=self->sum_deal/d; static int
self->sum_deal=0; check_size(ccobject *self)
self->mean_deal=((self->mean_deal*self->df +deal)/ {
(self->df +self->n)); if (self->cache_size < 1)
self->sum_deal=0; return 0;
return PyDict_Size(self->data);
}
self->df += self->n; static int
self->n=0; gc_all_items(ccobject *self, int now, int dt)
{
PyObject *key, *v;
int i;
self->last_check=now; for(i = 0; PyDict_Next(self->data, &i, &key, &v); )
if (gc_item(self, key, v, now, dt) < 0)
return -1;
return 0;
} }
static int static int
fullgc(ccobject *self, int dt) fullgc(ccobject *self, int dt)
{ {
PyObject *key, *v; long now;
int i;
long now;
if (self->cache_size < 1) if (check_size(self) <= 0)
return 0; return 0;
if ((i=PyDict_Size(self->data)) < 1)
return 0;
now = PER_TIME(); now = PER_TIME();
if (dt > 0) dt /= 3;
dt /= 3;
for(i=0; PyDict_Next(self->data, &i, &key, &v); ) if (gc_all_items(self, now, dt) < 0)
if (gc_item(self, key, v, now, dt) < 0)
return -1; return -1;
self->position=0; self->position = 0;
if(now-self->last_check > 1) update_stats(self, now); if (now - self->last_check > 1)
update_stats(self, now);
return 0; return 0;
} }
...@@ -177,139 +186,135 @@ fullgc(ccobject *self, int dt) ...@@ -177,139 +186,135 @@ fullgc(ccobject *self, int dt)
static int static int
reallyfullgc(ccobject *self, int dt) reallyfullgc(ccobject *self, int dt)
{ {
PyObject *key, *v; int l, last;
int i, l, last; time_t now;
time_t now;
if (self->cache_size < 1)
return 0;
last = PyDict_Size(self->data);
if (last < 0)
return -1;
now = PER_TIME(); last = check_size(self);
if (dt > 0) if (last <= 0)
dt /= 3; return 0;
/* First time through should get refcounts to 1 */ now = PER_TIME();
for(i=0; PyDict_Next(self->data, &i, &key, &v); ) /* Units are 3 seconds */
if (gc_item(self, key, v, now, dt) < 0) dt /= 3;
return -1;
l = PyDict_Size(self->data); /* First time through should get refcounts to 1 */
if (gc_all_items(self, now, dt) < 0)
return -1;
if (l < 0) l = PyDict_Size(self->data);
return -1; if (l < 0)
return -1;
while (l < last) /* Now continue to collect until the size of the cache stops
{ decreasing. */
for (i=0; PyDict_Next(self->data, &i, &key, &v); ) while (l < last) {
if (gc_item(self, key, v, now, dt) < 0) if (gc_all_items(self, now, dt) < 0)
return -1; return -1;
last = l; last = l;
l = PyDict_Size(self->data); l = PyDict_Size(self->data);
if (l < 0) if (l < 0)
return -1; return -1;
} }
if(now-self->last_check > 1) update_stats(self, now); if (now - self->last_check > 1)
update_stats(self, now);
self->position=0;
return 0; self->position = 0;
return 0;
} }
static int static int
maybegc(ccobject *self, PyObject *thisv) maybegc(ccobject *self, PyObject *thisv)
{ {
int n, s, size, dt; int n, s, size, dt;
long now; long now;
PyObject *key=0, *v=0; PyObject *key=0, *v=0;
if (self->cache_size < 1) return 0; s = check_size(self);
s=PyDict_Size(self->data); if (s <= 0)
if (s < 1) return s; return 0;
now = PER_TIME(); now = PER_TIME();
size=self->cache_size; size = self->cache_size;
self->cache_size=0; self->cache_size = 0;
/* Decide how many objects to look at */ /* Decide how many objects to look at */
n=(s-size)/10; n = (s - size) / 10;
if (n < 3) n=3; if (n < 3)
n = 3;
/* Decide how much time to give them before deactivating them */
s=8*size/s; /* Decide how much time to give them before deactivating them */
if (s > 100) s=100; s = 8 * size / s;
dt=(long)(self->cache_age*(0.2+0.1*s)); if (s > 100)
s = 100;
/* Units are 3 seconds */ dt = (long)(self->cache_age * (0.2 + 0.1 * s));
dt /= 3;
/* Units are 3 seconds */
if (dt < 1) dt=1; dt /= 3;
while (--n >= 0) while (--n >= 0) {
{ if (PyDict_Next(self->data, &(self->position), &key, &v)) {
if (PyDict_Next(self->data, &(self->position), &key, &v)) if (v != thisv && gc_item(self, key, v, now, dt) < 0) {
{ self->cache_size=size;
if (v != thisv && gc_item(self,key,v,now,dt) < 0) return -1;
{
self->cache_size=size;
return -1;
} }
} }
else else
self->position=0; self->position = 0;
} }
self->cache_size=size; self->cache_size = size;
if (now-self->last_check > 1) update_stats(self, now); if (now - self->last_check > 1)
update_stats(self, now);
return 0; return 0;
} }
static PyObject * static PyObject *
cc_full_sweep(ccobject *self, PyObject *args) cc_full_sweep(ccobject *self, PyObject *args)
{ {
int dt = self->cache_age; int dt = self->cache_age;
UNLESS(PyArg_ParseTuple(args, "|i:full_sweep", &dt)) return NULL; if (!PyArg_ParseTuple(args, "|i:full_sweep", &dt))
if (dt < -1) return NULL;
{ if (dt < -1) {
PyErr_SetString(PyExc_ValueError, "age must be >= -1"); PyErr_SetString(PyExc_ValueError, "age must be >= -1");
return NULL; return NULL;
} }
if (fullgc(self, dt) == -1) if (fullgc(self, dt) == -1)
return NULL; return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
static PyObject * static PyObject *
cc_reallyfull_sweep(ccobject *self, PyObject *args) cc_reallyfull_sweep(ccobject *self, PyObject *args)
{ {
int dt = self->cache_age; int dt = self->cache_age;
UNLESS(PyArg_ParseTuple(args, "|i:minimize", &dt)) return NULL; if (!PyArg_ParseTuple(args, "|i:minimize", &dt))
if (dt < -1) return NULL;
{ if (dt < -1) {
PyErr_SetString(PyExc_ValueError, "age must be >= -1"); PyErr_SetString(PyExc_ValueError, "age must be >= -1");
return NULL; return NULL;
} }
if (reallyfullgc(self, dt) == -1) if (reallyfullgc(self, dt) == -1)
return NULL; return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
static PyObject * static PyObject *
cc_incrgc(ccobject *self, PyObject *args) cc_incrgc(ccobject *self, PyObject *args)
{ {
int n=1; int n = 1;
UNLESS (PyArg_ParseTuple(args, "|i:incrgr",&n)) return NULL; if (!PyArg_ParseTuple(args, "|i:incrgr", &n))
return NULL;
for (; --n >= 0;) for (; --n >= 0;)
if(maybegc(self,NULL) < 0) return NULL; if (maybegc(self, NULL) < 0)
return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -317,114 +322,108 @@ cc_incrgc(ccobject *self, PyObject *args) ...@@ -317,114 +322,108 @@ cc_incrgc(ccobject *self, PyObject *args)
static void static void
_invalidate(ccobject *self, PyObject *key) _invalidate(ccobject *self, PyObject *key)
{ {
PyObject *v; PyObject *v = PyDict_GetItem(self->data, key);
if ((v=PyDict_GetItem(self->data, key))) if (!v)
{ return;
if (PyExtensionClass_Check(v)) if (PyExtensionClass_Check(v))
if(v->ob_refcnt <= 1) if (v->ob_refcnt <= 1) {
{
self->sum_deal++; self->sum_deal++;
if (PyDict_DelItem(self->data, key) < 0) if (PyDict_DelItem(self->data, key) < 0)
PyErr_Clear(); PyErr_Clear();
} } else {
else
{
PyObject *t = PyTuple_New(1); PyObject *t = PyTuple_New(1);
if (t) if (t) {
{
PyTuple_SET_ITEM(t, 0, v); PyTuple_SET_ITEM(t, 0, v);
v = PyObject_CallObject(self->setklassstate, t); v = PyObject_CallObject(self->setklassstate, t);
/* Set tuple element to NULL so that deallocating the
tuple does not decref t.
*/
PyTuple_SET_ITEM(t, 0, NULL); PyTuple_SET_ITEM(t, 0, NULL);
Py_DECREF(t); Py_DECREF(t);
} } else
else
{
v = t; v = t;
} if (v)
if (v) Py_DECREF(v); Py_DECREF(v);
else PyErr_Clear(); else
} PyErr_Clear();
else if (PyObject_DelAttr(v,py__p_changed) < 0) }
PyErr_Clear(); else if (PyObject_DelAttr(v, py__p_changed) < 0)
}
else
{
if (PyErr_Occurred())
PyErr_Clear(); PyErr_Clear();
} }
static void
_invalidate_all(ccobject *self)
{
PyObject *key, *v;
int i;
for (i = 0; PyDict_Next(self->data, &i, &key, &v); )
_invalidate(self, key);
} }
static PyObject * static PyObject *
cc_invalidate(ccobject *self, PyObject *args) cc_invalidate(ccobject *self, PyObject *args)
{ {
PyObject *inv, *key, *v; PyObject *inv, *key, *v;
int i; int i;
if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) { if (!PyArg_ParseTuple(args, "O:invalidate", &inv))
for (i=0; PyDict_Next(inv, &i, &key, &v); ) return NULL;
if (key==Py_None) if (PyDict_Check(inv)) {
{ /* Eek some nitwit invalidated everything! */ for (i = 0; PyDict_Next(inv, &i, &key, &v); )
for (i=0; PyDict_Next(self->data, &i, &key, &v); ) if (key == Py_None) {
_invalidate(self, key); /* Eek some nitwit invalidated everything! */
break; _invalidate_all(self);
} break;
else }
_invalidate(self, key); else
PyDict_Clear(inv); _invalidate(self, key);
} PyDict_Clear(inv);
else { } else if (PyString_Check(inv))
PyErr_Clear(); _invalidate(self, inv);
UNLESS (PyArg_ParseTuple(args, "O:invalidate", &inv)) return NULL; else if (inv == Py_None) /* All */
if (PyString_Check(inv)) _invalidate_all(self);
_invalidate(self, inv);
else if (inv==Py_None) /* All */
for (i=0; PyDict_Next(self->data, &i, &key, &v); )
_invalidate(self, key);
else { else {
int l; int l = PyObject_Length(inv);
PyErr_Clear(); if (l < 0)
if ((l=PyObject_Length(inv)) < 0) return NULL; return NULL;
for(i=l; --i >= 0; ) for (i = l; --i >= 0; ) {
{ key = PySequence_GetItem(inv, i);
UNLESS (key=PySequence_GetItem(inv, i)) return NULL; if (!key)
_invalidate(self, key); return NULL;
Py_DECREF(key); _invalidate(self, key);
Py_DECREF(key);
} }
PySequence_DelSlice(inv, 0, l); PySequence_DelSlice(inv, 0, l);
} }
}
Py_INCREF(Py_None);
Py_INCREF(Py_None); return Py_None;
return Py_None;
} }
static PyObject * static PyObject *
cc_get(ccobject *self, PyObject *args) cc_get(ccobject *self, PyObject *args)
{ {
PyObject *r, *key, *d=0; PyObject *r, *key, *d = NULL;
UNLESS (PyArg_ParseTuple(args, "O|O:get", &key, &d)) return NULL;
UNLESS (r=PyDict_GetItem(self->data, key)) if (!PyArg_ParseTuple(args, "O|O:get", &key, &d))
{ return NULL;
if (d)
{ r = PyDict_GetItem(self->data, key);
if (PyErr_Occurred()) if (!r) {
PyErr_Clear(); if (d)
r=d; r = d;
} else {
else PyErr_SetObject(PyExc_KeyError, key);
{ return NULL;
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
} }
} }
Py_INCREF(r); Py_INCREF(r);
return r; return r;
} }
...@@ -454,107 +453,115 @@ static struct PyMethodDef cc_methods[] = { ...@@ -454,107 +453,115 @@ static struct PyMethodDef cc_methods[] = {
static ccobject * static ccobject *
newccobject(PyObject *jar, int cache_size, int cache_age) newccobject(PyObject *jar, int cache_size, int cache_age)
{ {
ccobject *self; ccobject *self;
UNLESS(self = PyObject_NEW(ccobject, &Cctype)) return NULL; self = PyObject_NEW(ccobject, &Cctype);
self->setklassstate=self->jar=NULL; if (!self)
if((self->data=PyDict_New()))
{
self->jar=jar;
Py_INCREF(jar);
UNLESS (self->setklassstate=PyObject_GetAttrString(jar, "setklassstate"))
return NULL; return NULL;
self->position=0; self->setklassstate = self->jar = NULL;
self->cache_size=cache_size; self->data = PyDict_New();
self->cache_age=cache_age < 1 ? 1 : cache_age; if (self->data) {
self->sum_deal=0; self->jar=jar;
self->sum_deac=0; Py_INCREF(jar);
self->sum_age=0; self->setklassstate = PyObject_GetAttrString(jar, "setklassstate");
self->mean_deal=0; if (!self->setklassstate) {
self->mean_deac=0; Py_DECREF(jar);
self->mean_age=0; Py_DECREF(self->data);
self->df=1; goto error;
self->dfa=1; }
self->n=0; self->position = 0;
self->na=0; self->cache_size = cache_size;
self->last_check=time(NULL); self->cache_age = cache_age < 1 ? 1 : cache_age;
return self; self->sum_deal = 0;
self->sum_deac = 0;
self->sum_age = 0;
self->mean_deal = 0;
self->mean_deac = 0;
self->mean_age = 0;
self->df = 1;
self->dfa = 1;
self->n = 0;
self->na = 0;
self->last_check = time(NULL);
return self;
} }
Py_DECREF(self); error:
return NULL; Py_DECREF(self);
return NULL;
} }
static void static void
cc_dealloc(ccobject *self) cc_dealloc(ccobject *self)
{ {
Py_XDECREF(self->data); Py_XDECREF(self->data);
Py_XDECREF(self->jar); Py_XDECREF(self->jar);
Py_XDECREF(self->setklassstate); Py_XDECREF(self->setklassstate);
PyMem_DEL(self); PyMem_DEL(self);
} }
static PyObject * static PyObject *
cc_getattr(ccobject *self, char *name) cc_getattr(ccobject *self, char *name)
{ {
PyObject *r; PyObject *r;
if(*name=='c') if (*name == 'c') {
{ if(strcmp(name, "cache_age") == 0)
if(strcmp(name,"cache_age")==0) return PyInt_FromLong(self->cache_age);
return PyInt_FromLong(self->cache_age); if(strcmp(name, "cache_size") == 0)
if(strcmp(name,"cache_size")==0) return PyInt_FromLong(self->cache_size);
return PyInt_FromLong(self->cache_size); if(strcmp(name, "cache_mean_age") == 0)
if(strcmp(name,"cache_mean_age")==0) return PyFloat_FromDouble(self->mean_age);
return PyFloat_FromDouble(self->mean_age); if(strcmp(name, "cache_mean_deal") == 0)
if(strcmp(name,"cache_mean_deal")==0) return PyFloat_FromDouble(self->mean_deal);
return PyFloat_FromDouble(self->mean_deal); if(strcmp(name, "cache_mean_deac") == 0)
if(strcmp(name,"cache_mean_deac")==0) return PyFloat_FromDouble(self->mean_deac);
return PyFloat_FromDouble(self->mean_deac); if(strcmp(name, "cache_df") == 0)
if(strcmp(name,"cache_df")==0) return PyFloat_FromDouble(self->df);
return PyFloat_FromDouble(self->df); if(strcmp(name, "cache_dfa") == 0)
if(strcmp(name,"cache_dfa")==0) return PyFloat_FromDouble(self->dfa);
return PyFloat_FromDouble(self->dfa); if(strcmp(name, "cache_last_gc_time") == 0)
if(strcmp(name,"cache_last_gc_time")==0) return PyFloat_FromDouble(self->last_check);
return PyFloat_FromDouble(self->last_check); if(strcmp(name, "cache_data") == 0) {
if(strcmp(name,"cache_data")==0) Py_INCREF(self->data);
{ return self->data;
Py_INCREF(self->data);
return self->data;
} }
} }
if((*name=='h' && strcmp(name, "has_key")==0) || if ((strcmp(name, "has_key") == 0)
(*name=='i' && strcmp(name, "items")==0) || || (strcmp(name, "items") == 0)
(*name=='k' && strcmp(name, "keys")==0) || (strcmp(name, "keys") == 0))
) return PyObject_GetAttrString(self->data, name);
return PyObject_GetAttrString(self->data, name);
r = Py_FindMethod(cc_methods, (PyObject *)self, name);
if((r=Py_FindMethod(cc_methods, (PyObject *)self, name))) if (!r) {
PyErr_Clear();
return PyObject_GetAttrString(self->data, name);
}
return r; return r;
PyErr_Clear();
return PyObject_GetAttrString(self->data, name);
} }
static int static int
cc_setattr(ccobject *self, char *name, PyObject *value) cc_setattr(ccobject *self, char *name, PyObject *value)
{ {
if(value) if (value) {
{
int v; int v;
if(strcmp(name,"cache_age")==0) if (strcmp(name, "cache_age") == 0) {
{ v = PyInt_AsLong(value);
UNLESS(PyArg_Parse(value,"i",&v)) return -1; if (v == -1 && PyErr_Occurred())
if(v > 0)self->cache_age=v; return -1;
if (v > 0)
self->cache_age = v;
return 0; return 0;
} }
if(strcmp(name,"cache_size")==0) if (strcmp(name, "cache_size") == 0) {
{ v = PyInt_AsLong(value);
UNLESS(PyArg_Parse(value,"i",&v)) return -1; if (v == -1 && PyErr_Occurred())
self->cache_size=v; return -1;
self->cache_size = v;
return 0; return 0;
} }
} }
PyErr_SetString(PyExc_AttributeError, name); PyErr_SetString(PyExc_AttributeError, name);
return -1; return -1;
} }
...@@ -562,7 +569,7 @@ cc_setattr(ccobject *self, char *name, PyObject *value) ...@@ -562,7 +569,7 @@ cc_setattr(ccobject *self, char *name, PyObject *value)
static int static int
cc_length(ccobject *self) cc_length(ccobject *self)
{ {
return PyObject_Length(self->data); return PyDict_Size(self->data);
} }
static PyObject * static PyObject *
...@@ -570,10 +577,10 @@ cc_subscript(ccobject *self, PyObject *key) ...@@ -570,10 +577,10 @@ cc_subscript(ccobject *self, PyObject *key)
{ {
PyObject *r; PyObject *r;
UNLESS (r=PyDict_GetItem(self->data, key)) r = PyDict_GetItem(self->data, key);
{ if (!r) {
PyErr_SetObject(PyExc_KeyError, key); PyErr_SetObject(PyExc_KeyError, key);
return NULL; return NULL;
} }
Py_INCREF(r); Py_INCREF(r);
...@@ -583,8 +590,7 @@ cc_subscript(ccobject *self, PyObject *key) ...@@ -583,8 +590,7 @@ cc_subscript(ccobject *self, PyObject *key)
static int static int
cc_ass_sub(ccobject *self, PyObject *key, PyObject *v) cc_ass_sub(ccobject *self, PyObject *key, PyObject *v)
{ {
if(v) if (v) {
{
if (PyExtensionClass_Check(v) if (PyExtensionClass_Check(v)
|| ||
(PyExtensionInstance_Check(v) (PyExtensionInstance_Check(v)
...@@ -629,10 +635,6 @@ static PyTypeObject Cctype = { ...@@ -629,10 +635,6 @@ static PyTypeObject Cctype = {
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/ (ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
/* Space for future expansion */
0L,0L,0L,0L,
""
}; };
static PyObject * static PyObject *
...@@ -641,9 +643,9 @@ cCM_new(PyObject *self, PyObject *args) ...@@ -641,9 +643,9 @@ cCM_new(PyObject *self, PyObject *args)
int cache_size=100, cache_age=1000; int cache_size=100, cache_age=1000;
PyObject *jar; PyObject *jar;
UNLESS(PyArg_ParseTuple(args, "O|ii", &jar, &cache_size, &cache_age)) if (!PyArg_ParseTuple(args, "O|ii", &jar, &cache_size, &cache_age))
return NULL; return NULL;
return (PyObject*)newccobject(jar, cache_size,cache_age); return (PyObject *)newccobject(jar, cache_size, cache_age);
} }
static struct PyMethodDef cCM_methods[] = { static struct PyMethodDef cCM_methods[] = {
...@@ -654,22 +656,17 @@ static struct PyMethodDef cCM_methods[] = { ...@@ -654,22 +656,17 @@ static struct PyMethodDef cCM_methods[] = {
void void
initcPickleCache(void) initcPickleCache(void)
{ {
PyObject *m, *d; PyObject *m;
Cctype.ob_type=&PyType_Type; Cctype.ob_type = &PyType_Type;
UNLESS(ExtensionClassImported) return; if (!ExtensionClassImported)
return;
m = Py_InitModule4("cPickleCache", cCM_methods, cPickleCache_doc_string, m = Py_InitModule4("cPickleCache", cCM_methods, cPickleCache_doc_string,
(PyObject*)NULL, PYTHON_API_VERSION); (PyObject*)NULL, PYTHON_API_VERSION);
d = PyModule_GetDict(m); py_reload = PyString_InternFromString("reload");
py__p_jar = PyString_InternFromString("_p_jar");
py_reload=PyString_FromString("reload"); py__p_changed = PyString_InternFromString("_p_changed");
py__p_jar=PyString_FromString("_p_jar");
py__p_changed=PyString_FromString("_p_changed");
/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module cPickleCache");
} }
...@@ -13,12 +13,7 @@ ...@@ -13,12 +13,7 @@
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.38 2002/01/25 14:51:55 gvanrossum Exp $\n"; "$Id: cPickleCache.c,v 1.39 2002/02/11 19:43:55 jeremy Exp $\n";
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
#define OBJECT(O) ((PyObject*)O)
/* Compute the current time in the units and range used for peristent /* Compute the current time in the units and range used for peristent
objects. */ objects. */
...@@ -33,23 +28,23 @@ static char cPickleCache_doc_string[] = ...@@ -33,23 +28,23 @@ static char cPickleCache_doc_string[] =
static PyObject *py_reload, *py__p_jar, *py__p_changed; static PyObject *py_reload, *py__p_jar, *py__p_changed;
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *data; PyObject *data;
PyObject *jar; PyObject *jar;
PyObject *setklassstate; PyObject *setklassstate;
int position; int position;
int cache_size; int cache_size;
int cache_age; int cache_age;
/* Cache statistics */ /* Cache statistics */
int sum_deal; int sum_deal;
int sum_deac; int sum_deac;
double sum_age; double sum_age;
int n, na; int n, na;
time_t last_check; /* Time of last gc */ time_t last_check; /* Time of last gc */
double mean_age; double mean_age;
double mean_deal; double mean_deal;
double mean_deac; double mean_deac;
double df, dfa; /* Degees of freedom for above stats */ double df, dfa; /* Degees of freedom for above stats */
} ccobject; } ccobject;
#define WEIGHTING_PERIOD 600 #define WEIGHTING_PERIOD 600
...@@ -74,102 +69,116 @@ staticforward PyTypeObject Cctype; ...@@ -74,102 +69,116 @@ staticforward PyTypeObject Cctype;
static int static int
gc_item(ccobject *self, PyObject *key, PyObject *v, long now, int dt) gc_item(ccobject *self, PyObject *key, PyObject *v, long now, int dt)
{ {
if (v && key) if (!(v && key))
{ return 0;
self->n++; self->n++;
if(v->ob_refcnt <= 1)
{ /* If there is at most one reference to this object, then the
self->sum_deal++; cache has the only reference. It can be removed. */
/* XXX The fact that this works will iterating over if (v->ob_refcnt <= 1) {
self->data with PyDict_Next() is an accident of the self->sum_deal++;
current Python dictionary implementation. */ /* XXX The fact that this works will iterating over
return PyDict_DelItem(self->data, key); self->data with PyDict_Next() is an accident of the
} current Python dictionary implementation. */
return PyDict_DelItem(self->data, key);
}
if (dt >= 0 && if (dt >= 0 &&
(! PyExtensionClass_Check(v)) && (!PyExtensionClass_Check(v)) &&
((cPersistentObject*)v)->jar == self->jar /* I'm paranoid */ && ((cPersistentObject*)v)->jar == self->jar /* I'm paranoid */ &&
((cPersistentObject*)v)->state == cPersistent_UPTODATE_STATE ((cPersistentObject*)v)->state == cPersistent_UPTODATE_STATE) {
) now -= ((cPersistentObject*)v)->atime;
{ if (now < 0)
now -= ((cPersistentObject*)v)->atime; now += 65536;
if (now < 0) self->na++;
now += 65536; self->sum_age += now;
self->na++; if (now > dt) {
self->sum_age += now; /* We have a cPersistent object that hasn't been used in
if (now > dt) a while. Reinitialize it, hopefully freeing it's
{ state.
/* We have a cPersistent object that hasn't been used in */
a while. Reinitialize it, hopefully freeing it's self->sum_deac++;
state. if (PyObject_SetAttr(v, py__p_changed, Py_None) < 0)
*/
self->sum_deac++;
if (PyObject_SetAttr(v, py__p_changed, Py_None) < 0)
PyErr_Clear(); PyErr_Clear();
}
} }
} }
return 0; return 0;
} }
static void static void
update_stats(ccobject *self, time_t now) update_stats(ccobject *self, time_t now)
{ {
double d, deal, deac; double d, deal, deac;
d=now-self->last_check; d = now - self->last_check;
if(d < 1) return; if(d < 1)
return;
self->df *= WEIGHTING_PERIOD/(WEIGHTING_PERIOD+d);
self->dfa *= WEIGHTING_PERIOD/(WEIGHTING_PERIOD+d); self->df *= WEIGHTING_PERIOD / (WEIGHTING_PERIOD + d);
self->dfa *= WEIGHTING_PERIOD / (WEIGHTING_PERIOD + d);
self->mean_age=((self->mean_age*self->dfa+self->sum_age)/
(self->dfa+self->na))*3; self->mean_age = ((self->mean_age * self->dfa + self->sum_age)/
self->sum_age=0; (self->dfa + self->na)) * 3;
self->sum_age = 0;
deac=self->sum_deac/d;
self->sum_deac=0; deac = self->sum_deac / d;
self->mean_deac=((self->mean_deac*self->dfa+deac)/ self->sum_deac = 0;
(self->dfa+self->na)); self->mean_deac = ((self->mean_deac * self->dfa+deac)/
self->sum_deac=0; (self->dfa + self->na));
self->sum_deac = 0;
self->dfa += self->na;
self->na=0; self->dfa += self->na;
self->na = 0;
deal=self->sum_deal/d;
self->sum_deal = 0;
self->mean_deal = ((self->mean_deal * self->df + deal)/
(self->df +self->n));
self->sum_deal = 0;
self->df += self->n;
self->n = 0;
self->last_check = now;
}
deal=self->sum_deal/d; static int
self->sum_deal=0; check_size(ccobject *self)
self->mean_deal=((self->mean_deal*self->df +deal)/ {
(self->df +self->n)); if (self->cache_size < 1)
self->sum_deal=0; return 0;
return PyDict_Size(self->data);
}
self->df += self->n; static int
self->n=0; gc_all_items(ccobject *self, int now, int dt)
{
PyObject *key, *v;
int i;
self->last_check=now; for(i = 0; PyDict_Next(self->data, &i, &key, &v); )
if (gc_item(self, key, v, now, dt) < 0)
return -1;
return 0;
} }
static int static int
fullgc(ccobject *self, int dt) fullgc(ccobject *self, int dt)
{ {
PyObject *key, *v; long now;
int i;
long now;
if (self->cache_size < 1) if (check_size(self) <= 0)
return 0; return 0;
if ((i=PyDict_Size(self->data)) < 1)
return 0;
now = PER_TIME(); now = PER_TIME();
if (dt > 0) dt /= 3;
dt /= 3;
for(i=0; PyDict_Next(self->data, &i, &key, &v); ) if (gc_all_items(self, now, dt) < 0)
if (gc_item(self, key, v, now, dt) < 0)
return -1; return -1;
self->position=0; self->position = 0;
if(now-self->last_check > 1) update_stats(self, now); if (now - self->last_check > 1)
update_stats(self, now);
return 0; return 0;
} }
...@@ -177,139 +186,135 @@ fullgc(ccobject *self, int dt) ...@@ -177,139 +186,135 @@ fullgc(ccobject *self, int dt)
static int static int
reallyfullgc(ccobject *self, int dt) reallyfullgc(ccobject *self, int dt)
{ {
PyObject *key, *v; int l, last;
int i, l, last; time_t now;
time_t now;
if (self->cache_size < 1)
return 0;
last = PyDict_Size(self->data);
if (last < 0)
return -1;
now = PER_TIME(); last = check_size(self);
if (dt > 0) if (last <= 0)
dt /= 3; return 0;
/* First time through should get refcounts to 1 */ now = PER_TIME();
for(i=0; PyDict_Next(self->data, &i, &key, &v); ) /* Units are 3 seconds */
if (gc_item(self, key, v, now, dt) < 0) dt /= 3;
return -1;
l = PyDict_Size(self->data); /* First time through should get refcounts to 1 */
if (gc_all_items(self, now, dt) < 0)
return -1;
if (l < 0) l = PyDict_Size(self->data);
return -1; if (l < 0)
return -1;
while (l < last) /* Now continue to collect until the size of the cache stops
{ decreasing. */
for (i=0; PyDict_Next(self->data, &i, &key, &v); ) while (l < last) {
if (gc_item(self, key, v, now, dt) < 0) if (gc_all_items(self, now, dt) < 0)
return -1; return -1;
last = l; last = l;
l = PyDict_Size(self->data); l = PyDict_Size(self->data);
if (l < 0) if (l < 0)
return -1; return -1;
} }
if(now-self->last_check > 1) update_stats(self, now); if (now - self->last_check > 1)
update_stats(self, now);
self->position=0;
return 0; self->position = 0;
return 0;
} }
static int static int
maybegc(ccobject *self, PyObject *thisv) maybegc(ccobject *self, PyObject *thisv)
{ {
int n, s, size, dt; int n, s, size, dt;
long now; long now;
PyObject *key=0, *v=0; PyObject *key=0, *v=0;
if (self->cache_size < 1) return 0; s = check_size(self);
s=PyDict_Size(self->data); if (s <= 0)
if (s < 1) return s; return 0;
now = PER_TIME(); now = PER_TIME();
size=self->cache_size; size = self->cache_size;
self->cache_size=0; self->cache_size = 0;
/* Decide how many objects to look at */ /* Decide how many objects to look at */
n=(s-size)/10; n = (s - size) / 10;
if (n < 3) n=3; if (n < 3)
n = 3;
/* Decide how much time to give them before deactivating them */
s=8*size/s; /* Decide how much time to give them before deactivating them */
if (s > 100) s=100; s = 8 * size / s;
dt=(long)(self->cache_age*(0.2+0.1*s)); if (s > 100)
s = 100;
/* Units are 3 seconds */ dt = (long)(self->cache_age * (0.2 + 0.1 * s));
dt /= 3;
/* Units are 3 seconds */
if (dt < 1) dt=1; dt /= 3;
while (--n >= 0) while (--n >= 0) {
{ if (PyDict_Next(self->data, &(self->position), &key, &v)) {
if (PyDict_Next(self->data, &(self->position), &key, &v)) if (v != thisv && gc_item(self, key, v, now, dt) < 0) {
{ self->cache_size=size;
if (v != thisv && gc_item(self,key,v,now,dt) < 0) return -1;
{
self->cache_size=size;
return -1;
} }
} }
else else
self->position=0; self->position = 0;
} }
self->cache_size=size; self->cache_size = size;
if (now-self->last_check > 1) update_stats(self, now); if (now - self->last_check > 1)
update_stats(self, now);
return 0; return 0;
} }
static PyObject * static PyObject *
cc_full_sweep(ccobject *self, PyObject *args) cc_full_sweep(ccobject *self, PyObject *args)
{ {
int dt = self->cache_age; int dt = self->cache_age;
UNLESS(PyArg_ParseTuple(args, "|i:full_sweep", &dt)) return NULL; if (!PyArg_ParseTuple(args, "|i:full_sweep", &dt))
if (dt < -1) return NULL;
{ if (dt < -1) {
PyErr_SetString(PyExc_ValueError, "age must be >= -1"); PyErr_SetString(PyExc_ValueError, "age must be >= -1");
return NULL; return NULL;
} }
if (fullgc(self, dt) == -1) if (fullgc(self, dt) == -1)
return NULL; return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
static PyObject * static PyObject *
cc_reallyfull_sweep(ccobject *self, PyObject *args) cc_reallyfull_sweep(ccobject *self, PyObject *args)
{ {
int dt = self->cache_age; int dt = self->cache_age;
UNLESS(PyArg_ParseTuple(args, "|i:minimize", &dt)) return NULL; if (!PyArg_ParseTuple(args, "|i:minimize", &dt))
if (dt < -1) return NULL;
{ if (dt < -1) {
PyErr_SetString(PyExc_ValueError, "age must be >= -1"); PyErr_SetString(PyExc_ValueError, "age must be >= -1");
return NULL; return NULL;
} }
if (reallyfullgc(self, dt) == -1) if (reallyfullgc(self, dt) == -1)
return NULL; return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
static PyObject * static PyObject *
cc_incrgc(ccobject *self, PyObject *args) cc_incrgc(ccobject *self, PyObject *args)
{ {
int n=1; int n = 1;
UNLESS (PyArg_ParseTuple(args, "|i:incrgr",&n)) return NULL; if (!PyArg_ParseTuple(args, "|i:incrgr", &n))
return NULL;
for (; --n >= 0;) for (; --n >= 0;)
if(maybegc(self,NULL) < 0) return NULL; if (maybegc(self, NULL) < 0)
return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
...@@ -317,114 +322,108 @@ cc_incrgc(ccobject *self, PyObject *args) ...@@ -317,114 +322,108 @@ cc_incrgc(ccobject *self, PyObject *args)
static void static void
_invalidate(ccobject *self, PyObject *key) _invalidate(ccobject *self, PyObject *key)
{ {
PyObject *v; PyObject *v = PyDict_GetItem(self->data, key);
if ((v=PyDict_GetItem(self->data, key))) if (!v)
{ return;
if (PyExtensionClass_Check(v)) if (PyExtensionClass_Check(v))
if(v->ob_refcnt <= 1) if (v->ob_refcnt <= 1) {
{
self->sum_deal++; self->sum_deal++;
if (PyDict_DelItem(self->data, key) < 0) if (PyDict_DelItem(self->data, key) < 0)
PyErr_Clear(); PyErr_Clear();
} } else {
else
{
PyObject *t = PyTuple_New(1); PyObject *t = PyTuple_New(1);
if (t) if (t) {
{
PyTuple_SET_ITEM(t, 0, v); PyTuple_SET_ITEM(t, 0, v);
v = PyObject_CallObject(self->setklassstate, t); v = PyObject_CallObject(self->setklassstate, t);
/* Set tuple element to NULL so that deallocating the
tuple does not decref t.
*/
PyTuple_SET_ITEM(t, 0, NULL); PyTuple_SET_ITEM(t, 0, NULL);
Py_DECREF(t); Py_DECREF(t);
} } else
else
{
v = t; v = t;
} if (v)
if (v) Py_DECREF(v); Py_DECREF(v);
else PyErr_Clear(); else
} PyErr_Clear();
else if (PyObject_DelAttr(v,py__p_changed) < 0) }
PyErr_Clear(); else if (PyObject_DelAttr(v, py__p_changed) < 0)
}
else
{
if (PyErr_Occurred())
PyErr_Clear(); PyErr_Clear();
} }
static void
_invalidate_all(ccobject *self)
{
PyObject *key, *v;
int i;
for (i = 0; PyDict_Next(self->data, &i, &key, &v); )
_invalidate(self, key);
} }
static PyObject * static PyObject *
cc_invalidate(ccobject *self, PyObject *args) cc_invalidate(ccobject *self, PyObject *args)
{ {
PyObject *inv, *key, *v; PyObject *inv, *key, *v;
int i; int i;
if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) { if (!PyArg_ParseTuple(args, "O:invalidate", &inv))
for (i=0; PyDict_Next(inv, &i, &key, &v); ) return NULL;
if (key==Py_None) if (PyDict_Check(inv)) {
{ /* Eek some nitwit invalidated everything! */ for (i = 0; PyDict_Next(inv, &i, &key, &v); )
for (i=0; PyDict_Next(self->data, &i, &key, &v); ) if (key == Py_None) {
_invalidate(self, key); /* Eek some nitwit invalidated everything! */
break; _invalidate_all(self);
} break;
else }
_invalidate(self, key); else
PyDict_Clear(inv); _invalidate(self, key);
} PyDict_Clear(inv);
else { } else if (PyString_Check(inv))
PyErr_Clear(); _invalidate(self, inv);
UNLESS (PyArg_ParseTuple(args, "O:invalidate", &inv)) return NULL; else if (inv == Py_None) /* All */
if (PyString_Check(inv)) _invalidate_all(self);
_invalidate(self, inv);
else if (inv==Py_None) /* All */
for (i=0; PyDict_Next(self->data, &i, &key, &v); )
_invalidate(self, key);
else { else {
int l; int l = PyObject_Length(inv);
PyErr_Clear(); if (l < 0)
if ((l=PyObject_Length(inv)) < 0) return NULL; return NULL;
for(i=l; --i >= 0; ) for (i = l; --i >= 0; ) {
{ key = PySequence_GetItem(inv, i);
UNLESS (key=PySequence_GetItem(inv, i)) return NULL; if (!key)
_invalidate(self, key); return NULL;
Py_DECREF(key); _invalidate(self, key);
Py_DECREF(key);
} }
PySequence_DelSlice(inv, 0, l); PySequence_DelSlice(inv, 0, l);
} }
}
Py_INCREF(Py_None);
Py_INCREF(Py_None); return Py_None;
return Py_None;
} }
static PyObject * static PyObject *
cc_get(ccobject *self, PyObject *args) cc_get(ccobject *self, PyObject *args)
{ {
PyObject *r, *key, *d=0; PyObject *r, *key, *d = NULL;
UNLESS (PyArg_ParseTuple(args, "O|O:get", &key, &d)) return NULL;
UNLESS (r=PyDict_GetItem(self->data, key)) if (!PyArg_ParseTuple(args, "O|O:get", &key, &d))
{ return NULL;
if (d)
{ r = PyDict_GetItem(self->data, key);
if (PyErr_Occurred()) if (!r) {
PyErr_Clear(); if (d)
r=d; r = d;
} else {
else PyErr_SetObject(PyExc_KeyError, key);
{ return NULL;
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
} }
} }
Py_INCREF(r); Py_INCREF(r);
return r; return r;
} }
...@@ -454,107 +453,115 @@ static struct PyMethodDef cc_methods[] = { ...@@ -454,107 +453,115 @@ static struct PyMethodDef cc_methods[] = {
static ccobject * static ccobject *
newccobject(PyObject *jar, int cache_size, int cache_age) newccobject(PyObject *jar, int cache_size, int cache_age)
{ {
ccobject *self; ccobject *self;
UNLESS(self = PyObject_NEW(ccobject, &Cctype)) return NULL; self = PyObject_NEW(ccobject, &Cctype);
self->setklassstate=self->jar=NULL; if (!self)
if((self->data=PyDict_New()))
{
self->jar=jar;
Py_INCREF(jar);
UNLESS (self->setklassstate=PyObject_GetAttrString(jar, "setklassstate"))
return NULL; return NULL;
self->position=0; self->setklassstate = self->jar = NULL;
self->cache_size=cache_size; self->data = PyDict_New();
self->cache_age=cache_age < 1 ? 1 : cache_age; if (self->data) {
self->sum_deal=0; self->jar=jar;
self->sum_deac=0; Py_INCREF(jar);
self->sum_age=0; self->setklassstate = PyObject_GetAttrString(jar, "setklassstate");
self->mean_deal=0; if (!self->setklassstate) {
self->mean_deac=0; Py_DECREF(jar);
self->mean_age=0; Py_DECREF(self->data);
self->df=1; goto error;
self->dfa=1; }
self->n=0; self->position = 0;
self->na=0; self->cache_size = cache_size;
self->last_check=time(NULL); self->cache_age = cache_age < 1 ? 1 : cache_age;
return self; self->sum_deal = 0;
self->sum_deac = 0;
self->sum_age = 0;
self->mean_deal = 0;
self->mean_deac = 0;
self->mean_age = 0;
self->df = 1;
self->dfa = 1;
self->n = 0;
self->na = 0;
self->last_check = time(NULL);
return self;
} }
Py_DECREF(self); error:
return NULL; Py_DECREF(self);
return NULL;
} }
static void static void
cc_dealloc(ccobject *self) cc_dealloc(ccobject *self)
{ {
Py_XDECREF(self->data); Py_XDECREF(self->data);
Py_XDECREF(self->jar); Py_XDECREF(self->jar);
Py_XDECREF(self->setklassstate); Py_XDECREF(self->setklassstate);
PyMem_DEL(self); PyMem_DEL(self);
} }
static PyObject * static PyObject *
cc_getattr(ccobject *self, char *name) cc_getattr(ccobject *self, char *name)
{ {
PyObject *r; PyObject *r;
if(*name=='c') if (*name == 'c') {
{ if(strcmp(name, "cache_age") == 0)
if(strcmp(name,"cache_age")==0) return PyInt_FromLong(self->cache_age);
return PyInt_FromLong(self->cache_age); if(strcmp(name, "cache_size") == 0)
if(strcmp(name,"cache_size")==0) return PyInt_FromLong(self->cache_size);
return PyInt_FromLong(self->cache_size); if(strcmp(name, "cache_mean_age") == 0)
if(strcmp(name,"cache_mean_age")==0) return PyFloat_FromDouble(self->mean_age);
return PyFloat_FromDouble(self->mean_age); if(strcmp(name, "cache_mean_deal") == 0)
if(strcmp(name,"cache_mean_deal")==0) return PyFloat_FromDouble(self->mean_deal);
return PyFloat_FromDouble(self->mean_deal); if(strcmp(name, "cache_mean_deac") == 0)
if(strcmp(name,"cache_mean_deac")==0) return PyFloat_FromDouble(self->mean_deac);
return PyFloat_FromDouble(self->mean_deac); if(strcmp(name, "cache_df") == 0)
if(strcmp(name,"cache_df")==0) return PyFloat_FromDouble(self->df);
return PyFloat_FromDouble(self->df); if(strcmp(name, "cache_dfa") == 0)
if(strcmp(name,"cache_dfa")==0) return PyFloat_FromDouble(self->dfa);
return PyFloat_FromDouble(self->dfa); if(strcmp(name, "cache_last_gc_time") == 0)
if(strcmp(name,"cache_last_gc_time")==0) return PyFloat_FromDouble(self->last_check);
return PyFloat_FromDouble(self->last_check); if(strcmp(name, "cache_data") == 0) {
if(strcmp(name,"cache_data")==0) Py_INCREF(self->data);
{ return self->data;
Py_INCREF(self->data);
return self->data;
} }
} }
if((*name=='h' && strcmp(name, "has_key")==0) || if ((strcmp(name, "has_key") == 0)
(*name=='i' && strcmp(name, "items")==0) || || (strcmp(name, "items") == 0)
(*name=='k' && strcmp(name, "keys")==0) || (strcmp(name, "keys") == 0))
) return PyObject_GetAttrString(self->data, name);
return PyObject_GetAttrString(self->data, name);
r = Py_FindMethod(cc_methods, (PyObject *)self, name);
if((r=Py_FindMethod(cc_methods, (PyObject *)self, name))) if (!r) {
PyErr_Clear();
return PyObject_GetAttrString(self->data, name);
}
return r; return r;
PyErr_Clear();
return PyObject_GetAttrString(self->data, name);
} }
static int static int
cc_setattr(ccobject *self, char *name, PyObject *value) cc_setattr(ccobject *self, char *name, PyObject *value)
{ {
if(value) if (value) {
{
int v; int v;
if(strcmp(name,"cache_age")==0) if (strcmp(name, "cache_age") == 0) {
{ v = PyInt_AsLong(value);
UNLESS(PyArg_Parse(value,"i",&v)) return -1; if (v == -1 && PyErr_Occurred())
if(v > 0)self->cache_age=v; return -1;
if (v > 0)
self->cache_age = v;
return 0; return 0;
} }
if(strcmp(name,"cache_size")==0) if (strcmp(name, "cache_size") == 0) {
{ v = PyInt_AsLong(value);
UNLESS(PyArg_Parse(value,"i",&v)) return -1; if (v == -1 && PyErr_Occurred())
self->cache_size=v; return -1;
self->cache_size = v;
return 0; return 0;
} }
} }
PyErr_SetString(PyExc_AttributeError, name); PyErr_SetString(PyExc_AttributeError, name);
return -1; return -1;
} }
...@@ -562,7 +569,7 @@ cc_setattr(ccobject *self, char *name, PyObject *value) ...@@ -562,7 +569,7 @@ cc_setattr(ccobject *self, char *name, PyObject *value)
static int static int
cc_length(ccobject *self) cc_length(ccobject *self)
{ {
return PyObject_Length(self->data); return PyDict_Size(self->data);
} }
static PyObject * static PyObject *
...@@ -570,10 +577,10 @@ cc_subscript(ccobject *self, PyObject *key) ...@@ -570,10 +577,10 @@ cc_subscript(ccobject *self, PyObject *key)
{ {
PyObject *r; PyObject *r;
UNLESS (r=PyDict_GetItem(self->data, key)) r = PyDict_GetItem(self->data, key);
{ if (!r) {
PyErr_SetObject(PyExc_KeyError, key); PyErr_SetObject(PyExc_KeyError, key);
return NULL; return NULL;
} }
Py_INCREF(r); Py_INCREF(r);
...@@ -583,8 +590,7 @@ cc_subscript(ccobject *self, PyObject *key) ...@@ -583,8 +590,7 @@ cc_subscript(ccobject *self, PyObject *key)
static int static int
cc_ass_sub(ccobject *self, PyObject *key, PyObject *v) cc_ass_sub(ccobject *self, PyObject *key, PyObject *v)
{ {
if(v) if (v) {
{
if (PyExtensionClass_Check(v) if (PyExtensionClass_Check(v)
|| ||
(PyExtensionInstance_Check(v) (PyExtensionInstance_Check(v)
...@@ -629,10 +635,6 @@ static PyTypeObject Cctype = { ...@@ -629,10 +635,6 @@ static PyTypeObject Cctype = {
(hashfunc)0, /*tp_hash*/ (hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/ (ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/ (reprfunc)0, /*tp_str*/
/* Space for future expansion */
0L,0L,0L,0L,
""
}; };
static PyObject * static PyObject *
...@@ -641,9 +643,9 @@ cCM_new(PyObject *self, PyObject *args) ...@@ -641,9 +643,9 @@ cCM_new(PyObject *self, PyObject *args)
int cache_size=100, cache_age=1000; int cache_size=100, cache_age=1000;
PyObject *jar; PyObject *jar;
UNLESS(PyArg_ParseTuple(args, "O|ii", &jar, &cache_size, &cache_age)) if (!PyArg_ParseTuple(args, "O|ii", &jar, &cache_size, &cache_age))
return NULL; return NULL;
return (PyObject*)newccobject(jar, cache_size,cache_age); return (PyObject *)newccobject(jar, cache_size, cache_age);
} }
static struct PyMethodDef cCM_methods[] = { static struct PyMethodDef cCM_methods[] = {
...@@ -654,22 +656,17 @@ static struct PyMethodDef cCM_methods[] = { ...@@ -654,22 +656,17 @@ static struct PyMethodDef cCM_methods[] = {
void void
initcPickleCache(void) initcPickleCache(void)
{ {
PyObject *m, *d; PyObject *m;
Cctype.ob_type=&PyType_Type; Cctype.ob_type = &PyType_Type;
UNLESS(ExtensionClassImported) return; if (!ExtensionClassImported)
return;
m = Py_InitModule4("cPickleCache", cCM_methods, cPickleCache_doc_string, m = Py_InitModule4("cPickleCache", cCM_methods, cPickleCache_doc_string,
(PyObject*)NULL, PYTHON_API_VERSION); (PyObject*)NULL, PYTHON_API_VERSION);
d = PyModule_GetDict(m); py_reload = PyString_InternFromString("reload");
py__p_jar = PyString_InternFromString("_p_jar");
py_reload=PyString_FromString("reload"); py__p_changed = PyString_InternFromString("_p_changed");
py__p_jar=PyString_FromString("_p_jar");
py__p_changed=PyString_FromString("_p_changed");
/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module cPickleCache");
} }
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