cPickleCache.c 15.4 KB
Newer Older
1
/*****************************************************************************
matt@zope.com's avatar
matt@zope.com committed
2 3

  Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
4
  
matt@zope.com's avatar
matt@zope.com committed
5 6 7 8 9 10
  This software is subject to the provisions of the Zope Public License,
  Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  FOR A PARTICULAR PURPOSE
11 12
  
 ****************************************************************************/
Jeremy Hylton's avatar
Jeremy Hylton committed
13 14 15
static char cPickleCache_doc_string[] = 
"Defines the PickleCache used by ZODB Connection objects.\n"
"\n"
16
"$Id: cPickleCache.c,v 1.38 2002/01/25 14:51:55 gvanrossum Exp $\n";
Jim Fulton's avatar
Jim Fulton committed
17 18 19 20

#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)
21
#define OBJECT(O) ((PyObject*)O)
Jim Fulton's avatar
Jim Fulton committed
22

23 24 25 26
/* Compute the current time in the units and range used for peristent
   objects. */
#define PER_TIME() ((long)(time(NULL) / 3)) % 65536

27
#define DONT_USE_CPERSISTENCECAPI
28
#include "cPersistence.h"
Jim Fulton's avatar
Jim Fulton committed
29
#include <time.h>
Jim Fulton's avatar
Jim Fulton committed
30

31 32
#undef Py_FindMethod

33
static PyObject *py_reload, *py__p_jar, *py__p_changed;
34

Jim Fulton's avatar
Jim Fulton committed
35 36 37
typedef struct {
  PyObject_HEAD
  PyObject *data;
Jim Fulton's avatar
Jim Fulton committed
38
  PyObject *jar;
39
  PyObject *setklassstate;
Jim Fulton's avatar
Jim Fulton committed
40 41
  int position;
  int cache_size;
42
  int cache_age;
43 44 45 46 47 48 49 50 51 52
  /* Cache statistics */
  int sum_deal;
  int sum_deac;
  double sum_age;
  int n, na;
  time_t last_check;		/* Time of last gc */
  double mean_age;
  double mean_deal;
  double mean_deac;
  double df, dfa;			/* Degees of freedom for above stats */
Jim Fulton's avatar
Jim Fulton committed
53 54
} ccobject;

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
#define WEIGHTING_PERIOD 600

/*
  How to compute weighted means?

  Assume we have two means, a current mean, M, and a mean as of some
  time d seconds in the past, Md.  The means have effective degrees
  of freedom, N, and Nd. Where Nd is adjusted by d is some fashion.
  The combined mean is (M*N+Md*Nd)/(N+Nd).  The degrees of freedom
  of the combined mean, Nc, is N+Nd.  Nd is computed by weighting
  an old degree of freedom with the weight: I/(I+d), where I is some
  suitably chosen constant, which we will call a "weighting period".
  
 */

Jim Fulton's avatar
Jim Fulton committed
70 71 72 73
staticforward PyTypeObject Cctype;

/* ---------------------------------------------------------------- */

74
static int 
Jim Fulton's avatar
Jim Fulton committed
75
gc_item(ccobject *self, PyObject *key, PyObject *v, long now, int dt)
76
{
Jim Fulton's avatar
Jim Fulton committed
77
  if (v && key)
78
    {
79
      self->n++;
Jim Fulton's avatar
Jim Fulton committed
80
      if(v->ob_refcnt <= 1)
81
	{
Jim Fulton's avatar
Jim Fulton committed
82
	  self->sum_deal++;
83 84 85
	  /* XXX The fact that this works will iterating over
	     self->data with PyDict_Next() is an accident of the
	     current Python dictionary implementation. */
Jim Fulton's avatar
Jim Fulton committed
86 87 88
	  return PyDict_DelItem(self->data, key);
	}

89
      if (dt >= 0 && 
Jim Fulton's avatar
Jim Fulton committed
90
	  (! PyExtensionClass_Check(v)) &&
91 92
	  ((cPersistentObject*)v)->jar == self->jar /* I'm paranoid */ &&
	  ((cPersistentObject*)v)->state == cPersistent_UPTODATE_STATE
Jim Fulton's avatar
Jim Fulton committed
93
	  )
Jim Fulton's avatar
Jim Fulton committed
94 95
	{
	  now -= ((cPersistentObject*)v)->atime;
96 97
	  if (now < 0) 
	      now += 65536;
Jim Fulton's avatar
Jim Fulton committed
98 99 100
	  self->na++;
	  self->sum_age += now;
	  if (now > dt)
101
	    {
Jim Fulton's avatar
Jim Fulton committed
102 103 104 105 106
	      /* We have a cPersistent object that hasn't been used in
		 a while.  Reinitialize it, hopefully freeing it's
		 state.
	      */
	      self->sum_deac++;
107
	      if (PyObject_SetAttr(v, py__p_changed, Py_None) < 0)
108
		PyErr_Clear();
109 110
	    }
	}
111 112 113
    }
  return 0;
}
Jim Fulton's avatar
Jim Fulton committed
114

