Commit 724c428b authored by Jim Fulton's avatar Jim Fulton

many changes resulting from debugging

parent 97005d8e
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
attributions are listed in the accompanying credits file. attributions are listed in the accompanying credits file.
****************************************************************************/ ****************************************************************************/
static char *what_string = "$Id: cPersistence.c,v 1.27 1999/05/10 23:15:56 jim Exp $"; static char *what_string = "$Id: cPersistence.c,v 1.28 1999/05/12 15:55:44 jim Exp $";
#include <string.h> #include <string.h>
#include "cPersistence.h" #include "cPersistence.h"
...@@ -484,6 +484,8 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name, ...@@ -484,6 +484,8 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
case 's': case 's':
if(strcmp(n,"erial")==0) if(strcmp(n,"erial")==0)
return PyString_FromStringAndSize(self->serial, 8); return PyString_FromStringAndSize(self->serial, 8);
if(strcmp(n,"elf")==0)
return orNothing(OBJECT(self));
break; break;
case 'm': case 'm':
if(strcmp(n,"time")==0) if(strcmp(n,"time")==0)
...@@ -581,6 +583,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -581,6 +583,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
if (! v || v==Py_None) if (! v || v==Py_None)
{ {
if (Per__p_deactivate(self, NULL)) Py_DECREF(Py_None); if (Per__p_deactivate(self, NULL)) Py_DECREF(Py_None);
self->state=cPersistent_GHOST_STATE;
return 0; return 0;
} }
if (PyObject_IsTrue(v)) return changed(self); if (PyObject_IsTrue(v)) return changed(self);
...@@ -635,7 +638,7 @@ static PyExtensionClass Pertype = { ...@@ -635,7 +638,7 @@ static PyExtensionClass Pertype = {
/* Space for future expansion */ /* Space for future expansion */
0L,0L,"", 0L,0L,"",
METHOD_CHAIN(Per_methods), METHOD_CHAIN(Per_methods),
EXTENSIONCLASS_BASICNEW_FLAG, EXTENSIONCLASS_BASICNEW_FLAG | PERSISTENT_TYPE_FLAG,
}; };
/* End of code for Persistent objects */ /* End of code for Persistent objects */
...@@ -687,7 +690,7 @@ void ...@@ -687,7 +690,7 @@ void
initcPersistence() initcPersistence()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.27 $"; char *rev="$Revision: 1.28 $";
TimeStamp=PyString_FromString("TimeStamp"); TimeStamp=PyString_FromString("TimeStamp");
if (! TimeStamp) return; if (! TimeStamp) return;
......
...@@ -123,6 +123,8 @@ static cPersistenceCAPIstruct *cPersistenceCAPI; ...@@ -123,6 +123,8 @@ static cPersistenceCAPIstruct *cPersistenceCAPI;
#define cPersistanceModuleName "cPersistence" #define cPersistanceModuleName "cPersistence"
#define PERSISTENT_TYPE_FLAG EXTENSIONCLASS_USER_FLAG8
#define PER_USE_OR_RETURN(O,R) { \ #define PER_USE_OR_RETURN(O,R) { \
if ((O)->state==cPersistent_GHOST_STATE && \ if ((O)->state==cPersistent_GHOST_STATE && \
cPersistenceCAPI->setstate((PyObject*)(O)) < 0) \ cPersistenceCAPI->setstate((PyObject*)(O)) < 0) \
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
attributions are listed in the accompanying credits file. attributions are listed in the accompanying credits file.
****************************************************************************/ ****************************************************************************/
static char *what_string = "$Id: cPickleCache.c,v 1.18 1999/05/10 23:15:57 jim Exp $"; static char *what_string = "$Id: cPickleCache.c,v 1.19 1999/05/12 15:55:44 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))
...@@ -492,16 +492,19 @@ cc_subscript(ccobject *self, PyObject *key) ...@@ -492,16 +492,19 @@ cc_subscript(ccobject *self, PyObject *key)
return r; return r;
} }
static PyExtensionClass *Persistent=0;
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) && ||
ExtensionClassSubclassInstance_Check(v, Persistent) (PyExtensionInstance_Check(v)
&&
(((PyExtensionClass*)(v->ob_type))->class_flags
& PERSISTENT_TYPE_FLAG)
&&
(v->ob_type->tp_basicsize >= sizeof(cPersistentObject))
) )
) )
return PyDict_SetItem(self->data, key, v); return PyDict_SetItem(self->data, key, v);
...@@ -563,20 +566,12 @@ void ...@@ -563,20 +566,12 @@ void
initcPickleCache() initcPickleCache()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.18 $"; char *rev="$Revision: 1.19 $";
Cctype.ob_type=&PyType_Type; Cctype.ob_type=&PyType_Type;
UNLESS(ExtensionClassImported) return; UNLESS(ExtensionClassImported) return;
/* Get the Persistent base class */
UNLESS(m=PyString_FromString(cPersistanceModuleName)) return;
ASSIGN(m, PyImport_Import(m));
UNLESS(m) return;
ASSIGN(m, PyObject_GetAttrString(m, "Persistent"));
UNLESS(m) return;
Persistent=(PyExtensionClass *)m;
m = Py_InitModule4("cPickleCache", cCM_methods, "", m = Py_InitModule4("cPickleCache", cCM_methods, "",
(PyObject*)NULL,PYTHON_API_VERSION); (PyObject*)NULL,PYTHON_API_VERSION);
......
...@@ -84,14 +84,17 @@ ...@@ -84,14 +84,17 @@
############################################################################## ##############################################################################
"""Database connection support """Database connection support
$Id: Connection.py,v 1.4 1999/05/10 23:15:55 jim Exp $""" $Id: Connection.py,v 1.5 1999/05/12 15:55:43 jim Exp $"""
__version__='$Revision: 1.4 $'[11:-2] __version__='$Revision: 1.5 $'[11:-2]
from cPickleCache import PickleCache from cPickleCache import PickleCache
from bpthread import allocate_lock from bpthread import allocate_lock
from POSException import ConflictError from POSException import ConflictError
from cStringIO import StringIO from cStringIO import StringIO
from cPickle import Unpickler, Pickler from cPickle import Unpickler, Pickler
from ExtensionClass import Base
ExtensionKlass=Base.__class__
class HelperClass: pass class HelperClass: pass
ClassType=type(HelperClass) ClassType=type(HelperClass)
...@@ -139,12 +142,18 @@ class Connection: ...@@ -139,12 +142,18 @@ class Connection:
object = unpickler.load() object = unpickler.load()
klass, args = object klass, args = object
if type(klass) is tt:
module, name = klass
klass=self._db._classFactory(self, module, name)
if (args is None or if (args is None or
not args and not hasattr(klass,'__getinitargs__')): not args and not hasattr(klass,'__getinitargs__')):
object=klass.__basicnew__() object=klass.__basicnew__()
else: else:
object=apply(klass,args) object=apply(klass,args)
object.__dict__.clear() if klass is not ExtensionKlass:
object.__dict__.clear()
object._p_oid=oid object._p_oid=oid
object._p_jar=self object._p_jar=self
...@@ -167,19 +176,27 @@ class Connection: ...@@ -167,19 +176,27 @@ class Connection:
# to create the instance wo hitting the db, so go for it! # to create the instance wo hitting the db, so go for it!
oid, klass = oid oid, klass = oid
if cache.has_key(oid): return cache[oid] if cache.has_key(oid): return cache[oid]
if type(klass) is tt:
module, name = klass
try: klass=self._db._classFactory(self, module, name)
except:
# Eek, we couldn't get the class. Hm.
# Maybe their's more current data in the
# object's actual record!
return self[oid]
object=klass.__basicnew__() object=klass.__basicnew__()
object._p_oid=oid object._p_oid=oid
object._p_jar=self object._p_jar=self
object._p_changed=None object._p_changed=None
cache[oid]=object cache[oid]=object
return object return object
if type(oid) is st: oid=atoi(oid)
if cache.has_key(oid): return cache[oid] if cache.has_key(oid): return cache[oid]
object=cache[oid]=self[oid] return self[oid]
return object
def _planToStore(self,object,stackp): def _planToStore(self,object,stackp):
oid=object._p_oid oid=object._p_oid
...@@ -188,8 +205,10 @@ class Connection: ...@@ -188,8 +205,10 @@ class Connection:
object._p_jar=self object._p_jar=self
object._p_oid=oid object._p_oid=oid
stackp(object) stackp(object)
elif object._p_changed: elif object._p_changed:
stackp(object) stackp(object)
return oid return oid
def _setDB(self, odb=None): def _setDB(self, odb=None):
...@@ -220,6 +239,7 @@ class Connection: ...@@ -220,6 +239,7 @@ class Connection:
stackup=stack.append stackup=stack.append
topoid=plan(object,stackup) topoid=plan(object,stackup)
version=self._version version=self._version
if stack: if stack:
# Create a special persistent_id that passes T and the subobject # Create a special persistent_id that passes T and the subobject
# stack along: # stack along:
...@@ -235,8 +255,17 @@ class Connection: ...@@ -235,8 +255,17 @@ class Connection:
object._p_oid=oid object._p_oid=oid
stackup(object) stackup(object)
if hasattr(object.__class__, '__getinitargs__'): return oid klass=object.__class__
return oid, object.__class__
if klass is ExtensionKlass: return oid
if hasattr(klass, '__getinitargs__'): return oid
try: module=klass.__module__
except: module=''
if module: klass=module, klass.__name__
return oid, klass
file=StringIO() file=StringIO()
seek=file.seek seek=file.seek
...@@ -252,23 +281,42 @@ class Connection: ...@@ -252,23 +281,42 @@ class Connection:
object=stack[-1] object=stack[-1]
del stack[-1] del stack[-1]
oid=object._p_oid oid=object._p_oid
serial=object._p_serial try: serial=object._p_serial
except: serial='\0'*8
if self._invalidated.has_key(oid): raise ConflictError, oid if self._invalidated.has_key(oid): raise ConflictError, oid
cls = object.__class__ klass = object.__class__
if hasattr(cls, '__getinitargs__'):
args = object.__getinitargs__() if klass is ExtensionKlass:
len(args) # XXX Assert it's a sequence # Ye Ha!
dict={}
dict.update(object.__dict__)
del dict['_p_jar']
args=object.__name__, object.__bases__, dict
state=None
else: else:
args = None # New no-constructor protocol! if hasattr(klass, '__getinitargs__'):
args = object.__getinitargs__()
len(args) # XXX Assert it's a sequence
else:
args = None # New no-constructor protocol!
try: module=klass.__module__
except: module=''
if module: klass=module, klass.__name__
state=object.__getstate__()
seek(0) seek(0)
clear_memo() clear_memo()
dump((cls,args)) dump((klass,args))
state=object.__getstate__()
dump(state) dump(state)
p=file() p=file()
object._p_serial=dbstore(oid,serial,p,version,transaction) object._p_serial=dbstore(oid,serial,p,version,transaction)
object._p_changed=0 object._p_changed=0
cache[oid]=object try: cache[oid]=object
except:
# Dang, I bet its wrapped:
if hasattr(object, 'aq_base'):
cache[oid]=object.aq_base
return topoid return topoid
......
...@@ -84,8 +84,8 @@ ...@@ -84,8 +84,8 @@
############################################################################## ##############################################################################
"""Database objects """Database objects
$Id: DB.py,v 1.4 1999/05/10 23:15:55 jim Exp $""" $Id: DB.py,v 1.5 1999/05/12 15:55:43 jim Exp $"""
__version__='$Revision: 1.4 $'[11:-2] __version__='$Revision: 1.5 $'[11:-2]
import cPickle, cStringIO, sys import cPickle, cStringIO, sys
from Connection import Connection from Connection import Connection
...@@ -148,7 +148,8 @@ class DB: ...@@ -148,7 +148,8 @@ class DB:
# Pass through methods: # Pass through methods:
for m in ('history', 'modifiedInVersion', for m in ('history', 'modifiedInVersion',
'supportsUndo', 'supportsVersions', 'supportsUndo', 'supportsVersions',
'undo', 'undoLog', 'versionEmpty'): 'undo', 'undoLog',
'versionEmpty', 'versions'):
setattr(self, m, getattr(storage, m)) setattr(self, m, getattr(storage, m))
...@@ -163,6 +164,11 @@ class DB: ...@@ -163,6 +164,11 @@ class DB:
if m[1]: m=m[0]/m[1] if m[1]: m=m[0]/m[1]
else: m=None else: m=None
return m return m
def _classFactory(self, connection, location, name,
_silly=('__doc__',), _globals={}):
return getattr(__import__(location, _globals, _globals, _silly),
name)
def _closeConnection(self, connection): def _closeConnection(self, connection):
"""Return a connection to the pool""" """Return a connection to the pool"""
...@@ -269,11 +275,22 @@ class DB: ...@@ -269,11 +275,22 @@ class DB:
def exportFile(self, oid, file=None): def exportFile(self, oid, file=None):
raise 'Not yet implemented' raise 'Not yet implemented'
def getCacheDeactivateAfter(self): return self._cache_deactivate_after
def getCacheSize(self): return self._cache_size
def getName(self): return self._storage.getName() def getName(self): return self._storage.getName()
def getPoolSize(self): return self._pool_size
def getSize(self): return self._storage.getSize() def getSize(self): return self._storage.getSize()
def getVersionCacheDeactivateAfter(self):
return self._version_cache_deactivate_after
def getVersionCacheSize(self): return self._version_cache_size
def getVersionPoolSize(self): return self._version_pool_size
def importFile(self, file): def importFile(self, file):
raise 'Not yet implemented' raise 'Not yet implemented'
...@@ -369,7 +386,7 @@ class DB: ...@@ -369,7 +386,7 @@ class DB:
if not pool: if not pool:
c=None c=None
if version: if version:
if self._version_pool_size < len(allocated) or force: if self._version_pool_size > len(allocated) or force:
c=Connection( c=Connection(
storage=self._storage, storage=self._storage,
version=version, version=version,
...@@ -417,19 +434,15 @@ class DB: ...@@ -417,19 +434,15 @@ class DB:
def setCacheDeactivateAfter(self, v): self._cache_deactivate_after=v def setCacheDeactivateAfter(self, v): self._cache_deactivate_after=v
def setCacheSize(self, v): self._cache_size=v def setCacheSize(self, v): self._cache_size=v
def setClassFactory(self, factory):
self._classFactory=factory
def setPoolSize(self, v): self._pool_size=v def setPoolSize(self, v): self._pool_size=v
def setVersionCacheDeactivateAfter(self, v): def setVersionCacheDeactivateAfter(self, v):
self._version_cache_deactivate_after=v self._version_cache_deactivate_after=v
def setVersionCacheSize(self, v): self._version_cache_size=v def setVersionCacheSize(self, v): self._version_cache_size=v
def setVersionPoolSize(self, v): self._version_pool_size=v def setVersionPoolSize(self, v): self._version_pool_size=v
def getCacheDeactivateAfter(self): return self._cache_deactivate_after
def getCacheSize(self): return self._cache_size
def getPoolSize(self): return self._pool_size
def getVersionCacheDeactivateAfter(self):
return self._version_cache_deactivate_after
def getVersionCacheSize(self): return self._version_cache_size
def getVersionPoolSize(self): return self._version_pool_size
def cacheStatistics(self): return () # :( def cacheStatistics(self): return () # :(
......
...@@ -151,7 +151,7 @@ Also, the object ids time stamps are big-endian, so comparisons ...@@ -151,7 +151,7 @@ Also, the object ids time stamps are big-endian, so comparisons
are meaningful. are meaningful.
""" """
__version__='$Revision: 1.4 $'[11:-2] __version__='$Revision: 1.5 $'[11:-2]
import struct, time, os, bpthread import struct, time, os, bpthread
now=time.time now=time.time
...@@ -159,6 +159,7 @@ from struct import pack, unpack ...@@ -159,6 +159,7 @@ from struct import pack, unpack
from cPickle import dumps from cPickle import dumps
import POSException import POSException
from TimeStamp import TimeStamp from TimeStamp import TimeStamp
from lock_file import lock_file
t32 = 1L << 32 t32 = 1L << 32
...@@ -199,7 +200,7 @@ def error(log, message, *data): ...@@ -199,7 +200,7 @@ def error(log, message, *data):
def panic(log, message, *data): def panic(log, message, *data):
message=message%data message=message%data
log("%s ERROR: %s\n" % (packed_version, message)) log("%s ERROR: %s\n" % (packed_version, message))
raise CorruptedTransactionRecordError, message raise CorruptedTransactionError, message
class FileStorageError: pass class FileStorageError: pass
...@@ -238,11 +239,12 @@ class FileStorage: ...@@ -238,11 +239,12 @@ class FileStorage:
self.__name__=file_name self.__name__=file_name
self._tfile=open(file_name+'.tmp','w+b') self._tfile=open(file_name+'.tmp','w+b')
index, vindex, tindex = self._newIndexes() index, vindex, tindex, tvindex = self._newIndexes()
self._index=index self._index=index
self._vindex=vindex self._vindex=vindex
self._tindex=tindex self._tindex=tindex
self._tvindex=tvindex
self._indexpos=index.get self._indexpos=index.get
self._vindexpos=vindex.get self._vindexpos=vindex.get
self._tappend=tindex.append self._tappend=tindex.append
...@@ -268,6 +270,7 @@ class FileStorage: ...@@ -268,6 +270,7 @@ class FileStorage:
if os.path.exists(file_name): if os.path.exists(file_name):
file=open(file_name, read_only and 'rb' or 'r+b') file=open(file_name, read_only and 'rb' or 'r+b')
if not read_only: lock_file(file)
else: else:
if read_only: if read_only:
raise ValueError, "can\'t create a read-only file" raise ValueError, "can\'t create a read-only file"
...@@ -286,7 +289,7 @@ class FileStorage: ...@@ -286,7 +289,7 @@ class FileStorage:
def __len__(self): return len(self._index) def __len__(self): return len(self._index)
def _newIndexes(self): return {}, {}, [] def _newIndexes(self): return {}, {}, [], {}
def abortVersion(self, version, transaction): def abortVersion(self, version, transaction):
if transaction is not self._transaction: if transaction is not self._transaction:
...@@ -395,12 +398,12 @@ class FileStorage: ...@@ -395,12 +398,12 @@ class FileStorage:
(read(8) # skip past version link (read(8) # skip past version link
and version != read(vlen)) and version != read(vlen))
): ):
return _loadBack(file, oid, u64(pnv)) return _loadBack(file, oid, pnv)
# If we get here, then either this was not a version record, # If we get here, then either this was not a version record,
# or we've already read past the version data! # or we've already read past the version data!
if plen != z64: return read(u64(plen)), serial if plen != z64: return read(u64(plen)), serial
return _loadBack(file, oid, u64(pnv)) return _loadBack(file, oid, pnv)
finally: self._r() finally: self._r()
def modifiedInVersion(self, oid): def modifiedInVersion(self, oid):
...@@ -408,13 +411,14 @@ class FileStorage: ...@@ -408,13 +411,14 @@ class FileStorage:
try: try:
pos=self._index[oid] pos=self._index[oid]
file=self._file file=self._file
file.seek(pos) seek=file.seek
seek(pos)
doid,serial,prev,tloc,vlen = unpack(">8s8s8s8sH", file.read(34)) doid,serial,prev,tloc,vlen = unpack(">8s8s8s8sH", file.read(34))
if doid != oid: if doid != oid:
raise CorruptedDataError, h raise CorruptedDataError, h
if vlen: if vlen:
seek(16,1) seek(24,1) # skip plen, pnv, and pv
return read(vlen) return file.read(vlen)
return '' return ''
finally: self._r() finally: self._r()
...@@ -449,10 +453,10 @@ class FileStorage: ...@@ -449,10 +453,10 @@ class FileStorage:
if old: if old:
file=self._file file=self._file
file.seek(old) file.seek(old)
h=file.read(42) read=file.read
h=read(42)
doid,oserial,sprev,stloc,vlen,splen = unpack(">8s8s8s8sH8s", h) doid,oserial,sprev,stloc,vlen,splen = unpack(">8s8s8s8sH8s", h)
if doid != oid: raise CorruptedDataError, h if doid != oid: raise CorruptedDataError, h
if serial != oserial: raise POSException.ConflictError
if vlen: if vlen:
pnv=read(8) # non-version data pointer pnv=read(8) # non-version data pointer
if (len(version) != vlen or if (len(version) != vlen or
...@@ -461,10 +465,13 @@ class FileStorage: ...@@ -461,10 +465,13 @@ class FileStorage:
): ):
raise POSException.VersionLockError, oid raise POSException.VersionLockError, oid
if serial != oserial: raise POSException.ConflictError
tfile=self._tfile tfile=self._tfile
write=tfile.write write=tfile.write
self._tappend(oid, tfile.tell())
pos=self._pos pos=self._pos
here=tfile.tell()+pos+self._thl
self._tappend(oid, here)
serial=self._serial serial=self._serial
write(pack(">8s8s8s8sH8s", write(pack(">8s8s8s8sH8s",
oid,serial,p64(old),p64(pos), oid,serial,p64(old),p64(pos),
...@@ -475,10 +482,12 @@ class FileStorage: ...@@ -475,10 +482,12 @@ class FileStorage:
if pnv: write(pnv) if pnv: write(pnv)
else: write(p64(old)) else: write(p64(old))
# Link to last record for this version: # Link to last record for this version:
vindex=self._vindex tvindex=self._tvindex
write(p64(vindex[version])) pv=tvindex.get(version, 0) or self._vindexpos(version, 0)
vindex[version]=pos write(p64(pv))
tvindex[version]=here
write(version) write(version)
write(data) write(data)
return serial return serial
...@@ -505,12 +514,30 @@ class FileStorage: ...@@ -505,12 +514,30 @@ class FileStorage:
self._ca() self._ca()
self._a() self._a()
self._transaction=transaction self._transaction=transaction
del self._tindex[:] # Just to be sure! del self._tindex[:] # Just to be sure!
self._tvindex.clear() # ''
self._tfile.seek(0) self._tfile.seek(0)
t=time.time() t=time.time()
t=apply(TimeStamp,(time.gmtime(t)[:5]+(t%60,))) t=apply(TimeStamp,(time.gmtime(t)[:5]+(t%60,)))
self._ts=t=t.laterThan(self._ts) self._ts=t=t.laterThan(self._ts)
self._serial=`t` self._serial=`t`
user=transaction.user
desc=transaction.description
ext=transaction._extension
if ext: ext=dumps(ext,1)
else: ext=""
# Ugh, we have to record the transaction header length
# so that we can get version pointers right.
self._thl=33+len(user)+len(desc)+len(ext)
# And we have to save the data used to compute the
# header length. It's unlikely that this stuff would
# change, but if it did, it would be a disaster.
self._ude=user, desc, ext
finally: self._r() finally: self._r()
def tpc_finish(self, transaction, f=None): def tpc_finish(self, transaction, f=None):
...@@ -524,13 +551,10 @@ class FileStorage: ...@@ -524,13 +551,10 @@ class FileStorage:
dlen=tfile.tell() dlen=tfile.tell()
tfile.seek(0) tfile.seek(0)
id=self._serial id=self._serial
user=transaction.user user, desc, ext = self._ude
desc=transaction.description self._ude=None
ext=transaction._extension
if ext: ext=dumps(ext,1) tlen=self._thl
else: ext=""
tlen=33+len(user)+len(desc)+len(ext)
pos=self._pos pos=self._pos
file.seek(pos) file.seek(pos)
stpos=p64(self._tpos) stpos=p64(self._tpos)
...@@ -551,11 +575,15 @@ class FileStorage: ...@@ -551,11 +575,15 @@ class FileStorage:
self._tpos=pos self._tpos=pos
self._pos=pos+tl+8 self._pos=pos+tl+8
tindex=self._tindex
index=self._index index=self._index
dpos=pos+tlen for oid, pos in tindex: index[oid]=pos
for oid, pos in self._tindex: index[oid]=pos+dpos del tindex[:]
tvindex=self._tvindex
self._vindex.update(tvindex)
tvindex.clear()
del self._tindex[:]
self._transaction=None self._transaction=None
self._cr() self._cr()
finally: self._r() finally: self._r()
...@@ -571,6 +599,10 @@ class FileStorage: ...@@ -571,6 +599,10 @@ class FileStorage:
def versionEmpty(self, version): def versionEmpty(self, version):
return not self._vindex.has_key(version) return not self._vindex.has_key(version)
def versions(self, max=None):
if max: return self._vindex.keys()[:max]
return self._vindex.keys()
def read_index(file, name, index, vindex, tindex, stop='\377'*8, def read_index(file, name, index, vindex, tindex, stop='\377'*8,
log=lambda s: None): log=lambda s: None):
...@@ -677,7 +709,7 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8, ...@@ -677,7 +709,7 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8,
tappend((oid,pos)) tappend((oid,pos))
if vlen: if vlen:
dlen=vlen+16 dlen=dlen+16
seek(8,1) seek(8,1)
pv=u64(read(8)) pv=u64(read(8))
version=read(vlen) version=read(vlen)
...@@ -716,16 +748,19 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8, ...@@ -716,16 +748,19 @@ def read_index(file, name, index, vindex, tindex, stop='\377'*8,
def _loadBack(file, oid, back): def _loadBack(file, oid, back):
seek=file.seek
read=file.read
while 1: while 1:
old=unpack(">i",back)[0] old=u64(back)
if not old: raise KeyError, oid if not old: raise KeyError, oid
file.seek(old) seek(old)
h=file.read(42) h=read(42)
doid,serial,prev,tloc,vlen,plen = unpack(">8s8s8s8sH8s", h) doid,serial,prev,tloc,vlen,plen = unpack(">8s8s8s8sH8s", h)
if doid != oid or vlen: if doid != oid or vlen:
panic(lambda x: None, panic(lambda x: None,
"%s version record back pointer points to " "%s version record back pointer points to "
"invalid record as %s", name, back) "invalid record as %s", name, back)
if plen: return read(plen), serial if plen: return read(u64(plen)), serial
back=read(4) # We got a back pointer! back=read(8) # We got a back pointer!
*shared* *shared*
cPersistence cPersistence.c -I../../Components/ExtensionClass cPersistence cPersistence.c -I../../Components/ExtensionClass
cPickleCache cPickleCache.c -I../../Components/ExtensionClass cPickleCache cPickleCache.c -I../../Components/ExtensionClass
TimeStamp TimeStamp.c -DUSE_EXTENSION_CLASS TimeStamp TimeStamp.c -I../../Components/ExtensionClass -DUSE_EXTENSION_CLASS
...@@ -84,8 +84,8 @@ ...@@ -84,8 +84,8 @@
############################################################################## ##############################################################################
"""Transaction management """Transaction management
$Id: Transaction.py,v 1.5 1999/05/10 23:15:56 jim Exp $""" $Id: Transaction.py,v 1.6 1999/05/12 15:55:44 jim Exp $"""
__version__='$Revision: 1.5 $'[11:-2] __version__='$Revision: 1.6 $'[11:-2]
import time, sys, struct import time, sys, struct
from struct import pack from struct import pack
...@@ -130,7 +130,7 @@ class Transaction: ...@@ -130,7 +130,7 @@ class Transaction:
This aborts any transaction in progres. This aborts any transaction in progres.
''' '''
if self._objects: self._abort(0) if self._objects: self.abort(0)
self.__init__() self.__init__()
if info: if info:
info=split(info,'\t') info=split(info,'\t')
......
...@@ -87,7 +87,9 @@ ...@@ -87,7 +87,9 @@
This module provides a wrapper that causes a database connection to be created This module provides a wrapper that causes a database connection to be created
and used when bobo publishes a bobo_application object. and used when bobo publishes a bobo_application object.
""" """
__version__='$Revision: 1.3 $'[11:-2] __version__='$Revision: 1.4 $'[11:-2]
StringType=type('')
class ZApplicationWrapper: class ZApplicationWrapper:
...@@ -137,6 +139,8 @@ class ZApplicationWrapper: ...@@ -137,6 +139,8 @@ class ZApplicationWrapper:
if connection is None: if connection is None:
connection=db.open() connection=db.open()
elif type(connection) is StringType:
connection=db.open(connection)
return connection.root()[aname] return connection.root()[aname]
......
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
# #
############################################################################## ##############################################################################
import sys, ExtensionClass, TimeStamp, cPersistence, Persistence import sys, ExtensionClass, TimeStamp, cPersistence, Persistence
import cStringIO, cPickle
# This is lame. Don't look. :( # This is lame. Don't look. :(
sys.modules['cPersistence']=cPersistence sys.modules['cPersistence']=cPersistence
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
attributions are listed in the accompanying credits file. attributions are listed in the accompanying credits file.
****************************************************************************/ ****************************************************************************/
static char *what_string = "$Id: cPersistence.c,v 1.27 1999/05/10 23:15:56 jim Exp $"; static char *what_string = "$Id: cPersistence.c,v 1.28 1999/05/12 15:55:44 jim Exp $";
#include <string.h> #include <string.h>
#include "cPersistence.h" #include "cPersistence.h"
...@@ -484,6 +484,8 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name, ...@@ -484,6 +484,8 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
case 's': case 's':
if(strcmp(n,"erial")==0) if(strcmp(n,"erial")==0)
return PyString_FromStringAndSize(self->serial, 8); return PyString_FromStringAndSize(self->serial, 8);
if(strcmp(n,"elf")==0)
return orNothing(OBJECT(self));
break; break;
case 'm': case 'm':
if(strcmp(n,"time")==0) if(strcmp(n,"time")==0)
...@@ -581,6 +583,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -581,6 +583,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
if (! v || v==Py_None) if (! v || v==Py_None)
{ {
if (Per__p_deactivate(self, NULL)) Py_DECREF(Py_None); if (Per__p_deactivate(self, NULL)) Py_DECREF(Py_None);
self->state=cPersistent_GHOST_STATE;
return 0; return 0;
} }
if (PyObject_IsTrue(v)) return changed(self); if (PyObject_IsTrue(v)) return changed(self);
...@@ -635,7 +638,7 @@ static PyExtensionClass Pertype = { ...@@ -635,7 +638,7 @@ static PyExtensionClass Pertype = {
/* Space for future expansion */ /* Space for future expansion */
0L,0L,"", 0L,0L,"",
METHOD_CHAIN(Per_methods), METHOD_CHAIN(Per_methods),
EXTENSIONCLASS_BASICNEW_FLAG, EXTENSIONCLASS_BASICNEW_FLAG | PERSISTENT_TYPE_FLAG,
}; };
/* End of code for Persistent objects */ /* End of code for Persistent objects */
...@@ -687,7 +690,7 @@ void ...@@ -687,7 +690,7 @@ void
initcPersistence() initcPersistence()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.27 $"; char *rev="$Revision: 1.28 $";
TimeStamp=PyString_FromString("TimeStamp"); TimeStamp=PyString_FromString("TimeStamp");
if (! TimeStamp) return; if (! TimeStamp) return;
......
...@@ -123,6 +123,8 @@ static cPersistenceCAPIstruct *cPersistenceCAPI; ...@@ -123,6 +123,8 @@ static cPersistenceCAPIstruct *cPersistenceCAPI;
#define cPersistanceModuleName "cPersistence" #define cPersistanceModuleName "cPersistence"
#define PERSISTENT_TYPE_FLAG EXTENSIONCLASS_USER_FLAG8
#define PER_USE_OR_RETURN(O,R) { \ #define PER_USE_OR_RETURN(O,R) { \
if ((O)->state==cPersistent_GHOST_STATE && \ if ((O)->state==cPersistent_GHOST_STATE && \
cPersistenceCAPI->setstate((PyObject*)(O)) < 0) \ cPersistenceCAPI->setstate((PyObject*)(O)) < 0) \
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
attributions are listed in the accompanying credits file. attributions are listed in the accompanying credits file.
****************************************************************************/ ****************************************************************************/
static char *what_string = "$Id: cPickleCache.c,v 1.18 1999/05/10 23:15:57 jim Exp $"; static char *what_string = "$Id: cPickleCache.c,v 1.19 1999/05/12 15:55:44 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))
...@@ -492,16 +492,19 @@ cc_subscript(ccobject *self, PyObject *key) ...@@ -492,16 +492,19 @@ cc_subscript(ccobject *self, PyObject *key)
return r; return r;
} }
static PyExtensionClass *Persistent=0;
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) && ||
ExtensionClassSubclassInstance_Check(v, Persistent) (PyExtensionInstance_Check(v)
&&
(((PyExtensionClass*)(v->ob_type))->class_flags
& PERSISTENT_TYPE_FLAG)
&&
(v->ob_type->tp_basicsize >= sizeof(cPersistentObject))
) )
) )
return PyDict_SetItem(self->data, key, v); return PyDict_SetItem(self->data, key, v);
...@@ -563,20 +566,12 @@ void ...@@ -563,20 +566,12 @@ void
initcPickleCache() initcPickleCache()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.18 $"; char *rev="$Revision: 1.19 $";
Cctype.ob_type=&PyType_Type; Cctype.ob_type=&PyType_Type;
UNLESS(ExtensionClassImported) return; UNLESS(ExtensionClassImported) return;
/* Get the Persistent base class */
UNLESS(m=PyString_FromString(cPersistanceModuleName)) return;
ASSIGN(m, PyImport_Import(m));
UNLESS(m) return;
ASSIGN(m, PyObject_GetAttrString(m, "Persistent"));
UNLESS(m) return;
Persistent=(PyExtensionClass *)m;
m = Py_InitModule4("cPickleCache", cCM_methods, "", m = Py_InitModule4("cPickleCache", cCM_methods, "",
(PyObject*)NULL,PYTHON_API_VERSION); (PyObject*)NULL,PYTHON_API_VERSION);
......
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
import POSException
# Try to create a function that creates Unix file locks. On windows
# this will fail.
try:
import fcntl, FCNTL
lock_file_FLAG=FCNTL.LOCK_EX|FCNTL.LOCK_NB
def lock_file(file, error=POSException.StorageSystemError):
try: un=file.fileno()
except: return # don't care if not a real file
try: fcntl.flock(un,lock_file_FLAG)
except:
raise error, (
"Could not lock the database file. There must be\n"
"another process that has opened the file.\n"
"<p>")
except:
# Try windows-specific code:
try:
from winlock import LockFile
def lock_file(file, error=POSException.StorageSystemError):
try: un=file.fileno()
except: return # don't care if not a real file
try: LockFile(un,0,0,1,0) # just lock the first byte, who cares
except:
raise error, (
"Could not lock the database file. There must be\n"
"another process that has opened the file.\n"
"<p>")
except:
def lock_file(file, error=None): pass
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
attributions are listed in the accompanying credits file. attributions are listed in the accompanying credits file.
****************************************************************************/ ****************************************************************************/
static char *what_string = "$Id: cPersistence.c,v 1.27 1999/05/10 23:15:56 jim Exp $"; static char *what_string = "$Id: cPersistence.c,v 1.28 1999/05/12 15:55:44 jim Exp $";
#include <string.h> #include <string.h>
#include "cPersistence.h" #include "cPersistence.h"
...@@ -484,6 +484,8 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name, ...@@ -484,6 +484,8 @@ Per_getattr(cPersistentObject *self, PyObject *oname, char *name,
case 's': case 's':
if(strcmp(n,"erial")==0) if(strcmp(n,"erial")==0)
return PyString_FromStringAndSize(self->serial, 8); return PyString_FromStringAndSize(self->serial, 8);
if(strcmp(n,"elf")==0)
return orNothing(OBJECT(self));
break; break;
case 'm': case 'm':
if(strcmp(n,"time")==0) if(strcmp(n,"time")==0)
...@@ -581,6 +583,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v, ...@@ -581,6 +583,7 @@ _setattro(cPersistentObject *self, PyObject *oname, PyObject *v,
if (! v || v==Py_None) if (! v || v==Py_None)
{ {
if (Per__p_deactivate(self, NULL)) Py_DECREF(Py_None); if (Per__p_deactivate(self, NULL)) Py_DECREF(Py_None);
self->state=cPersistent_GHOST_STATE;
return 0; return 0;
} }
if (PyObject_IsTrue(v)) return changed(self); if (PyObject_IsTrue(v)) return changed(self);
...@@ -635,7 +638,7 @@ static PyExtensionClass Pertype = { ...@@ -635,7 +638,7 @@ static PyExtensionClass Pertype = {
/* Space for future expansion */ /* Space for future expansion */
0L,0L,"", 0L,0L,"",
METHOD_CHAIN(Per_methods), METHOD_CHAIN(Per_methods),
EXTENSIONCLASS_BASICNEW_FLAG, EXTENSIONCLASS_BASICNEW_FLAG | PERSISTENT_TYPE_FLAG,
}; };
/* End of code for Persistent objects */ /* End of code for Persistent objects */
...@@ -687,7 +690,7 @@ void ...@@ -687,7 +690,7 @@ void
initcPersistence() initcPersistence()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.27 $"; char *rev="$Revision: 1.28 $";
TimeStamp=PyString_FromString("TimeStamp"); TimeStamp=PyString_FromString("TimeStamp");
if (! TimeStamp) return; if (! TimeStamp) return;
......
...@@ -123,6 +123,8 @@ static cPersistenceCAPIstruct *cPersistenceCAPI; ...@@ -123,6 +123,8 @@ static cPersistenceCAPIstruct *cPersistenceCAPI;
#define cPersistanceModuleName "cPersistence" #define cPersistanceModuleName "cPersistence"
#define PERSISTENT_TYPE_FLAG EXTENSIONCLASS_USER_FLAG8
#define PER_USE_OR_RETURN(O,R) { \ #define PER_USE_OR_RETURN(O,R) { \
if ((O)->state==cPersistent_GHOST_STATE && \ if ((O)->state==cPersistent_GHOST_STATE && \
cPersistenceCAPI->setstate((PyObject*)(O)) < 0) \ cPersistenceCAPI->setstate((PyObject*)(O)) < 0) \
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
attributions are listed in the accompanying credits file. attributions are listed in the accompanying credits file.
****************************************************************************/ ****************************************************************************/
static char *what_string = "$Id: cPickleCache.c,v 1.18 1999/05/10 23:15:57 jim Exp $"; static char *what_string = "$Id: cPickleCache.c,v 1.19 1999/05/12 15:55:44 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))
...@@ -492,16 +492,19 @@ cc_subscript(ccobject *self, PyObject *key) ...@@ -492,16 +492,19 @@ cc_subscript(ccobject *self, PyObject *key)
return r; return r;
} }
static PyExtensionClass *Persistent=0;
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) && ||
ExtensionClassSubclassInstance_Check(v, Persistent) (PyExtensionInstance_Check(v)
&&
(((PyExtensionClass*)(v->ob_type))->class_flags
& PERSISTENT_TYPE_FLAG)
&&
(v->ob_type->tp_basicsize >= sizeof(cPersistentObject))
) )
) )
return PyDict_SetItem(self->data, key, v); return PyDict_SetItem(self->data, key, v);
...@@ -563,20 +566,12 @@ void ...@@ -563,20 +566,12 @@ void
initcPickleCache() initcPickleCache()
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.18 $"; char *rev="$Revision: 1.19 $";
Cctype.ob_type=&PyType_Type; Cctype.ob_type=&PyType_Type;
UNLESS(ExtensionClassImported) return; UNLESS(ExtensionClassImported) return;
/* Get the Persistent base class */
UNLESS(m=PyString_FromString(cPersistanceModuleName)) return;
ASSIGN(m, PyImport_Import(m));
UNLESS(m) return;
ASSIGN(m, PyObject_GetAttrString(m, "Persistent"));
UNLESS(m) return;
Persistent=(PyExtensionClass *)m;
m = Py_InitModule4("cPickleCache", cCM_methods, "", m = Py_InitModule4("cPickleCache", cCM_methods, "",
(PyObject*)NULL,PYTHON_API_VERSION); (PyObject*)NULL,PYTHON_API_VERSION);
......
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