Commit 1f2a7cce authored by Chris McDonough's avatar Chris McDonough

Merge from 2.7 branch:

- Add "instance-local" "period" to TransientObjectContainer.  This allows
  users to dial a knob which may (or may not) reduce the number of conflicts
  that happen during heavy sessioning usage by reducing the frequency at
  which buckets potentially expire at the cost of expiration time
  accuracy.  Previously, this setting was hardcoded to 20 (seconds) at
  module scope.

- Add 'session-resolution-seconds' to zope.conf.in/zopeschema.xml to
  control instance-local period for /temp_folder/session_data.

- Update TOC UI, interface, and help files to deal with instance-local
  period.

- Update OFS/Application to deal with instance-local period for default
  /temp/session_data TOC.

- Use __setstate__ for TOC upgrade instead of a dedicated _upgrade method
  (it was too hard to figure out where to call _upgrade from and when to
  call it).

- Perform a few formatting changes that should make it easier to merge the 2.7
  branch with the HEAD going forward.  I beseech those who make formatting
  changes to a branch or the HEAD make them to the other at that time
  as well, especially with the SVN/CVS split it's very painful to do merging
  when there are non-substantive differences between HEAD/maint.  When I was
  a child, I never thought I would need to use the word "beseech", however, it
  has indeed happened.