115 116 117 118 119 120 121 122 123 124 125 126
static void
update_stats(ccobject *self, time_t now)
{
  double d, deal, deac;

  d=now-self->last_check;
  if(d < 1) return;

  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)/
Jim Fulton's avatar
Jim Fulton committed
127
		  (self->dfa+self->na))*3;
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
  self->sum_age=0;

  deac=self->sum_deac/d;
  self->sum_deac=0;
  self->mean_deac=((self->mean_deac*self->dfa+deac)/
		   (self->dfa+self->na));
  self->sum_deac=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;
}

Jim Fulton's avatar
Jim Fulton committed
151
static int
152
fullgc(ccobject *self, int dt)
Jim Fulton's avatar
Jim Fulton committed
153 154
{
  PyObject *key, *v;
155
  int i;
Jim Fulton's avatar
Jim Fulton committed
156 157
  long now;

158 159 160 161
  if (self->cache_size < 1) 
      return 0;
  if ((i=PyDict_Size(self->data)) < 1) 
      return 0;
Jim Fulton's avatar
Jim Fulton committed
162

163 164 165
  now = PER_TIME();
  if (dt > 0)
      dt /= 3; 
Jim Fulton's avatar
Jim Fulton committed
166 167

  for(i=0; PyDict_Next(self->data, &i, &key, &v); )
168 169
    if (gc_item(self, key, v, now, dt) < 0) 
	return -1;
Jim Fulton's avatar
Jim Fulton committed
170
  self->position=0;
171 172 173

  if(now-self->last_check > 1) update_stats(self, now);
  
Jim Fulton's avatar
Jim Fulton committed
174 175 176
  return 0;
}

Jim Fulton's avatar
Jim Fulton committed
177
static int
178
reallyfullgc(ccobject *self, int dt)
Jim Fulton's avatar
Jim Fulton committed
179 180
{
  PyObject *key, *v;
181
  int i, l, last;
182
  time_t now;
183

184 185 186 187 188
  if (self->cache_size < 1) 
      return 0;
  last = PyDict_Size(self->data);
  if (last < 0)
      return -1;
Jim Fulton's avatar
Jim Fulton committed
189

190 191 192
  now = PER_TIME();
  if (dt > 0)
      dt /= 3;
193

Jim Fulton's avatar
Jim Fulton committed
194 195
  /* First time through should get refcounts to 1 */
  for(i=0; PyDict_Next(self->data, &i, &key, &v); )
196 197 198 199
      if (gc_item(self, key, v, now, dt) < 0) 
	  return -1;

  l = PyDict_Size(self->data);
Jim Fulton's avatar
Jim Fulton committed
200

201 202 203 204
  if (l < 0)
      return -1;

  while (l < last)
205
    {
206 207 208 209 210 211 212
      for (i=0; PyDict_Next(self->data, &i, &key, &v); )
	  if (gc_item(self, key, v, now, dt) < 0) 
	      return -1;
      last = l;
      l = PyDict_Size(self->data);
      if (l < 0)
	  return -1;
213 214
    }

215 216
  if(now-self->last_check > 1) update_stats(self, now);

Jim Fulton's avatar
Jim Fulton committed
217 218 219 220
  self->position=0;
  return 0;
}

