Commit ee678d39 authored by Jim Fulton's avatar Jim Fulton

Added object-deactivation support. This only works with cPersistent

objects.
parent ad26c082
/* /*
$Id: cPickleCache.c,v 1.1 1997/02/17 18:39:02 jim Exp $ $Id: cPickleCache.c,v 1.2 1997/03/11 20:48:38 jim Exp $
C implementation of a pickle jar cache. C implementation of a pickle jar cache.
...@@ -56,23 +56,18 @@ ...@@ -56,23 +56,18 @@
(540) 371-6909 (540) 371-6909
***************************************************************************/ ***************************************************************************/
static char *what_string = "$Id: cPickleCache.c,v 1.1 1997/02/17 18:39:02 jim Exp $"; static char *what_string = "$Id: cPickleCache.c,v 1.2 1997/03/11 20:48:38 jim Exp $";
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V) #define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
#define Py_ASSIGN(P,E) if(!PyObject_AssignExpression(&(P),(E))) return NULL #define Py_ASSIGN(P,E) if(!PyObject_AssignExpression(&(P),(E))) return NULL
#ifdef __cplusplus
#define ARG(T,N) T N
#define ARGDECL(T,N)
#else
#define ARG(T,N) N
#define ARGDECL(T,N) T N;
#endif
#include "Python.h" #include "Python.h"
static PyObject *py_reload, *py__p_jar, *py__p_atime;
/* Declarations for objects of type cCache */ /* Declarations for objects of type cCache */
typedef struct { typedef struct {
...@@ -80,50 +75,91 @@ typedef struct { ...@@ -80,50 +75,91 @@ typedef struct {
PyObject *data; PyObject *data;
int position; int position;
int cache_size; int cache_size;
int cache_age;
} ccobject; } ccobject;
staticforward PyTypeObject Cctype; staticforward PyTypeObject Cctype;
static PyObject *PATimeType=NULL;
typedef struct {
PyObject_HEAD
time_t value;
} PATimeobject;
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
static char cc_full_sweep__doc__[] =
"Perform a full sweep of the cache, looking for objects that can be removed" static int
; gc_item(ccobject *self, PyObject *key, PyObject *v, time_t now, time_t dt)
{
PyObject *atime;
if(v && key)
{
if(PyTuple_GET_ITEM(v,0)->ob_refcnt <= 1)
{
UNLESS(-1 != PyDict_DelItem(self->data, key)) return -1;
}
else if((atime=PyTuple_GET_ITEM(v,1)) &&
now-((PATimeobject*)atime)->value >dt)
{
/* We have a cPersistent object that hasn't been used in
a while. Reinitialize it, hopefully freeing it's state.
*/
v=PyTuple_GET_ITEM(v,0);
UNLESS(key=PyObject_GetAttr(v,py__p_jar)) return -1;
if(key!=Py_None)
{
UNLESS_ASSIGN(key,PyObject_GetAttr(key,py_reload)) return -1;
UNLESS_ASSIGN(key,PyObject_CallFunction(key,"(O)",v))
return -1;
}
Py_DECREF(key);
}
}
return 0;
}
static int static int
fullgc(ARG(ccobject *, self)) fullgc(ccobject *self)
ARGDECL(ccobject *, self)
{ {
PyObject *key, *v; PyObject *key, *v;
int i, l; int i;
time_t now, dt;
i=PyDict_Size(self->data)-3/self->cache_size;
if(i < 3) i=3;
dt=self->cache_age*3/i;
if(dt < 60) dt=60;
now=time(NULL);
for(i=0; PyDict_Next(self->data, &i, &key, &v); ) for(i=0; PyDict_Next(self->data, &i, &key, &v); )
{ if(gc_item(self,key,v,now,dt) < 0) return -1;
if(v->ob_refcnt <= 1)
UNLESS(-1 != PyDict_DelItem(self->data, key)) return -1;
}
self->position=0; self->position=0;
return 0; return 0;
} }
static int static int
maybegc(ARG(ccobject *, self)) maybegc(ccobject *self)
ARGDECL(ccobject *, self)
{ {
int n, s, p; int n, s;
int r; time_t now,dt;
PyObject *key=0, *v=0; PyObject *key=0, *v=0, *atime;
s=PyDict_Size(self->data)-3; s=PyDict_Size(self->data)-3;
if(s < self->cache_size) return 0; if(s < self->cache_size) return 0;
n=s/self->cache_size; n=s/self->cache_size;
if(n < 3) n=3; if(n < 3) n=3;
dt=3 * self->cache_age/n;
if(dt < 60) dt=60;
now=time(NULL);
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 && key && v->ob_refcnt <= 1) if(gc_item(self,key,v,now,dt) < 0) return -1;
UNLESS(-1 != PyDict_DelItem(self->data, key)) return -1;
} }
else else
self->position=0; self->position=0;
...@@ -132,9 +168,7 @@ maybegc(ARG(ccobject *, self)) ...@@ -132,9 +168,7 @@ maybegc(ARG(ccobject *, self))
} }
static PyObject * static PyObject *
cc_full_sweep(ARG(ccobject *, self), ARG(PyObject *, args)) cc_full_sweep(ccobject *self, PyObject *args)
ARGDECL(ccobject *, self)
ARGDECL(PyObject *, args)
{ {
UNLESS(PyArg_Parse(args, "")) return NULL; UNLESS(PyArg_Parse(args, "")) return NULL;
UNLESS(-1 != fullgc(self)) return NULL; UNLESS(-1 != fullgc(self)) return NULL;
...@@ -143,7 +177,9 @@ cc_full_sweep(ARG(ccobject *, self), ARG(PyObject *, args)) ...@@ -143,7 +177,9 @@ cc_full_sweep(ARG(ccobject *, self), ARG(PyObject *, args))
} }
static struct PyMethodDef cc_methods[] = { static struct PyMethodDef cc_methods[] = {
{"full_sweep", (PyCFunction)cc_full_sweep, 0, cc_full_sweep__doc__}, {"full_sweep", (PyCFunction)cc_full_sweep, 0,
"Perform a full sweep of the cache, looking for objects that can be removed"
},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
...@@ -151,8 +187,7 @@ static struct PyMethodDef cc_methods[] = { ...@@ -151,8 +187,7 @@ static struct PyMethodDef cc_methods[] = {
static ccobject * static ccobject *
newccobject(ARG(int,cache_size)) newccobject(int cache_size, int cache_age)
ARGDECL(int,cache_size)
{ {
ccobject *self; ccobject *self;
...@@ -161,6 +196,7 @@ newccobject(ARG(int,cache_size)) ...@@ -161,6 +196,7 @@ newccobject(ARG(int,cache_size))
{ {
self->position=0; self->position=0;
self->cache_size=cache_size < 1 ? 1 : cache_size; self->cache_size=cache_size < 1 ? 1 : cache_size;
self->cache_age=cache_size < 1 ? 1 : cache_age;
return self; return self;
} }
Py_DECREF(self); Py_DECREF(self);
...@@ -169,17 +205,14 @@ newccobject(ARG(int,cache_size)) ...@@ -169,17 +205,14 @@ newccobject(ARG(int,cache_size))
static void static void
cc_dealloc(ARG(ccobject *, self)) cc_dealloc(ccobject *self)
ARGDECL(ccobject *, self)
{ {
Py_XDECREF(self->data); Py_XDECREF(self->data);
PyMem_DEL(self); PyMem_DEL(self);
} }
static PyObject * static PyObject *
cc_getattr(ARG(ccobject *, self), ARG(char *, name)) cc_getattr(ccobject *self, char *name)
ARGDECL(ccobject *, self)
ARGDECL(char *, name)
{ {
PyObject *r; PyObject *r;
if(r=Py_FindMethod(cc_methods, (PyObject *)self, name)) if(r=Py_FindMethod(cc_methods, (PyObject *)self, name))
...@@ -189,11 +222,8 @@ cc_getattr(ARG(ccobject *, self), ARG(char *, name)) ...@@ -189,11 +222,8 @@ cc_getattr(ARG(ccobject *, self), ARG(char *, name))
} }
static PyObject * static PyObject *
cc_repr(ARG(ccobject *, self)) cc_repr(ccobject *self)
ARGDECL(ccobject *, self)
{ {
PyObject *s;
return PyObject_Repr(self->data); return PyObject_Repr(self->data);
} }
...@@ -208,16 +238,13 @@ cc_str(self) ...@@ -208,16 +238,13 @@ cc_str(self)
/* Code to access cCache objects as mappings */ /* Code to access cCache objects as mappings */
static int static int
cc_length(ARG(ccobject *, self)) cc_length(ccobject *self)
ARGDECL(ccobject *, self)
{ {
return PyObject_Length(self->data); return PyObject_Length(self->data);
} }
static PyObject * static PyObject *
cc_subscript(ARG(ccobject *, self), ARG(PyObject *, key)) cc_subscript(ccobject *self, PyObject *key)
ARGDECL(ccobject *, self)
ARGDECL(PyObject *, key)
{ {
PyObject *r; PyObject *r;
...@@ -231,19 +258,37 @@ cc_subscript(ARG(ccobject *, self), ARG(PyObject *, key)) ...@@ -231,19 +258,37 @@ cc_subscript(ARG(ccobject *, self), ARG(PyObject *, key))
Py_DECREF(r); Py_DECREF(r);
return NULL; return NULL;
} }
ASSIGN(r,PySequence_GetItem(r,0));
return r; return r;
} }
static int static int
cc_ass_sub(ARG(ccobject *, self), cc_ass_sub(ccobject *self, PyObject *key, PyObject *v)
ARG(PyObject *, key), ARG(PyObject *, v))
ARGDECL(ccobject *, self)
ARGDECL(PyObject *, key)
ARGDECL(PyObject *, v)
{ {
if(v) if(v)
{ {
UNLESS(-1 != PyDict_SetItem(self->data,key, v)) return -1; PyObject *t;
/* Create a tuple to hold object and object access time */
UNLESS(t=PyTuple_New(2)) return -1;
/* Save value as first item in tuple */
Py_INCREF(v);
PyTuple_SET_ITEM(t,0,v);
/* Now get and save the access time */
if(v=PyObject_GetAttr(v,py__p_atime))
{
if(v->ob_type == (PyTypeObject *)PATimeType)
PyTuple_SET_ITEM(t,1,v);
else
Py_DECREF(v);
}
else
PyErr_Clear();
UNLESS(-1 != PyDict_SetItem(self->data,key,t)) return -1;
Py_DECREF(t);
} }
else else
{ {
...@@ -265,7 +310,7 @@ static char Cctype__doc__[] = ...@@ -265,7 +310,7 @@ static char Cctype__doc__[] =
; ;
static PyTypeObject Cctype = { static PyTypeObject Cctype = {
PyObject_HEAD_INIT(&PyType_Type) PyObject_HEAD_INIT(NULL)
0, /*ob_size*/ 0, /*ob_size*/
"cPickleCache", /*tp_name*/ "cPickleCache", /*tp_name*/
sizeof(ccobject), /*tp_basicsize*/ sizeof(ccobject), /*tp_basicsize*/
...@@ -292,26 +337,26 @@ static PyTypeObject Cctype = { ...@@ -292,26 +337,26 @@ static PyTypeObject Cctype = {
/* End of code for cCache objects */ /* End of code for cCache objects */
/* -------------------------------------------------------- */ /* -------------------------------------------------------- */
static char cCM_new__doc__[] =
""
;
static PyObject * static PyObject *
cCM_new(ARG(PyObject *, self), ARG(PyObject *, args)) cCM_new(PyObject *self, PyObject *args)
ARGDECL(PyObject *, self) /* Not used */
ARGDECL(PyObject *, args)
{ {
int cache_size=100; int cache_size=100, cache_age=1000;
UNLESS(PyArg_ParseTuple(args, "|i", &cache_size)) return NULL; UNLESS(PyArg_ParseTuple(args, "|ii", &cache_size, &cache_age)) return NULL;
return (PyObject*)newccobject(cache_size); return (PyObject*)newccobject(cache_size,cache_age);
} }
/* List of methods defined in the module */ /* List of methods defined in the module */
static struct PyMethodDef cCM_methods[] = { static struct PyMethodDef cCM_methods[] = {
{"PickleCache",(PyCFunction)cCM_new, 1, cCM_new__doc__}, {"PickleCache",(PyCFunction)cCM_new, 1,
"PickleCache([size,age]) -- Create a pickle jar cache\n\n"
"The cache will attempt to garbage collect items when the cache size is\n"
"greater than the given size, which defaults to 100. Normally, objects\n"
"are garbage collected if their reference count is one, meaning that\n"
"they are only referenced by the cache. In some cases, objects that\n"
"have not been accessed in 'age' seconds may be partially garbage\n"
"collected, meaning that most of their state is freed.\n"
},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
...@@ -326,23 +371,37 @@ void ...@@ -326,23 +371,37 @@ void
initcPickleCache() initcPickleCache()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.1 $"; char *rev="$Revision: 1.2 $";
Cctype.ob_type=&PyType_Type;
if(PATimeType=PyImport_ImportModule("cPersistence"))
ASSIGN(PATimeType,PyObject_GetAttrString(PATimeType,"atimeType"));
UNLESS(PATimeType) PyErr_Clear();
/* Create the module and add the functions */
m = Py_InitModule4("cPickleCache", cCM_methods, m = Py_InitModule4("cPickleCache", cCM_methods,
cCache_module_documentation, cCache_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION); (PyObject*)NULL,PYTHON_API_VERSION);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
py_reload=PyString_FromString("reload");
py__p_jar=PyString_FromString("_p_jar");
py__p_atime=PyString_FromString("_p_atime");
PyDict_SetItemString(d,"__version__", PyDict_SetItemString(d,"__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2)); PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
if (PyErr_Occurred()) Py_FatalError("can't initialize module cCache"); if (PyErr_Occurred()) Py_FatalError("can't initialize module cCache");
} }
/****************************************************************************** /******************************************************************************
$Log: cPickleCache.c,v $ $Log: cPickleCache.c,v $
Revision 1.2 1997/03/11 20:48:38 jim
Added object-deactivation support. This only works with cPersistent
objects.
Revision 1.1 1997/02/17 18:39:02 jim Revision 1.1 1997/02/17 18:39:02 jim
*** empty log message *** *** empty log message ***
......
/* /*
$Id: cPickleCache.c,v 1.1 1997/02/17 18:39:02 jim Exp $ $Id: cPickleCache.c,v 1.2 1997/03/11 20:48:38 jim Exp $
C implementation of a pickle jar cache. C implementation of a pickle jar cache.
...@@ -56,23 +56,18 @@ ...@@ -56,23 +56,18 @@
(540) 371-6909 (540) 371-6909
***************************************************************************/ ***************************************************************************/
static char *what_string = "$Id: cPickleCache.c,v 1.1 1997/02/17 18:39:02 jim Exp $"; static char *what_string = "$Id: cPickleCache.c,v 1.2 1997/03/11 20:48:38 jim Exp $";
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V) #define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
#define Py_ASSIGN(P,E) if(!PyObject_AssignExpression(&(P),(E))) return NULL #define Py_ASSIGN(P,E) if(!PyObject_AssignExpression(&(P),(E))) return NULL
#ifdef __cplusplus
#define ARG(T,N) T N
#define ARGDECL(T,N)
#else
#define ARG(T,N) N
#define ARGDECL(T,N) T N;
#endif
#include "Python.h" #include "Python.h"
static PyObject *py_reload, *py__p_jar, *py__p_atime;
/* Declarations for objects of type cCache */ /* Declarations for objects of type cCache */
typedef struct { typedef struct {
...@@ -80,50 +75,91 @@ typedef struct { ...@@ -80,50 +75,91 @@ typedef struct {
PyObject *data; PyObject *data;
int position; int position;
int cache_size; int cache_size;
int cache_age;
} ccobject; } ccobject;
staticforward PyTypeObject Cctype; staticforward PyTypeObject Cctype;
static PyObject *PATimeType=NULL;
typedef struct {
PyObject_HEAD
time_t value;
} PATimeobject;
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
static char cc_full_sweep__doc__[] =
"Perform a full sweep of the cache, looking for objects that can be removed" static int
; gc_item(ccobject *self, PyObject *key, PyObject *v, time_t now, time_t dt)
{
PyObject *atime;
if(v && key)
{
if(PyTuple_GET_ITEM(v,0)->ob_refcnt <= 1)
{
UNLESS(-1 != PyDict_DelItem(self->data, key)) return -1;
}
else if((atime=PyTuple_GET_ITEM(v,1)) &&
now-((PATimeobject*)atime)->value >dt)
{
/* We have a cPersistent object that hasn't been used in
a while. Reinitialize it, hopefully freeing it's state.
*/
v=PyTuple_GET_ITEM(v,0);
UNLESS(key=PyObject_GetAttr(v,py__p_jar)) return -1;
if(key!=Py_None)
{
UNLESS_ASSIGN(key,PyObject_GetAttr(key,py_reload)) return -1;
UNLESS_ASSIGN(key,PyObject_CallFunction(key,"(O)",v))
return -1;
}
Py_DECREF(key);
}
}
return 0;
}
static int static int
fullgc(ARG(ccobject *, self)) fullgc(ccobject *self)
ARGDECL(ccobject *, self)
{ {
PyObject *key, *v; PyObject *key, *v;
int i, l; int i;
time_t now, dt;
i=PyDict_Size(self->data)-3/self->cache_size;
if(i < 3) i=3;
dt=self->cache_age*3/i;
if(dt < 60) dt=60;
now=time(NULL);
for(i=0; PyDict_Next(self->data, &i, &key, &v); ) for(i=0; PyDict_Next(self->data, &i, &key, &v); )
{ if(gc_item(self,key,v,now,dt) < 0) return -1;
if(v->ob_refcnt <= 1)
UNLESS(-1 != PyDict_DelItem(self->data, key)) return -1;
}
self->position=0; self->position=0;
return 0; return 0;
} }
static int static int
maybegc(ARG(ccobject *, self)) maybegc(ccobject *self)
ARGDECL(ccobject *, self)
{ {
int n, s, p; int n, s;
int r; time_t now,dt;
PyObject *key=0, *v=0; PyObject *key=0, *v=0, *atime;
s=PyDict_Size(self->data)-3; s=PyDict_Size(self->data)-3;
if(s < self->cache_size) return 0; if(s < self->cache_size) return 0;
n=s/self->cache_size; n=s/self->cache_size;
if(n < 3) n=3; if(n < 3) n=3;
dt=3 * self->cache_age/n;
if(dt < 60) dt=60;
now=time(NULL);
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 && key && v->ob_refcnt <= 1) if(gc_item(self,key,v,now,dt) < 0) return -1;
UNLESS(-1 != PyDict_DelItem(self->data, key)) return -1;
} }
else else
self->position=0; self->position=0;
...@@ -132,9 +168,7 @@ maybegc(ARG(ccobject *, self)) ...@@ -132,9 +168,7 @@ maybegc(ARG(ccobject *, self))
} }
static PyObject * static PyObject *
cc_full_sweep(ARG(ccobject *, self), ARG(PyObject *, args)) cc_full_sweep(ccobject *self, PyObject *args)
ARGDECL(ccobject *, self)
ARGDECL(PyObject *, args)
{ {
UNLESS(PyArg_Parse(args, "")) return NULL; UNLESS(PyArg_Parse(args, "")) return NULL;
UNLESS(-1 != fullgc(self)) return NULL; UNLESS(-1 != fullgc(self)) return NULL;
...@@ -143,7 +177,9 @@ cc_full_sweep(ARG(ccobject *, self), ARG(PyObject *, args)) ...@@ -143,7 +177,9 @@ cc_full_sweep(ARG(ccobject *, self), ARG(PyObject *, args))
} }
static struct PyMethodDef cc_methods[] = { static struct PyMethodDef cc_methods[] = {
{"full_sweep", (PyCFunction)cc_full_sweep, 0, cc_full_sweep__doc__}, {"full_sweep", (PyCFunction)cc_full_sweep, 0,
"Perform a full sweep of the cache, looking for objects that can be removed"
},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
...@@ -151,8 +187,7 @@ static struct PyMethodDef cc_methods[] = { ...@@ -151,8 +187,7 @@ static struct PyMethodDef cc_methods[] = {
static ccobject * static ccobject *
newccobject(ARG(int,cache_size)) newccobject(int cache_size, int cache_age)
ARGDECL(int,cache_size)
{ {
ccobject *self; ccobject *self;
...@@ -161,6 +196,7 @@ newccobject(ARG(int,cache_size)) ...@@ -161,6 +196,7 @@ newccobject(ARG(int,cache_size))
{ {
self->position=0; self->position=0;
self->cache_size=cache_size < 1 ? 1 : cache_size; self->cache_size=cache_size < 1 ? 1 : cache_size;
self->cache_age=cache_size < 1 ? 1 : cache_age;
return self; return self;
} }
Py_DECREF(self); Py_DECREF(self);
...@@ -169,17 +205,14 @@ newccobject(ARG(int,cache_size)) ...@@ -169,17 +205,14 @@ newccobject(ARG(int,cache_size))
static void static void
cc_dealloc(ARG(ccobject *, self)) cc_dealloc(ccobject *self)
ARGDECL(ccobject *, self)
{ {
Py_XDECREF(self->data); Py_XDECREF(self->data);
PyMem_DEL(self); PyMem_DEL(self);
} }
static PyObject * static PyObject *
cc_getattr(ARG(ccobject *, self), ARG(char *, name)) cc_getattr(ccobject *self, char *name)
ARGDECL(ccobject *, self)
ARGDECL(char *, name)
{ {
PyObject *r; PyObject *r;
if(r=Py_FindMethod(cc_methods, (PyObject *)self, name)) if(r=Py_FindMethod(cc_methods, (PyObject *)self, name))
...@@ -189,11 +222,8 @@ cc_getattr(ARG(ccobject *, self), ARG(char *, name)) ...@@ -189,11 +222,8 @@ cc_getattr(ARG(ccobject *, self), ARG(char *, name))
} }
static PyObject * static PyObject *
cc_repr(ARG(ccobject *, self)) cc_repr(ccobject *self)
ARGDECL(ccobject *, self)
{ {
PyObject *s;
return PyObject_Repr(self->data); return PyObject_Repr(self->data);
} }
...@@ -208,16 +238,13 @@ cc_str(self) ...@@ -208,16 +238,13 @@ cc_str(self)
/* Code to access cCache objects as mappings */ /* Code to access cCache objects as mappings */
static int static int
cc_length(ARG(ccobject *, self)) cc_length(ccobject *self)
ARGDECL(ccobject *, self)
{ {
return PyObject_Length(self->data); return PyObject_Length(self->data);
} }
static PyObject * static PyObject *
cc_subscript(ARG(ccobject *, self), ARG(PyObject *, key)) cc_subscript(ccobject *self, PyObject *key)
ARGDECL(ccobject *, self)
ARGDECL(PyObject *, key)
{ {
PyObject *r; PyObject *r;
...@@ -231,19 +258,37 @@ cc_subscript(ARG(ccobject *, self), ARG(PyObject *, key)) ...@@ -231,19 +258,37 @@ cc_subscript(ARG(ccobject *, self), ARG(PyObject *, key))
Py_DECREF(r); Py_DECREF(r);
return NULL; return NULL;
} }
ASSIGN(r,PySequence_GetItem(r,0));
return r; return r;
} }
static int static int
cc_ass_sub(ARG(ccobject *, self), cc_ass_sub(ccobject *self, PyObject *key, PyObject *v)
ARG(PyObject *, key), ARG(PyObject *, v))
ARGDECL(ccobject *, self)
ARGDECL(PyObject *, key)
ARGDECL(PyObject *, v)
{ {
if(v) if(v)
{ {
UNLESS(-1 != PyDict_SetItem(self->data,key, v)) return -1; PyObject *t;
/* Create a tuple to hold object and object access time */
UNLESS(t=PyTuple_New(2)) return -1;
/* Save value as first item in tuple */
Py_INCREF(v);
PyTuple_SET_ITEM(t,0,v);
/* Now get and save the access time */
if(v=PyObject_GetAttr(v,py__p_atime))
{
if(v->ob_type == (PyTypeObject *)PATimeType)
PyTuple_SET_ITEM(t,1,v);
else
Py_DECREF(v);
}
else
PyErr_Clear();
UNLESS(-1 != PyDict_SetItem(self->data,key,t)) return -1;
Py_DECREF(t);
} }
else else
{ {
...@@ -265,7 +310,7 @@ static char Cctype__doc__[] = ...@@ -265,7 +310,7 @@ static char Cctype__doc__[] =
; ;
static PyTypeObject Cctype = { static PyTypeObject Cctype = {
PyObject_HEAD_INIT(&PyType_Type) PyObject_HEAD_INIT(NULL)
0, /*ob_size*/ 0, /*ob_size*/
"cPickleCache", /*tp_name*/ "cPickleCache", /*tp_name*/
sizeof(ccobject), /*tp_basicsize*/ sizeof(ccobject), /*tp_basicsize*/
...@@ -292,26 +337,26 @@ static PyTypeObject Cctype = { ...@@ -292,26 +337,26 @@ static PyTypeObject Cctype = {
/* End of code for cCache objects */ /* End of code for cCache objects */
/* -------------------------------------------------------- */ /* -------------------------------------------------------- */
static char cCM_new__doc__[] =
""
;
static PyObject * static PyObject *
cCM_new(ARG(PyObject *, self), ARG(PyObject *, args)) cCM_new(PyObject *self, PyObject *args)
ARGDECL(PyObject *, self) /* Not used */
ARGDECL(PyObject *, args)
{ {
int cache_size=100; int cache_size=100, cache_age=1000;
UNLESS(PyArg_ParseTuple(args, "|i", &cache_size)) return NULL; UNLESS(PyArg_ParseTuple(args, "|ii", &cache_size, &cache_age)) return NULL;
return (PyObject*)newccobject(cache_size); return (PyObject*)newccobject(cache_size,cache_age);
} }
/* List of methods defined in the module */ /* List of methods defined in the module */
static struct PyMethodDef cCM_methods[] = { static struct PyMethodDef cCM_methods[] = {
{"PickleCache",(PyCFunction)cCM_new, 1, cCM_new__doc__}, {"PickleCache",(PyCFunction)cCM_new, 1,
"PickleCache([size,age]) -- Create a pickle jar cache\n\n"
"The cache will attempt to garbage collect items when the cache size is\n"
"greater than the given size, which defaults to 100. Normally, objects\n"
"are garbage collected if their reference count is one, meaning that\n"
"they are only referenced by the cache. In some cases, objects that\n"
"have not been accessed in 'age' seconds may be partially garbage\n"
"collected, meaning that most of their state is freed.\n"
},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
...@@ -326,23 +371,37 @@ void ...@@ -326,23 +371,37 @@ void
initcPickleCache() initcPickleCache()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.1 $"; char *rev="$Revision: 1.2 $";
Cctype.ob_type=&PyType_Type;
if(PATimeType=PyImport_ImportModule("cPersistence"))
ASSIGN(PATimeType,PyObject_GetAttrString(PATimeType,"atimeType"));
UNLESS(PATimeType) PyErr_Clear();
/* Create the module and add the functions */
m = Py_InitModule4("cPickleCache", cCM_methods, m = Py_InitModule4("cPickleCache", cCM_methods,
cCache_module_documentation, cCache_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION); (PyObject*)NULL,PYTHON_API_VERSION);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
py_reload=PyString_FromString("reload");
py__p_jar=PyString_FromString("_p_jar");
py__p_atime=PyString_FromString("_p_atime");
PyDict_SetItemString(d,"__version__", PyDict_SetItemString(d,"__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2)); PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
if (PyErr_Occurred()) Py_FatalError("can't initialize module cCache"); if (PyErr_Occurred()) Py_FatalError("can't initialize module cCache");
} }
/****************************************************************************** /******************************************************************************
$Log: cPickleCache.c,v $ $Log: cPickleCache.c,v $
Revision 1.2 1997/03/11 20:48:38 jim
Added object-deactivation support. This only works with cPersistent
objects.
Revision 1.1 1997/02/17 18:39:02 jim Revision 1.1 1997/02/17 18:39:02 jim
*** empty log message *** *** empty log message ***
......
/* /*
$Id: cPickleCache.c,v 1.1 1997/02/17 18:39:02 jim Exp $ $Id: cPickleCache.c,v 1.2 1997/03/11 20:48:38 jim Exp $
C implementation of a pickle jar cache. C implementation of a pickle jar cache.
...@@ -56,23 +56,18 @@ ...@@ -56,23 +56,18 @@
(540) 371-6909 (540) 371-6909
***************************************************************************/ ***************************************************************************/
static char *what_string = "$Id: cPickleCache.c,v 1.1 1997/02/17 18:39:02 jim Exp $"; static char *what_string = "$Id: cPickleCache.c,v 1.2 1997/03/11 20:48:38 jim Exp $";
#define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;} #define ASSIGN(V,E) {PyObject *__e; __e=(E); Py_XDECREF(V); (V)=__e;}
#define UNLESS(E) if(!(E)) #define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V) #define UNLESS_ASSIGN(V,E) ASSIGN(V,E) UNLESS(V)
#define Py_ASSIGN(P,E) if(!PyObject_AssignExpression(&(P),(E))) return NULL #define Py_ASSIGN(P,E) if(!PyObject_AssignExpression(&(P),(E))) return NULL
#ifdef __cplusplus
#define ARG(T,N) T N
#define ARGDECL(T,N)
#else
#define ARG(T,N) N
#define ARGDECL(T,N) T N;
#endif
#include "Python.h" #include "Python.h"
static PyObject *py_reload, *py__p_jar, *py__p_atime;
/* Declarations for objects of type cCache */ /* Declarations for objects of type cCache */
typedef struct { typedef struct {
...@@ -80,50 +75,91 @@ typedef struct { ...@@ -80,50 +75,91 @@ typedef struct {
PyObject *data; PyObject *data;
int position; int position;
int cache_size; int cache_size;
int cache_age;
} ccobject; } ccobject;
staticforward PyTypeObject Cctype; staticforward PyTypeObject Cctype;
static PyObject *PATimeType=NULL;
typedef struct {
PyObject_HEAD
time_t value;
} PATimeobject;
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
static char cc_full_sweep__doc__[] =
"Perform a full sweep of the cache, looking for objects that can be removed" static int
; gc_item(ccobject *self, PyObject *key, PyObject *v, time_t now, time_t dt)
{
PyObject *atime;
if(v && key)
{
if(PyTuple_GET_ITEM(v,0)->ob_refcnt <= 1)
{
UNLESS(-1 != PyDict_DelItem(self->data, key)) return -1;
}
else if((atime=PyTuple_GET_ITEM(v,1)) &&
now-((PATimeobject*)atime)->value >dt)
{
/* We have a cPersistent object that hasn't been used in
a while. Reinitialize it, hopefully freeing it's state.
*/
v=PyTuple_GET_ITEM(v,0);
UNLESS(key=PyObject_GetAttr(v,py__p_jar)) return -1;
if(key!=Py_None)
{
UNLESS_ASSIGN(key,PyObject_GetAttr(key,py_reload)) return -1;
UNLESS_ASSIGN(key,PyObject_CallFunction(key,"(O)",v))
return -1;
}
Py_DECREF(key);
}
}
return 0;
}
static int static int
fullgc(ARG(ccobject *, self)) fullgc(ccobject *self)
ARGDECL(ccobject *, self)
{ {
PyObject *key, *v; PyObject *key, *v;
int i, l; int i;
time_t now, dt;
i=PyDict_Size(self->data)-3/self->cache_size;
if(i < 3) i=3;
dt=self->cache_age*3/i;
if(dt < 60) dt=60;
now=time(NULL);
for(i=0; PyDict_Next(self->data, &i, &key, &v); ) for(i=0; PyDict_Next(self->data, &i, &key, &v); )
{ if(gc_item(self,key,v,now,dt) < 0) return -1;
if(v->ob_refcnt <= 1)
UNLESS(-1 != PyDict_DelItem(self->data, key)) return -1;
}
self->position=0; self->position=0;
return 0; return 0;
} }
static int static int
maybegc(ARG(ccobject *, self)) maybegc(ccobject *self)
ARGDECL(ccobject *, self)
{ {
int n, s, p; int n, s;
int r; time_t now,dt;
PyObject *key=0, *v=0; PyObject *key=0, *v=0, *atime;
s=PyDict_Size(self->data)-3; s=PyDict_Size(self->data)-3;
if(s < self->cache_size) return 0; if(s < self->cache_size) return 0;
n=s/self->cache_size; n=s/self->cache_size;
if(n < 3) n=3; if(n < 3) n=3;
dt=3 * self->cache_age/n;
if(dt < 60) dt=60;
now=time(NULL);
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 && key && v->ob_refcnt <= 1) if(gc_item(self,key,v,now,dt) < 0) return -1;
UNLESS(-1 != PyDict_DelItem(self->data, key)) return -1;
} }
else else
self->position=0; self->position=0;
...@@ -132,9 +168,7 @@ maybegc(ARG(ccobject *, self)) ...@@ -132,9 +168,7 @@ maybegc(ARG(ccobject *, self))
} }
static PyObject * static PyObject *
cc_full_sweep(ARG(ccobject *, self), ARG(PyObject *, args)) cc_full_sweep(ccobject *self, PyObject *args)
ARGDECL(ccobject *, self)
ARGDECL(PyObject *, args)
{ {
UNLESS(PyArg_Parse(args, "")) return NULL; UNLESS(PyArg_Parse(args, "")) return NULL;
UNLESS(-1 != fullgc(self)) return NULL; UNLESS(-1 != fullgc(self)) return NULL;
...@@ -143,7 +177,9 @@ cc_full_sweep(ARG(ccobject *, self), ARG(PyObject *, args)) ...@@ -143,7 +177,9 @@ cc_full_sweep(ARG(ccobject *, self), ARG(PyObject *, args))
} }
static struct PyMethodDef cc_methods[] = { static struct PyMethodDef cc_methods[] = {
{"full_sweep", (PyCFunction)cc_full_sweep, 0, cc_full_sweep__doc__}, {"full_sweep", (PyCFunction)cc_full_sweep, 0,
"Perform a full sweep of the cache, looking for objects that can be removed"
},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
...@@ -151,8 +187,7 @@ static struct PyMethodDef cc_methods[] = { ...@@ -151,8 +187,7 @@ static struct PyMethodDef cc_methods[] = {
static ccobject * static ccobject *
newccobject(ARG(int,cache_size)) newccobject(int cache_size, int cache_age)
ARGDECL(int,cache_size)
{ {
ccobject *self; ccobject *self;
...@@ -161,6 +196,7 @@ newccobject(ARG(int,cache_size)) ...@@ -161,6 +196,7 @@ newccobject(ARG(int,cache_size))
{ {
self->position=0; self->position=0;
self->cache_size=cache_size < 1 ? 1 : cache_size; self->cache_size=cache_size < 1 ? 1 : cache_size;
self->cache_age=cache_size < 1 ? 1 : cache_age;
return self; return self;
} }
Py_DECREF(self); Py_DECREF(self);
...@@ -169,17 +205,14 @@ newccobject(ARG(int,cache_size)) ...@@ -169,17 +205,14 @@ newccobject(ARG(int,cache_size))
static void static void
cc_dealloc(ARG(ccobject *, self)) cc_dealloc(ccobject *self)
ARGDECL(ccobject *, self)
{ {
Py_XDECREF(self->data); Py_XDECREF(self->data);
PyMem_DEL(self); PyMem_DEL(self);
} }
static PyObject * static PyObject *
cc_getattr(ARG(ccobject *, self), ARG(char *, name)) cc_getattr(ccobject *self, char *name)
ARGDECL(ccobject *, self)
ARGDECL(char *, name)
{ {
PyObject *r; PyObject *r;
if(r=Py_FindMethod(cc_methods, (PyObject *)self, name)) if(r=Py_FindMethod(cc_methods, (PyObject *)self, name))
...@@ -189,11 +222,8 @@ cc_getattr(ARG(ccobject *, self), ARG(char *, name)) ...@@ -189,11 +222,8 @@ cc_getattr(ARG(ccobject *, self), ARG(char *, name))
} }
static PyObject * static PyObject *
cc_repr(ARG(ccobject *, self)) cc_repr(ccobject *self)
ARGDECL(ccobject *, self)
{ {
PyObject *s;
return PyObject_Repr(self->data); return PyObject_Repr(self->data);
} }
...@@ -208,16 +238,13 @@ cc_str(self) ...@@ -208,16 +238,13 @@ cc_str(self)
/* Code to access cCache objects as mappings */ /* Code to access cCache objects as mappings */
static int static int
cc_length(ARG(ccobject *, self)) cc_length(ccobject *self)
ARGDECL(ccobject *, self)
{ {
return PyObject_Length(self->data); return PyObject_Length(self->data);
} }
static PyObject * static PyObject *
cc_subscript(ARG(ccobject *, self), ARG(PyObject *, key)) cc_subscript(ccobject *self, PyObject *key)
ARGDECL(ccobject *, self)
ARGDECL(PyObject *, key)
{ {
PyObject *r; PyObject *r;
...@@ -231,19 +258,37 @@ cc_subscript(ARG(ccobject *, self), ARG(PyObject *, key)) ...@@ -231,19 +258,37 @@ cc_subscript(ARG(ccobject *, self), ARG(PyObject *, key))
Py_DECREF(r); Py_DECREF(r);
return NULL; return NULL;
} }
ASSIGN(r,PySequence_GetItem(r,0));
return r; return r;
} }
static int static int
cc_ass_sub(ARG(ccobject *, self), cc_ass_sub(ccobject *self, PyObject *key, PyObject *v)
ARG(PyObject *, key), ARG(PyObject *, v))
ARGDECL(ccobject *, self)
ARGDECL(PyObject *, key)
ARGDECL(PyObject *, v)
{ {
if(v) if(v)
{ {
UNLESS(-1 != PyDict_SetItem(self->data,key, v)) return -1; PyObject *t;
/* Create a tuple to hold object and object access time */
UNLESS(t=PyTuple_New(2)) return -1;
/* Save value as first item in tuple */
Py_INCREF(v);
PyTuple_SET_ITEM(t,0,v);
/* Now get and save the access time */
if(v=PyObject_GetAttr(v,py__p_atime))
{
if(v->ob_type == (PyTypeObject *)PATimeType)
PyTuple_SET_ITEM(t,1,v);
else
Py_DECREF(v);
}
else
PyErr_Clear();
UNLESS(-1 != PyDict_SetItem(self->data,key,t)) return -1;
Py_DECREF(t);
} }
else else
{ {
...@@ -265,7 +310,7 @@ static char Cctype__doc__[] = ...@@ -265,7 +310,7 @@ static char Cctype__doc__[] =
; ;
static PyTypeObject Cctype = { static PyTypeObject Cctype = {
PyObject_HEAD_INIT(&PyType_Type) PyObject_HEAD_INIT(NULL)
0, /*ob_size*/ 0, /*ob_size*/
"cPickleCache", /*tp_name*/ "cPickleCache", /*tp_name*/
sizeof(ccobject), /*tp_basicsize*/ sizeof(ccobject), /*tp_basicsize*/
...@@ -292,26 +337,26 @@ static PyTypeObject Cctype = { ...@@ -292,26 +337,26 @@ static PyTypeObject Cctype = {
/* End of code for cCache objects */ /* End of code for cCache objects */
/* -------------------------------------------------------- */ /* -------------------------------------------------------- */
static char cCM_new__doc__[] =
""
;
static PyObject * static PyObject *
cCM_new(ARG(PyObject *, self), ARG(PyObject *, args)) cCM_new(PyObject *self, PyObject *args)
ARGDECL(PyObject *, self) /* Not used */
ARGDECL(PyObject *, args)
{ {
int cache_size=100; int cache_size=100, cache_age=1000;
UNLESS(PyArg_ParseTuple(args, "|i", &cache_size)) return NULL; UNLESS(PyArg_ParseTuple(args, "|ii", &cache_size, &cache_age)) return NULL;
return (PyObject*)newccobject(cache_size); return (PyObject*)newccobject(cache_size,cache_age);
} }
/* List of methods defined in the module */ /* List of methods defined in the module */
static struct PyMethodDef cCM_methods[] = { static struct PyMethodDef cCM_methods[] = {
{"PickleCache",(PyCFunction)cCM_new, 1, cCM_new__doc__}, {"PickleCache",(PyCFunction)cCM_new, 1,
"PickleCache([size,age]) -- Create a pickle jar cache\n\n"
"The cache will attempt to garbage collect items when the cache size is\n"
"greater than the given size, which defaults to 100. Normally, objects\n"
"are garbage collected if their reference count is one, meaning that\n"
"they are only referenced by the cache. In some cases, objects that\n"
"have not been accessed in 'age' seconds may be partially garbage\n"
"collected, meaning that most of their state is freed.\n"
},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
...@@ -326,23 +371,37 @@ void ...@@ -326,23 +371,37 @@ void
initcPickleCache() initcPickleCache()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.1 $"; char *rev="$Revision: 1.2 $";
Cctype.ob_type=&PyType_Type;
if(PATimeType=PyImport_ImportModule("cPersistence"))
ASSIGN(PATimeType,PyObject_GetAttrString(PATimeType,"atimeType"));
UNLESS(PATimeType) PyErr_Clear();
/* Create the module and add the functions */
m = Py_InitModule4("cPickleCache", cCM_methods, m = Py_InitModule4("cPickleCache", cCM_methods,
cCache_module_documentation, cCache_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION); (PyObject*)NULL,PYTHON_API_VERSION);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
py_reload=PyString_FromString("reload");
py__p_jar=PyString_FromString("_p_jar");
py__p_atime=PyString_FromString("_p_atime");
PyDict_SetItemString(d,"__version__", PyDict_SetItemString(d,"__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2)); PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
if (PyErr_Occurred()) Py_FatalError("can't initialize module cCache"); if (PyErr_Occurred()) Py_FatalError("can't initialize module cCache");
} }
/****************************************************************************** /******************************************************************************
$Log: cPickleCache.c,v $ $Log: cPickleCache.c,v $
Revision 1.2 1997/03/11 20:48:38 jim
Added object-deactivation support. This only works with cPersistent
objects.
Revision 1.1 1997/02/17 18:39:02 jim Revision 1.1 1997/02/17 18:39:02 jim
*** empty log message *** *** empty log message ***
......
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