parent 0871e361
############################################################################
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
......@@ -375,9 +375,15 @@ class AppInitializer:
delnotify = getattr(config, 'session_delete_notify_script_path',
None)
default_limit = 1000
default_period_secs = 20
default_timeout_mins = 20
limit = (getattr(config, 'maximum_number_of_session_objects', None)
or default_limit)
timeout_spec = getattr(config, 'session_timeout_minutes', None)
timeout_spec = getattr(config, 'session_timeout_minutes',
default_timeout_mins)
period_spec = getattr(config, 'session_resolution_seconds',
default_period_secs)
if addnotify and app.unrestrictedTraverse(addnotify, None) is None:
LOG('Zope Default Object Creation', WARNING,
......@@ -395,7 +401,8 @@ class AppInitializer:
'session_data', 'Session Data Container',
addNotification = addnotify,
delNotification = delnotify,
limit=limit)
limit=limit,
period_secs=period_spec)
if timeout_spec is not None:
toc = TransientObjectContainer('session_data',
......@@ -403,7 +410,8 @@ class AppInitializer:
timeout_mins = timeout_spec,
addNotification = addnotify,
delNotification = delnotify,
limit=limit)
limit=limit,
period_secs = period_spec)
tf._setObject('session_data', toc)
tf_reserved = getattr(tf, '_reserved_names', ())
......
......@@ -16,8 +16,6 @@ Transient Object Container Class ('timeslice'-based design, no index).
$Id$
"""
__version__='$Revision: 1.32.12.5 $'[11:-2]
import math
import time
import random
......@@ -54,7 +52,6 @@ CREATE_TRANSIENTS_PERM = 'Create Transient Objects'
ACCESS_TRANSIENTS_PERM = 'Access Transient Objects'
MANAGE_CONTAINER_PERM = 'Manage Transient Object Container'
PERIOD = 20 # signifies "resolution" of transience machinery in seconds
SPARE_BUCKETS = 15 # minimum number of buckets to keep "spare"
BUCKET_CLASS = OOBTree # constructor for buckets
STRICT = os.environ.get('Z_TOC_STRICT', '')
......@@ -80,10 +77,11 @@ constructTransientObjectContainerForm = HTMLFile(
'dtml/addTransientObjectContainer', globals())
def constructTransientObjectContainer(self, id, title='', timeout_mins=20,
addNotification=None, delNotification=None, limit=0, REQUEST=None):
addNotification=None, delNotification=None, limit=0, period_secs=20,
REQUEST=None):
""" """
ob = TransientObjectContainer(id, title, timeout_mins,
addNotification, delNotification, limit=limit)
addNotification, delNotification, limit=limit, period_secs=period_secs)
self._setObject(id, ob)
if REQUEST is not None:
return self.manage_main(self, REQUEST, update_menu=1)
......@@ -133,10 +131,10 @@ class TransientObjectContainer(SimpleItem):
security.setDefaultAccess('deny')
def __init__(self, id, title='', timeout_mins=20, addNotification=None,
delNotification=None, limit=0):
delNotification=None, limit=0, period_secs=20):
self.id = id
self.title=title
self._setTimeout(timeout_mins)
self._setTimeout(timeout_mins, period_secs)
self._setLimit(limit)
self.setDelNotificationTarget(delNotification)
self.setAddNotificationTarget(addNotification)
......@@ -144,12 +142,42 @@ class TransientObjectContainer(SimpleItem):
# helpers
def _setTimeout(self, timeout_mins):
def _setTimeout(self, timeout_mins, period_secs):
if type(timeout_mins) is not type(1):
raise TypeError, (escape(`timeout_mins`), "Must be integer")
self._timeout_secs = t_secs = timeout_mins * 60
# timeout_slices == fewest number of timeslices that's >= t_secs
self._timeout_slices=int(math.ceil(float(t_secs)/PERIOD))
if type(period_secs) is not type(1):
raise TypeError, (escape(`period_secs`), "Must be integer")
timeout_secs = timeout_mins * 60
# special-case 0-minute timeout value by ignoring period
if timeout_secs != 0:
if period_secs == 0:
raise ValueError('resolution cannot be 0')
if period_secs > timeout_secs:
raise ValueError(
'resolution cannot be greater than timeout '
'minutes * 60 ( %s > %s )' % (period_secs, timeout_secs))
# we need the timeout to be evenly divisible by the period
if timeout_secs % period_secs != 0:
raise ValueError(
'timeout seconds (%s) must be evenly divisible '
'by resolution (%s)' % (timeout_secs, period_secs)
)
# our timeout secs is the number of seconds that an item should
# remain unexpired
self._timeout_secs = timeout_secs
# our _period is the number of seconds that constitutes a timeslice
self._period = period_secs
# timeout_slices == fewest number of timeslices that's >= timeout_secs
self._timeout_slices=int(math.ceil(float(timeout_secs)/period_secs))
def _setLimit(self, limit):
if type(limit) is not type(1):
......@@ -173,7 +201,10 @@ class TransientObjectContainer(SimpleItem):
# populate _data with some number of buckets, each of which
# is "current" for its timeslice key
if self._timeout_slices:
new_slices = getTimeslices(getCurrentTimeslice(), SPARE_BUCKETS*2)
new_slices = getTimeslices(
getCurrentTimeslice(self._period),
SPARE_BUCKETS*2,
self._period)
for i in new_slices:
self._data[i] = BUCKET_CLASS()
# create an Increaser for max timeslice
......@@ -190,32 +221,26 @@ class TransientObjectContainer(SimpleItem):
def _getCurrentSlices(self, now):
if self._timeout_slices:
begin = now - (PERIOD * self._timeout_slices)
begin = now - (self._period * self._timeout_slices)
# add add one to _timeout_slices below to account for the fact that
# a call to this method may happen any time within the current
# timeslice; calling it in the beginning of the timeslice can lead
# to sessions becoming invalid a maximum of <PERIOD> seconds
# to sessions becoming invalid a maximum of self._period seconds
# earlier than the requested timeout value. Adding one here can
# lead to sessions becoming invalid *later* than the timeout value
# (also by a max of <PERIOD>), but in the common sessioning case,
# that seems preferable.
# (also by a max of self._period), but in the common sessioning
# case, that seems preferable.
num_slices = self._timeout_slices + 1
else:
return [0] # sentinel for timeout value 0 (don't expire)
DEBUG and TLOG('_getCurrentSlices, now = %s ' % now)
DEBUG and TLOG('_getCurrentSlices, begin = %s' % begin)
DEBUG and TLOG('_getCurrentSlices, num_slices = %s' % num_slices)
result = getTimeslices(begin, num_slices)
result = getTimeslices(begin, num_slices, self._period)
DEBUG and TLOG('_getCurrentSlices, result = %s' % result)
return result
def _move_item(self, k, current_ts, default=None):
if not getattr(self, '_max_timeslice', None):
# in-place upgrade for old instances; this would usually be
# "evil" but sessions are all about write-on-read anyway,
# so it really doesn't matter.
self._upgrade()
if self._timeout_slices:
if self._roll(current_ts, 'replentish'):
......@@ -289,12 +314,8 @@ class TransientObjectContainer(SimpleItem):
return item
def _all(self):
if not getattr(self, '_max_timeslice', None):
# in-place upgrade for old instances
self._upgrade()
if self._timeout_slices:
current_ts = getCurrentTimeslice()
current_ts = getCurrentTimeslice(self._period)
else:
current_ts = 0
......@@ -352,7 +373,7 @@ class TransientObjectContainer(SimpleItem):
def __getitem__(self, k):
if self._timeout_slices:
current_ts = getCurrentTimeslice()
current_ts = getCurrentTimeslice(self._period)
else:
current_ts = 0
item = self._move_item(k, current_ts, _marker)
......@@ -366,7 +387,7 @@ class TransientObjectContainer(SimpleItem):
def __setitem__(self, k, v):
DEBUG and TLOG('__setitem__: called with key %s, value %s' % (k,v))
if self._timeout_slices:
current_ts = getCurrentTimeslice()
current_ts = getCurrentTimeslice(self._period)
else:
current_ts = 0
item = self._move_item(k, current_ts, _marker)
......@@ -398,7 +419,7 @@ class TransientObjectContainer(SimpleItem):
def __delitem__(self, k):
DEBUG and TLOG('__delitem__ called with key %s' % k)
if self._timeout_slices:
current_ts = getCurrentTimeslice()
current_ts = getCurrentTimeslice(self._period)
else:
current_ts = 0
item = self._move_item(k, current_ts)
......@@ -418,7 +439,7 @@ class TransientObjectContainer(SimpleItem):
def get(self, k, default=None):
DEBUG and TLOG('get: called with key %s, default %s' % (k, default))
if self._timeout_slices:
current_ts = getCurrentTimeslice()
current_ts = getCurrentTimeslice(self._period)
else:
current_ts = 0
item = self._move_item(k, current_ts, default)
......@@ -431,7 +452,7 @@ class TransientObjectContainer(SimpleItem):
security.declareProtected(ACCESS_TRANSIENTS_PERM, 'has_key')
def has_key(self, k):
if self._timeout_slices:
current_ts = getCurrentTimeslice()
current_ts = getCurrentTimeslice(self._period)
else:
current_ts = 0
DEBUG and TLOG('has_key: calling _move_item with %s' % str(k))
......@@ -455,8 +476,8 @@ class TransientObjectContainer(SimpleItem):
is to minimize the chance that two threads will attempt to
do housekeeping at the same time (causing conflicts).
"""
low = now/PERIOD
high = self._max_timeslice()/PERIOD
low = now/self._period
high = self._max_timeslice()/self._period
if high <= low:
# we really need to win this roll because we have no
# spare buckets (and no valid values to provide to randrange), so
......@@ -481,7 +502,7 @@ class TransientObjectContainer(SimpleItem):
return # do nothing if no timeout
max_ts = self._max_timeslice()
available_spares = (max_ts-now) / PERIOD
available_spares = (max_ts-now) / self._period
DEBUG and TLOG('_replentish: now = %s' % now)
DEBUG and TLOG('_replentish: max_ts = %s' % max_ts)
DEBUG and TLOG('_replentish: available_spares = %s'
......@@ -490,19 +511,19 @@ class TransientObjectContainer(SimpleItem):
if available_spares < SPARE_BUCKETS:
if max_ts < now:
replentish_start = now
replentish_end = now + (PERIOD * SPARE_BUCKETS)
replentish_end = now + (self._period * SPARE_BUCKETS)
else:
replentish_start = max_ts + PERIOD
replentish_end = max_ts + (PERIOD * SPARE_BUCKETS)
replentish_start = max_ts + self._period
replentish_end = max_ts + (self._period * SPARE_BUCKETS)
DEBUG and TLOG('_replentish: replentish_start = %s' %
replentish_start)
DEBUG and TLOG('_replentish: replentish_end = %s'
% replentish_end)
# n is the number of buckets to create
n = (replentish_end - replentish_start) / PERIOD
new_buckets = getTimeslices(replentish_start, n)
n = (replentish_end - replentish_start) / self._period
new_buckets = getTimeslices(replentish_start, n, self._period)
new_buckets.reverse()
STRICT and _assert(new_buckets)
DEBUG and TLOG('_replentish: adding %s new buckets' % n)
......@@ -523,8 +544,8 @@ class TransientObjectContainer(SimpleItem):
return # dont do gc if there is no timeout
if now is None:
now = getCurrentTimeslice() # for unit tests
max_ts = now - (PERIOD * (self._timeout_slices + 1))
now = getCurrentTimeslice(self._period) # for unit tests
max_ts = now - (self._period * (self._timeout_slices + 1))
to_notify = []
......@@ -633,16 +654,26 @@ class TransientObjectContainer(SimpleItem):
# TransientItemContainer methods
security.declareProtected(MANAGE_CONTAINER_PERM, 'setTimeoutMinutes')
def setTimeoutMinutes(self, timeout_mins):
""" """
if timeout_mins != self.getTimeoutMinutes():
self._setTimeout(timeout_mins)
def setTimeoutMinutes(self, timeout_mins, period_secs=20):
""" The period_secs parameter is defaulted to preserve backwards API
compatibility. In older versions of this code, period was
hardcoded to 20. """
timeout_secs = timeout_mins * 60
if (timeout_mins != self.getTimeoutMinutes()
or period_secs != self.getPeriodSeconds()):
# do nothing unless something has changed
self._setTimeout(timeout_mins, period_secs)
self._reset()
def getTimeoutMinutes(self):
""" """
return self._timeout_secs / 60
def getPeriodSeconds(self):
""" """
return self._period
security.declareProtected(MGMT_SCREEN_PERM, 'getSubobjectLimit')
def getSubobjectLimit(self):
""" """
......@@ -681,11 +712,11 @@ class TransientObjectContainer(SimpleItem):
'manage_changeTransientObjectContainer')
def manage_changeTransientObjectContainer(
self, title='', timeout_mins=20, addNotification=None,
delNotification=None, limit=0, REQUEST=None
delNotification=None, limit=0, period_secs=20, REQUEST=None
):
""" Change an existing transient object container. """
self.title = title
self.setTimeoutMinutes(timeout_mins)
self.setTimeoutMinutes(timeout_mins, period_secs)
self.setSubobjectLimit(limit)
if not addNotification:
addNotification = None
......@@ -699,49 +730,61 @@ class TransientObjectContainer(SimpleItem):
self, REQUEST, manage_tabs_message='Changes saved.'
)
def _upgrade(self):
# inplace upgrade for versions of Transience in Zope versions less
def __setstate__(self, state):
# upgrade versions of Transience in Zope versions less
# than 2.7.1, which used a different transience mechanism. Note:
# this will not work for upgrading versions older than 2.6.0,
# all of which used a very different transience implementation
if not getattr(self, '_max_timeslice', None):
new_slices = getTimeslices(getCurrentTimeslice(), SPARE_BUCKETS*2)
# can't make __len__ an instance variable in new-style classes
# f/w compat: 2.8 cannot use __len__ as an instance variable
if not state.has_key('_length'):
length = state.get('__len__', Length())
self._length = self.getLen = length
# TOCs prior to 2.7.1 took their period from a global
if not state.has_key('_period'):
self._period = 20 # this was the default for all prior releases
# TOCs prior to 2.7.1 used a different set of data structures
# for efficiently keeping tabs on the maximum slice
if not state.has_key('_max_timeslice'):
new_slices = getTimeslices(
getCurrentTimeslice(self._period),
SPARE_BUCKETS*2,
self._period)
for i in new_slices:
if not self._data.has_key(i):
self._data[i] = BUCKET_CLASS()
# create an Increaser for max timeslice
self._max_timeslice = Increaser(max(new_slices))
# can't make __len__ an instance variable in new-style classes
if not getattr(self, '_length', None):
length = self.__dict__.get('__len__', Length())
self._length = self.getLen = length
# we should probably delete older attributes such as
# we should probably delete older attributes from state such as
# '_last_timeslice', '_deindex_next',and '__len__' here but we leave
# them in order to allow people to switch between 2.6.0->2.7.0 and
# 2.7.1+ as necessary (although that has not been tested)
self.__dict__.update(state)
def getCurrentTimeslice():
def getCurrentTimeslice(period):
"""
Return an integer representing the 'current' timeslice.
The current timeslice is guaranteed to be the same integer
within a 'slice' of time based on a divisor of 'period'.
'period' is the number of seconds in a slice.
within a 'slice' of time based on a divisor of 'self._period'.
'self._period' is the number of seconds in a slice.
"""
now = time.time()
low = int(math.floor(now)) - PERIOD + 1
low = int(math.floor(now)) - period + 1
high = int(math.ceil(now)) + 1
for x in range(low, high):
if x % PERIOD == 0:
if x % period == 0:
return x
def getTimeslices(begin, n):
def getTimeslices(begin, n, period):
""" Get a list of future timeslice integers of 'n' size in descending
order """
l = []
for x in range(n):
l.insert(0, begin + (x * PERIOD))
l.insert(0, begin + (x * period))
return l
def _assert(case):
......
......@@ -62,7 +62,7 @@ the Zope physical path to the method to be invoked to receive the notification
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Data object timeout in minutes
Data object timeout (in minutes)
</div>
<div class="form-help">
("0" means no expiration)
......@@ -73,6 +73,20 @@ the Zope physical path to the method to be invoked to receive the notification
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Timeout resolution (in seconds)
</div>
<div class="form-help">
(accept the default if you're not sure)
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="period_secs:int" SIZE="10" value="20">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
......
......@@ -5,7 +5,6 @@
help_topic='Transience-change.stx'
)">
<form action="manage_changeTransientObjectContainer" method="post">
<p class="form-help">
......@@ -13,7 +12,9 @@ Transient Object Containers are used to store transient data.
Transient data will persist, but only for a user-specified period of time
(the "data object timeout") after which it will be flushed.
</p>
<dtml-call nudge><!-- turn the buckets if necessary -->
<p class="form-label">
<font color="green">
<dtml-let l=getLen>
......@@ -43,7 +44,7 @@ Transient data will persist, but only for a user-specified period of time
<tr>
<td align="left" valign="top">
<div class="form-label">
Data object timeout value in minutes
Data object timeout value (in minutes)
</div>
<div class="form-help">
("0" means no expiration)
......@@ -55,6 +56,26 @@ Transient data will persist, but only for a user-specified period of time
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Timeout resolution (in seconds)
</div>
<div class="form-help">
Defines what the "resolution" of item timeout is. Setting this higher
allows the transience machinery to do fewer "writes" at the expense of
causing items to time out later than the "Data object timeout value" by
a factor of (at most) this many seconds. This number must divide evenly
into the number of timeout seconds ("Data object timeout value" * 60)
and cannot be set higher than the timeout value in seconds.
</div>
</td>
<td align="left" valign="top">
<input type="text" name="period_secs:int" size=10
value=&dtml-getPeriodSeconds;>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
......@@ -100,6 +121,22 @@ Transient data will persist, but only for a user-specified period of time
</td>
</tr>
<dtml-let l=getLen>
<dtml-if l>
<tr>
<td colspan=2>
<br/>
<p class="form-label">
<font color="red">WARNING!</font>
All data objects existing in this transient object container
will be deleted when the data object timeout or expiration resolution
is changed.
</p>
</tr>
</td>
</dtml-if>
</dtml-let>
<tr>
<td></td>
<td>
......@@ -109,12 +146,5 @@ Transient data will persist, but only for a user-specified period of time
</table>
</form>
<p class="form-label">
<font color="red">WARNING!</font>
The data objects existing in this transient object container
will be deleted when the data object timeout is changed.
</p>
<dtml-var manage_page_footer>
......@@ -23,13 +23,23 @@ TransientObjectContainer - Add
The title of the object.
- **Data object timeout in minutes**
- **Data object timeout (in minutes)**
The minimum number of minutes that objects in the container will
persist for. Objects in the container are passively deleted, so
they may not be deleted exactly after this number of minutes elapses.
A setting of "0" indicates that objects should not expire.
- **Timeout resolution (in seconds)**
Defines what the "resolution" of item timeout is. Setting this
higher allows the transience machinery to do fewer "writes" at
the expense of causing items to time out later than the "Data
object timeout value" by a factor of (at most) this many
seconds. This number must divide evenly into the number of
timeout seconds ("Data object timeout value" * 60) and cannot
be set higher than the timeout value in seconds.
- **Maximum number of subobjects **
The maximum number of subobjects that this container may
......
......@@ -23,7 +23,7 @@ TransientObjectContainer - Manage
The title of the object.
- **Data object timeout in minutes**
- **Data object timeout (in minutes)**
The minimum number of minutes that objects in the container will
persist for. Objects in the container are passively deleted, so
......@@ -34,6 +34,16 @@ TransientObjectContainer - Manage
If the timeout value is "0", objects will not time out.
- **Timeout resolution (in seconds)**
Defines what the "resolution" of item timeout is. Setting this
higher allows the transience machinery to do fewer "writes" at
the expense of causing items to time out later than the "Data
object timeout value" by a factor of (at most) this many
seconds. This number must divide evenly into the number of
timeout seconds ("Data object timeout value" * 60) and cannot
be set higher than the timeout value in seconds.
- **Maximum number of subobjects **
The maximum number of subobjects that this container may
......@@ -92,11 +102,6 @@ TransientObjectContainer - Manage
from zLOG import LOG
LOG(100, 'test', 'id: %s' % item.getId())
Environment Variables
You can control some transient object settings with environment
variables. See 'doc/ENVIORNMENT.txt' for more informatin.
See Also
- "Transience API":TransienceInterfaces.py
......
......@@ -80,10 +80,12 @@ class TransientObjectContainer:
Permission -- 'Create Transient Objects'
"""
def setTimeoutMinutes(self, timeout_mins):
def setTimeoutMinutes(self, timeout_mins, period=20):
"""
Set the number of minutes of inactivity allowable for subobjects
before they expire.
before they expire (timeout_mins) as well as the 'timeout resolution'
in seconds (period). 'timeout_mins' * 60 must be evenly divisible
by the period. Period must be less than 'timeout_mins' * 60.
Permission -- 'Manage Transient Object Container'
"""
......@@ -96,6 +98,13 @@ class TransientObjectContainer:
Permission -- 'View management screens'
"""
def getPeriodSeconds(self):
"""
Return the 'timeout resolution' in seconds.
Permission -- 'View management screens'
"""
def getAddNotificationTarget(self):
"""
Returns the current 'after add' function, or None.
......
......@@ -34,7 +34,9 @@ class TestBase(TestCase):
self.errmargin = .20
self.timeout = 120
self.t = TransientObjectContainer('sdc', timeout_mins=self.timeout/60)
self.period = 20
self.t = TransientObjectContainer('sdc', timeout_mins=self.timeout/60,
period_secs=self.period)
def tearDown(self):
self.t = None
......@@ -267,7 +269,7 @@ class TestTransientObjectContainer(TestBase):
self.assertEqual(len(self.t.keys()), 0)
# 2 minutes
self.t._setTimeout(self.timeout/60*2)
self.t._setTimeout(self.timeout/60*2, self.period)
self.t._reset()
for x in range(10, 110):
self.t[x] = x
......@@ -279,7 +281,7 @@ class TestTransientObjectContainer(TestBase):
self.assertEqual(len(self.t.keys()), 0)
# 3 minutes
self.t._setTimeout(self.timeout/60*3)
self.t._setTimeout(self.timeout/60*3, self.period)
self.t._reset()
for x in range(10, 110):
self.t[x] = x
......@@ -318,7 +320,8 @@ class TestTransientObjectContainer(TestBase):
def testLen(self):
# This test must not time out else it will fail.
self.t._setTimeout(self.timeout) # make timeout extremely unlikely
# make timeout extremely unlikely by setting it very high
self.t._setTimeout(self.timeout, self.period)
added = {}
r = range(10, 1010)
for x in r:
......@@ -340,8 +343,9 @@ class TestTransientObjectContainer(TestBase):
def testGetTimeoutMinutesWorks(self):
self.assertEqual(self.t.getTimeoutMinutes(), self.timeout / 60)
self.t._setTimeout(10)
self.t._setTimeout(10, 30)
self.assertEqual(self.t.getTimeoutMinutes(), 10)
self.assertEqual(self.t.getPeriodSeconds(), 30)
def test_new(self):
t = self.t.new('foobieblech')
......@@ -369,7 +373,7 @@ class TestTransientObjectContainer(TestBase):
self.assertRaises(MaxTransientObjectsExceeded, self._maxOut)
def testZeroTimeoutMeansPersistForever(self):
self.t._setTimeout(0)
self.t._setTimeout(0, self.period)
self.t._reset()
for x in range(10, 110):
self.t[x] = x
......
......@@ -627,6 +627,16 @@
<metadefault>20</metadefault>
</key>
<key name="session-resolution-seconds" datatype="integer"
default="20">
<description>
An integer value representing the number of seconds to be used as the
"timeout resolution" of the '/temp_folder/session_data' transient
object container in Zope's object database.
</description>
<metadefault>20</metadefault>
</key>
<key name="suppress-all-access-rules" datatype="boolean"
default="off" handler="suppress_all_access_rules">
<description>
......
......@@ -548,6 +548,20 @@ instancehome $INSTANCE
# session-timeout-minutes 30
# Directive: session-resolution-seconds
#
# Description:
# An integer value representing the number of seconds to be used as the
# "timeout resolution" of the '/temp_folder/session_data' transient
# object container.
#
# Default: 20
#
# Example:
#
# session-resolution-seconds 60
# Directive: suppress-all-access-rules
#
# Description:
......
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