Jim Fulton's avatar
Jim Fulton committed
221
static int
222
maybegc(ccobject *self, PyObject *thisv)
Jim Fulton's avatar
Jim Fulton committed
223
{
Jim Fulton's avatar
Jim Fulton committed
224 225
  int n, s, size, dt;
  long now;
Jim Fulton's avatar
Jim Fulton committed
226
  PyObject *key=0, *v=0;
Jim Fulton's avatar
Jim Fulton committed
227

Jim Fulton's avatar
Jim Fulton committed
228 229 230 231
  if (self->cache_size < 1) return 0;
  s=PyDict_Size(self->data);
  if (s < 1) return s;

232
  now = PER_TIME();
233 234 235

  size=self->cache_size;
  self->cache_size=0;
236

237
  /* Decide how many objects to look at */
238
  n=(s-size)/10;
Jim Fulton's avatar
Jim Fulton committed
239
  if (n < 3) n=3;
240 241

  /* Decide how much time to give them before deactivating them */
Jim Fulton's avatar
Jim Fulton committed
242 243 244
  s=8*size/s;
  if (s > 100) s=100;
  dt=(long)(self->cache_age*(0.2+0.1*s));
245 246 247 248 249

  /* Units are 3 seconds */
  dt /= 3; 

  if (dt < 1) dt=1;
250
  
Jim Fulton's avatar
Jim Fulton committed
251
  while (--n >= 0)
Jim Fulton's avatar
Jim Fulton committed
252
    {
Jim Fulton's avatar
Jim Fulton committed
253
      if (PyDict_Next(self->data, &(self->position), &key, &v))
Jim Fulton's avatar
Jim Fulton committed
254
	{
Jim Fulton's avatar
Jim Fulton committed
255
	  if (v != thisv && gc_item(self,key,v,now,dt) < 0)
256 257 258 259
	    {
	      self->cache_size=size;
	      return -1;
	    }
Jim Fulton's avatar
Jim Fulton committed
260 261 262 263
	}
      else
	self->position=0;
    }
264
  self->cache_size=size;
265

Jim Fulton's avatar
Jim Fulton committed
266
  if (now-self->last_check > 1) update_stats(self, now);
267

Jim Fulton's avatar
Jim Fulton committed
268 269 270 271
  return 0;
}

static PyObject *
272
cc_full_sweep(ccobject *self, PyObject *args)
Jim Fulton's avatar
Jim Fulton committed
273
{
274 275 276 277 278 279 280 281 282
  int dt = self->cache_age;
  UNLESS(PyArg_ParseTuple(args, "|i:full_sweep", &dt)) return NULL;
  if (dt < -1) 
    {
      PyErr_SetString(PyExc_ValueError, "age must be >= -1");
      return NULL;
    }
  if (fullgc(self, dt) == -1)
      return NULL;
Jim Fulton's avatar
Jim Fulton committed
283 284 285 286
  Py_INCREF(Py_None);
  return Py_None;
}

Jim Fulton's avatar
Jim Fulton committed
287 288 289
static PyObject *
cc_reallyfull_sweep(ccobject *self, PyObject *args)
{
290 291 292 293 294 295 296 297 298
  int dt = self->cache_age;
  UNLESS(PyArg_ParseTuple(args, "|i:minimize", &dt)) return NULL;
  if (dt < -1) 
    {
      PyErr_SetString(PyExc_ValueError, "age must be >= -1");
      return NULL;
    }
  if (reallyfullgc(self, dt) == -1)
      return NULL;
Jim Fulton's avatar
Jim Fulton committed
299 300 301 302
  Py_INCREF(Py_None);
  return Py_None;
}

303 304 305
static PyObject *
cc_incrgc(ccobject *self, PyObject *args)
{
306 307
  int n=1;

308
  UNLESS (PyArg_ParseTuple(args, "|i:incrgr",&n)) return NULL;
309 310 311 312

  for (; --n >= 0;)
    if(maybegc(self,NULL) < 0) return NULL;

313 314 315 316
  Py_INCREF(Py_None);
  return Py_None;
}

