# -*- coding: iso-8859-1 -*-
#-----------------------------------------------------------------------------
# Modeling Framework: an Object-Relational Bridge for python
#
# Copyright (c) 2001-2004 Sbastien Bigaret <sbigaret@users.sourceforge.net>
# All rights reserved.
#
# This file is part of the Modeling Framework.
#
# This code is distributed under a "3-clause BSD"-style license;
# see the LICENSE file for details.
#-----------------------------------------------------------------------------
"""
"""
__version__='$Revision: 932 $'[11:-2]
from time import time
from logging import info,debug
# Constants
DistantPastTimeInterval = 0
from Modeling.utils import base_object
class SnapshotsTable(base_object):
"""
__TBD
"""
def __init__(self):
"""
Initializer. Note that the timestamp is initialized to the value
'time.time()'.
"""
self._currentTimestamp=time()
self.__isSnapshotRefCountingEnabled=1
# ``regular'' snapshots
self._snapshots={} # GlobalID -> snapshot (dictionary)
self._snapshotsRefCount={} # GlobalID -> refCount
self._timestamps={} # GlobalID -> timestamp
# ``sourceGlobalIDs'' / toMany snapshots
self._gidsForSrcGid={} # GlobalID -> {'name' -> GlobalIDs (list)}
self._timeStampForSrcGid={} # GlobalID -> {'name' -> timeStamp}
def isSnapshotRefCountingEnabled(self):
"""
Tells whether snapshot refCounting is enabled.
Note that once it has been disabled, the snapshot refcounting **cannot**
be re-enabled.
If you need to bind this to some external functionality or trigger of your
own, simply subclass 'SnapshotsTable' and override this method, and
possibly disableSnapshotRefCounting() as well. An example of such an
usage can be found in class 'Database' (cf. 'Database.SnapshotsTable').
See also: disableSnapshotRefCounting(),
decrementSnapshotCountForGlobalID(),
incrementSnapshotCountForGlobalID()
"""
return self.__isSnapshotRefCountingEnabled
def decrementSnapshotCountForGlobalID(self, aGlobalID):
"""
"""
if not self.isSnapshotRefCountingEnabled():
return
refCount=self._snapshotsRefCount[aGlobalID]-1
if refCount != 0:
#debug('### refCount for globalID: %s decremented to %i'%(aGlobalID,
# refCount))
self._snapshotsRefCount[aGlobalID]=refCount
else: ## release the snapshots
#info('### refCount reached 0 for globalID: %s'%aGlobalID)
self.forgetSnapshotForGlobalID(aGlobalID)
def disableSnapshotRefCounting(self):
"""
Disables the snapshot refcounting. Note that once it has been disabled,
the snapshot refcounting **cannot** be re-enabled.
Please refer to documentation for 'isSnapshotRefCountingEnabled()' for
a full discussion what subclasses may do.
"""
self.__isSnapshotRefCountingEnabled=0
def forgetAllSnapshots(self):
"""
Clears every snapshots currently referenced
See also: forgetSnapshotForGlobalID(), forgetSnapshotForGlobalIDs()
"""
self._snapshotsRefCount={}
self._snapshots={}
self._timestamps={}
self._gidsForSrcGid={}
self._timeStampForSrcGid={}
def forgetSnapshotForGlobalID(self, aGlobalID):
"""
Deletes all references to snapshots for 'aGlobalID'
See also: forgetSnapshotForGlobalID(), forgetAllSnapshots()
"""
del self._snapshotsRefCount[aGlobalID]
del self._snapshots[aGlobalID]
del self._timestamps[aGlobalID]
del self._gidsForSrcGid[aGlobalID]
del self._timeStampForSrcGid[aGlobalID]
def forgetSnapshotForGlobalIDs(self, globalIDs):
"""
Deletes all references to snapshots registered for the GlobalIDs in
'globalIDs'
Parameter:
'globalIDs' -- a sequence of 'GlobalID'
Raises KeyError if one GlobalID in 'globalIDs' is not registered.
See also: forgetSnapshotForGlobalID(), forgetAllSnapshots()
"""
validGids=self.globalIDs()
for gID in globalIDs: # first make sure each gID is indeed registered
if gid not in validGids:
raise KeyError
for gID in globalIDs:
self.forgetSnapshotForGlobalID(gID)
def globalIDs(self):
"""
Returns the list of all 'GlobalIDs' referenced in the snapshots
"""
return self._timestamps.keys()
def incrementSnapshotCountForGlobalID(self, aGlobalID):
"""
See also: decrementSnapshotCountForGlobalID()
"""
if not self.isSnapshotRefCountingEnabled():
return
self._snapshotsRefCount[aGlobalID]+=1
#debug('### refCount for globalID: %s incremented to %i'%(aGlobalID, self._snapshotsRefCount[aGlobalID]))
def recordSnapshotForGlobalID(self, snapshot, aGlobalID):
self.setTimestampToNow()
self._snapshots[aGlobalID]=snapshot
self._timestamps[aGlobalID]=self._currentTimestamp
self._snapshotsRefCount.setdefault(aGlobalID, 0)
# resets toMany as well
self._gidsForSrcGid[aGlobalID]={}
self._timeStampForSrcGid[aGlobalID]={}
def recordSnapshotForSourceGlobalID(self, gids, aGlobalID, aName):
"""
Sets the toMany snapshot for the supplied GlobalID.
Note that 'aGlobalID' should already be known to the SnapshotsTable,
or ValueError is raised
"""
self.setTimestampToNow()
if self._snapshots.get(aGlobalID, None) is None:
raise ValueError, 'Unknown GlobalID: %s'%str(aGlobalID)
# GlobalID -> {'name' -> GlobalIDs (list)}
_gidsForSrcGid=self._gidsForSrcGid.get(aGlobalID, {})
_gidsForSrcGid[aName]=gids
self._gidsForSrcGid[aGlobalID]=_gidsForSrcGid
# GlobalID -> {'name' -> timeStamp}
_timeStampForSrcGid=self._timeStampForSrcGid.get(aGlobalID, {})
_timeStampForSrcGid[aName]=self._currentTimestamp
self._timeStampForSrcGid[aGlobalID]=_timeStampForSrcGid
def recordSnapshots(self, snapshots):
for gID in snapshots.keys():
self.recordSnapshotForGlobalID(snapshots[gID], gID)
def recordToManySnapshots(self, snapshots):
"""
Records the snapshots for a toMany relationship.
Parameter:
snapshots -- a dictionary with GlobalIDs as keys and dictionary as
values, the latter dictionary having relationships' names as keys and
a list of GlobalIDs as values.
"""
for gID in snapshots.keys():
for name in snapshots[gID].keys():
self.recordSnapshotForSourceGlobalID(snapshots[gID][name], gID, name)
def setTimestampToNow(self):
self._currentTimestamp=time()
def snapshotCountForGlobalID(self, aGlobalID):
"""
See also: incrementSnapshotCountForGlobalID,
decrementSnapshotCountForGlobalID()
"""
return self._snapshotsRefCount.get(aGlobalID, 0)
def snapshotForGlobalID(self,
aGlobalID, timestamp=DistantPastTimeInterval):
snapshot=self._snapshots.get(aGlobalID, None)
if snapshot is None:
return snapshot
if self._timestamps[aGlobalID] >= timestamp :
return snapshot
return None
def snapshotForSourceGlobalID(self, aGlobalID, aName,
timestamp=DistantPastTimeInterval):
if self._timeStampForSrcGid.get(aGlobalID, {}).get(aName, DistantPastTimeInterval) < timestamp:
return ()
return self._gidsForSrcGid.get(aGlobalID,{}).get(aName, ())
def snapshots(self):
d={}
d.update(self._snapshots)
return d
def toManySnapshots(self):
d={}
d.update(self._gidsForSrcGid)
return d
def timestampForGlobalID(self, aGlobalID):
return self._timestamps.get(aGlobalID, DistantPastTimeInterval)
def timestampForSourceGlobalID(self, aGlobalID, aName):
return self._timeStampForSrcGid.get(aGlobalID,{}).get(aName,DistantPastTimeInterval)
def __unimplemented__(self):
"Raises Unimplemented..."
raise 'Unimplemented', 'Not supported yet'
|