317 318 319 320 321 322 323
static void 
_invalidate(ccobject *self, PyObject *key)
{
  PyObject *v;

  if ((v=PyDict_GetItem(self->data, key)))
    {
324 325 326 327 328 329 330 331 332
      if (PyExtensionClass_Check(v))
	if(v->ob_refcnt <= 1)
	  {
	    self->sum_deal++;
	    if (PyDict_DelItem(self->data, key) < 0) 
	      PyErr_Clear();
	  }
	else
	  {
333 334 335 336
	    PyObject *t = PyTuple_New(1);
	    if (t)
	      {
		PyTuple_SET_ITEM(t, 0, v);
337
		v = PyObject_CallObject(self->setklassstate, t);
338 339 340 341 342 343 344
		PyTuple_SET_ITEM(t, 0, NULL);
		Py_DECREF(t);
	      }
	    else 
	      {
		v = t;
	      }
345 346 347 348
	    if (v) Py_DECREF(v);
	    else PyErr_Clear();
	  }
      else if (PyObject_DelAttr(v,py__p_changed) < 0)
349 350
	PyErr_Clear();
    }
351 352 353 354 355
  else 
    {
      if (PyErr_Occurred())
	PyErr_Clear();
    }
356 357 358 359 360 361
}

static PyObject *
cc_invalidate(ccobject *self, PyObject *args)
{
  PyObject *inv, *key, *v;
362
  int i;
363
  
364
  if (PyArg_ParseTuple(args, "O!", &PyDict_Type, &inv)) {
365 366 367 368 369 370 371 372 373 374 375 376 377
    for (i=0; PyDict_Next(inv, &i, &key, &v); ) 
      if (key==Py_None)
	{ /* Eek some nitwit invalidated everything! */
	  for (i=0; PyDict_Next(self->data, &i, &key, &v); )
	    _invalidate(self, key);
	  break;
	}
      else
	_invalidate(self, key);
    PyDict_Clear(inv);
  }
  else {
    PyErr_Clear();
378
    UNLESS (PyArg_ParseTuple(args, "O:invalidate", &inv)) return NULL;
379
    if (PyString_Check(inv))
380
      _invalidate(self, inv);
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
    else if (inv==Py_None)	/* All */
      for (i=0; PyDict_Next(self->data, &i, &key, &v); )
	_invalidate(self, key);
    else {
      int l;

      PyErr_Clear();
      if ((l=PyObject_Length(inv)) < 0) return NULL;
      for(i=l; --i >= 0; )
	{
	  UNLESS (key=PySequence_GetItem(inv, i)) return NULL;
	  _invalidate(self, key);
	  Py_DECREF(key);
	}
      PySequence_DelSlice(inv, 0, l);
    }
  }

  Py_INCREF(Py_None);
  return Py_None;
}
  
Jim Fulton's avatar
Jim Fulton committed
403 404 405 406 407 408
  
static PyObject *
cc_get(ccobject *self, PyObject *args)
{
  PyObject *r, *key, *d=0;

409
  UNLESS (PyArg_ParseTuple(args, "O|O:get", &key, &d)) return NULL;
Jim Fulton's avatar
Jim Fulton committed
410

Jim Fulton's avatar
Jim Fulton committed
411 412 413 414
  UNLESS (r=PyDict_GetItem(self->data, key))
    {
      if (d) 
	{
415 416
	  if (PyErr_Occurred())
	    PyErr_Clear();
Jim Fulton's avatar
Jim Fulton committed
417 418 419 420 421 422 423 424 425
	  r=d;
	}
      else
	{
	  PyErr_SetObject(PyExc_KeyError, key);
	  return NULL;
	}
    }

Jim Fulton's avatar
Jim Fulton committed
426 427 428 429
  Py_INCREF(r);
  return r;
}

430

Jim Fulton's avatar
Jim Fulton committed
431
static struct PyMethodDef cc_methods[] = {
Jim Fulton's avatar
Jim Fulton committed
432
  {"full_sweep", (PyCFunction)cc_full_sweep, METH_VARARGS,
433 434 435 436 437
   "full_sweep([age]) -- Perform a full sweep of the cache\n\n"
   "Make a single pass through the cache, removing any objects that are no\n"
   "longer referenced, and deactivating objects that have not been\n"
   "accessed in the number of seconds given by 'age'.  "
   "'age defaults to the cache age.\n"
438
   },
Jim Fulton's avatar
Jim Fulton committed
439
  {"minimize",	(PyCFunction)cc_reallyfull_sweep, METH_VARARGS,
440 441 442 443 444
   "minimize([age]) -- Remove as many objects as possible\n\n"
   "Make multiple passes through the cache, removing any objects that are no\n"
   "longer referenced, and deactivating objects that have not been\n"
   "accessed in the number of seconds given by 'age'.  'age defaults to 0.\n"
   },
Jim Fulton's avatar
Jim Fulton committed
445
  {"incrgc", (PyCFunction)cc_incrgc, METH_VARARGS,
446
   "incrgc() -- Perform incremental garbage collection"},
447 448
  {"invalidate", (PyCFunction)cc_invalidate, METH_VARARGS,
   "invalidate(oids) -- invalidate one, many, or all ids"},
Jim Fulton's avatar
Jim Fulton committed
449 450
  {"get", (PyCFunction)cc_get, METH_VARARGS,
   "get(key [, default]) -- get an item, or a default"},
Jim Fulton's avatar
Jim Fulton committed
451 452 453 454
  {NULL,		NULL}		/* sentinel */
};

static ccobject *
Jim Fulton's avatar
Jim Fulton committed
455
newccobject(PyObject *jar, int cache_size, int cache_age)
Jim Fulton's avatar
Jim Fulton committed
456 457 458 459
{
  ccobject *self;
  
  UNLESS(self = PyObject_NEW(ccobject, &Cctype)) return NULL;
460
  self->setklassstate=self->jar=NULL;
Jeremy Hylton's avatar
Jeremy Hylton committed
461
  if((self->data=PyDict_New()))
Jim Fulton's avatar
Jim Fulton committed
462
    {
Jim Fulton's avatar
Jim Fulton committed
463 464
      self->jar=jar; 
      Py_INCREF(jar);
465 466
      UNLESS (self->setklassstate=PyObject_GetAttrString(jar, "setklassstate"))
	return NULL;
Jim Fulton's avatar
Jim Fulton committed
467
      self->position=0;
468 469
      self->cache_size=cache_size;
      self->cache_age=cache_age < 1 ? 1 : cache_age;
470 471 472 473 474 475 476 477 478 479 480
      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);
Jim Fulton's avatar
Jim Fulton committed
481 482 483 484 485 486 487
      return self;
    }
  Py_DECREF(self);
  return NULL;
}

static void
488
cc_dealloc(ccobject *self)
Jim Fulton's avatar
Jim Fulton committed
489 490
{
  Py_XDECREF(self->data);
Jim Fulton's avatar
Jim Fulton committed
491
  Py_XDECREF(self->jar);
492
  Py_XDECREF(self->setklassstate);
Jim Fulton's avatar
Jim Fulton committed
493 494 495 496
  PyMem_DEL(self);
}

static PyObject *
497
cc_getattr(ccobject *self, char *name)
Jim Fulton's avatar
Jim Fulton committed
498 499
{
  PyObject *r;
500 501 502 503 504 505 506

  if(*name=='c')
    {
      if(strcmp(name,"cache_age")==0)
	return PyInt_FromLong(self->cache_age);
      if(strcmp(name,"cache_size")==0)
	return PyInt_FromLong(self->cache_size);
507 508 509 510 511 512 513 514 515 516 517 518
      if(strcmp(name,"cache_mean_age")==0)
	return PyFloat_FromDouble(self->mean_age);
      if(strcmp(name,"cache_mean_deal")==0)
	return PyFloat_FromDouble(self->mean_deal);
      if(strcmp(name,"cache_mean_deac")==0)
	return PyFloat_FromDouble(self->mean_deac);
      if(strcmp(name,"cache_df")==0)
	return PyFloat_FromDouble(self->df);
      if(strcmp(name,"cache_dfa")==0)
	return PyFloat_FromDouble(self->dfa);
      if(strcmp(name,"cache_last_gc_time")==0)
	return PyFloat_FromDouble(self->last_check);
519 520 521 522 523
      if(strcmp(name,"cache_data")==0)
	{
	  Py_INCREF(self->data);
	  return self->data;
	}
524
    }
Jeremy Hylton's avatar
Jeremy Hylton committed
525 526 527
  if((*name=='h' && strcmp(name, "has_key")==0) ||
     (*name=='i' && strcmp(name, "items")==0) ||
     (*name=='k' && strcmp(name, "keys")==0)
Jim Fulton's avatar
Jim Fulton committed
528
     )
Jim Fulton's avatar
Jim Fulton committed
529
    return PyObject_GetAttrString(self->data, name);
530

Jeremy Hylton's avatar
Jeremy Hylton committed
531
  if((r=Py_FindMethod(cc_methods, (PyObject *)self, name)))
Jim Fulton's avatar
Jim Fulton committed
532 533 534 535 536
    return r;
  PyErr_Clear();
  return PyObject_GetAttrString(self->data, name);
}

Jim Fulton's avatar
Jim Fulton committed
537 538 539 540 541 542 543 544 545
static int
cc_setattr(ccobject *self, char *name, PyObject *value)
{
  if(value)
    {
      int v;

      if(strcmp(name,"cache_age")==0)
	{
546
	  UNLESS(PyArg_Parse(value,"i",&v)) return -1;
Jim Fulton's avatar
Jim Fulton committed
547
	  if(v > 0)self->cache_age=v;
548
	  return 0;
Jim Fulton's avatar
Jim Fulton committed
549 550 551 552
	}

      if(strcmp(name,"cache_size")==0)
	{
553
	  UNLESS(PyArg_Parse(value,"i",&v)) return -1;
554
	  self->cache_size=v;
555
	  return 0;
Jim Fulton's avatar
Jim Fulton committed
556 557 558 559 560 561
	}
    }
  PyErr_SetString(PyExc_AttributeError, name);
  return -1;
}

Jim Fulton's avatar
Jim Fulton committed
562
static int
563
cc_length(ccobject *self)
Jim Fulton's avatar
Jim Fulton committed
564 565 566 567 568
{
  return PyObject_Length(self->data);
}
  
static PyObject *
569
cc_subscript(ccobject *self, PyObject *key)
Jim Fulton's avatar
Jim Fulton committed
570 571 572
{
  PyObject *r;

Jim Fulton's avatar
Jim Fulton committed
573
  UNLESS (r=PyDict_GetItem(self->data, key))
Jim Fulton's avatar
Jim Fulton committed
574 575 576 577
  {
    PyErr_SetObject(PyExc_KeyError, key);
    return NULL;
  }
Jim Fulton's avatar
Jim Fulton committed
578 579

  Py_INCREF(r);
Jim Fulton's avatar
Jim Fulton committed
580 581 582 583
  return r;
}

static int
584
cc_ass_sub(ccobject *self, PyObject *key, PyObject *v)
Jim Fulton's avatar
Jim Fulton committed
585
{
Jim Fulton's avatar
Jim Fulton committed
586 587
  if(v) 
    {
588 589 590 591 592 593 594 595
      if (PyExtensionClass_Check(v) 
	  ||
	  (PyExtensionInstance_Check(v) 
	   &&
	   (((PyExtensionClass*)(v->ob_type))->class_flags 
	    & PERSISTENT_TYPE_FLAG)
	   &&
	   (v->ob_type->tp_basicsize >= sizeof(cPersistentObject))
Jim Fulton's avatar
Jim Fulton committed
596 597 598 599 600 601 602 603
	   )
	  )	  
	return PyDict_SetItem(self->data, key, v);

      PyErr_SetString(PyExc_ValueError,
		      "Cache values must be persistent objects or classes.");
      return -1;
    }
Jim Fulton's avatar
Jim Fulton committed
604
  return PyDict_DelItem(self->data, key);
Jim Fulton's avatar
Jim Fulton committed
605 606 607 608 609 610 611 612 613
}

static PyMappingMethods cc_as_mapping = {
  (inquiry)cc_length,		/*mp_length*/
  (binaryfunc)cc_subscript,	/*mp_subscript*/
  (objobjargproc)cc_ass_sub,	/*mp_ass_subscript*/
};

static PyTypeObject Cctype = {
614
  PyObject_HEAD_INIT(NULL)
Jim Fulton's avatar
Jim Fulton committed
615 616 617 618 619 620 621 622
  0,				/*ob_size*/
  "cPickleCache",		/*tp_name*/
  sizeof(ccobject),		/*tp_basicsize*/
  0,				/*tp_itemsize*/
  /* methods */
  (destructor)cc_dealloc,	/*tp_dealloc*/
  (printfunc)0,			/*tp_print*/
  (getattrfunc)cc_getattr,	/*tp_getattr*/
Jim Fulton's avatar
Jim Fulton committed
623
  (setattrfunc)cc_setattr,	/*tp_setattr*/
Jim Fulton's avatar
Jim Fulton committed
624
  (cmpfunc)0,			/*tp_compare*/
Jim Fulton's avatar
Jim Fulton committed
625
  (reprfunc)0,   		/*tp_repr*/
Jim Fulton's avatar
Jim Fulton committed
626 627 628 629 630
  0,				/*tp_as_number*/
  0,				/*tp_as_sequence*/
  &cc_as_mapping,		/*tp_as_mapping*/
  (hashfunc)0,			/*tp_hash*/
  (ternaryfunc)0,		/*tp_call*/
Jim Fulton's avatar
Jim Fulton committed
631
  (reprfunc)0,  		/*tp_str*/
Jim Fulton's avatar
Jim Fulton committed
632 633 634

  /* Space for future expansion */
  0L,0L,0L,0L,
Jim Fulton's avatar
Jim Fulton committed
635
  ""
Jim Fulton's avatar
Jim Fulton committed
636 637 638
};

static PyObject *
639
cCM_new(PyObject *self, PyObject *args)
Jim Fulton's avatar
Jim Fulton committed
640
{
641
  int cache_size=100, cache_age=1000;
Jim Fulton's avatar
Jim Fulton committed
642 643
  PyObject *jar;

Jeremy Hylton's avatar
Jeremy Hylton committed
644 645
  UNLESS(PyArg_ParseTuple(args, "O|ii", &jar, &cache_size, &cache_age))
      return NULL;
Jim Fulton's avatar
Jim Fulton committed
646
  return (PyObject*)newccobject(jar, cache_size,cache_age);
Jim Fulton's avatar
Jim Fulton committed
647 648 649
}

static struct PyMethodDef cCM_methods[] = {
Jim Fulton's avatar
Jim Fulton committed
650
  {"PickleCache",(PyCFunction)cCM_new,	METH_VARARGS, ""},
Jim Fulton's avatar
Jim Fulton committed
651 652 653 654
  {NULL,		NULL}		/* sentinel */
};

void
Jeremy Hylton's avatar
Jeremy Hylton committed
655
initcPickleCache(void)
Jim Fulton's avatar
Jim Fulton committed
656
{
657
  PyObject *m, *d;
658 659 660

  Cctype.ob_type=&PyType_Type;

Jim Fulton's avatar
Jim Fulton committed
661 662
  UNLESS(ExtensionClassImported) return;

Jeremy Hylton's avatar
Jeremy Hylton committed
663 664
  m = Py_InitModule4("cPickleCache", cCM_methods, cPickleCache_doc_string,
		     (PyObject*)NULL, PYTHON_API_VERSION);
Jim Fulton's avatar
Jim Fulton committed
665 666

  d = PyModule_GetDict(m);
667 668 669

  py_reload=PyString_FromString("reload");
  py__p_jar=PyString_FromString("_p_jar");
670
  py__p_changed=PyString_FromString("_p_changed");
671

672 673 674
  /* Check for errors */
  if (PyErr_Occurred())
    Py_FatalError("can't initialize module cPickleCache");
Jim Fulton's avatar
Jim Fulton committed
675
}