Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
7ad4e9ae
Commit
7ad4e9ae
authored
Mar 24, 2002
by
Chris McDonough
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Merging 2-5 branch transience changes to trunk.
parent
67043f55
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
125 additions
and
34 deletions
+125
-34
lib/python/Products/Transience/TransienceInterfaces.py
lib/python/Products/Transience/TransienceInterfaces.py
+17
-1
lib/python/Products/Transience/TransientObject.py
lib/python/Products/Transience/TransientObject.py
+93
-33
lib/python/Products/Transience/tests/testTransientObject.py
lib/python/Products/Transience/tests/testTransientObject.py
+15
-0
No files found.
lib/python/Products/Transience/TransienceInterfaces.py
View file @
7ad4e9ae
...
...
@@ -95,7 +95,9 @@ class Transient(Interface.Base):
def
getLastAccessed
():
"""
Return the time the transient object was last accessed in
integer seconds-since-the-epoch form.
integer seconds-since-the-epoch form. Last accessed time
is defined as the last time the transient object's container
"asked about" this transient object.
"""
def
setLastAccessed
():
...
...
@@ -103,6 +105,20 @@ class Transient(Interface.Base):
Cause the last accessed time to be set to now.
"""
def
getLastModified
():
"""
Return the time the transient object was last modified in
integer seconds-since-the-epoch form. Modification generally implies
a call to one of the transient object's __setitem__ or __delitem__
methods, directly or indirectly as a result of a call to
update, clear, or other mutating data access methods.
"""
def
setLastModified
():
"""
Cause the last modified time to be set to now.
"""
def
getCreated
():
"""
Return the time the transient object was created in integer
...
...
lib/python/Products/Transience/TransientObject.py
View file @
7ad4e9ae
...
...
@@ -13,10 +13,10 @@
"""
Simple ZODB-based transient object implementation.
$Id: TransientObject.py,v 1.
3 2001/11/28 15:51:09 matt
Exp $
$Id: TransientObject.py,v 1.
4 2002/03/24 04:44:32 chrism
Exp $
"""
__version__
=
'$Revision: 1.
3
$'
[
11
:
-
2
]
__version__
=
'$Revision: 1.
4
$'
[
11
:
-
2
]
from
Persistence
import
Persistent
from
Acquisition
import
Implicit
...
...
@@ -25,11 +25,12 @@ from TransienceInterfaces import ItemWithId, Transient, DictionaryLike,\
TTWDictionary
,
ImmutablyValuedMappingOfPickleableObjects
from
AccessControl
import
ClassSecurityInfo
import
Globals
from
zLOG
import
LOG
,
BLATHER
from
zLOG
import
LOG
,
BLATHER
,
INFO
import
sys
_notfound
=
[]
WRITEGRANULARITY
=
30
# Timing granularity for write clustering, in
seconds
WRITEGRANULARITY
=
30
# Timing granularity for access write clustering,
seconds
class
TransientObject
(
Persistent
,
Implicit
):
""" Dictionary-like object that supports additional methods
...
...
@@ -45,12 +46,21 @@ class TransientObject(Persistent, Implicit):
security
=
ClassSecurityInfo
()
security
.
setDefaultAccess
(
'allow'
)
security
.
declareObjectPublic
()
_last_modified
=
None
# _last modified indicates the last time that __setitem__, __delitem__,
# update or clear was called on us.
def
__init__
(
self
,
containerkey
):
self
.
token
=
containerkey
self
.
id
=
self
.
_generateUniqueId
()
self
.
_container
=
{}
self
.
_created
=
self
.
_last_accessed
=
time
.
time
()
# _last_accessed indicates the last time that *our container
# was asked about us* (NOT the last time __getitem__ or get
# or any of our other invariant data access methods are called).
# Our container manages our last accessed time, we don't much
# concern ourselves with it other than exposing an interface
# to set it on ourselves.
# -----------------------------------------------------------------
# ItemWithId
...
...
@@ -72,13 +82,19 @@ class TransientObject(Persistent, Implicit):
def
getLastAccessed
(
self
):
return
self
.
_last_accessed
def
setLastAccessed
(
self
,
WG
=
WRITEGRANULARITY
):
def
setLastAccessed
(
self
):
# check to see if the last_accessed time is too recent, and avoid
# setting if so, to cut down on heavy writes
t
=
time
.
time
()
if
(
self
.
_last_accessed
+
W
G
)
<
t
:
if
(
self
.
_last_accessed
+
W
RITEGRANULARITY
)
<
t
:
self
.
_last_accessed
=
t
def
getLastModified
(
self
):
return
self
.
_last_modified
def
setLastModified
(
self
):
self
.
_last_modified
=
time
.
time
()
def
getCreated
(
self
):
return
self
.
_created
...
...
@@ -109,7 +125,7 @@ class TransientObject(Persistent, Implicit):
def
clear
(
self
):
self
.
_container
.
clear
()
self
.
_p_changed
=
1
self
.
setLastModified
()
def
update
(
self
,
d
):
for
k
in
d
.
keys
():
...
...
@@ -129,25 +145,22 @@ class TransientObject(Persistent, Implicit):
k
.
_p_jar
=
self
.
_p_jar
k
.
_p_changed
=
1
self
.
_container
[
k
]
=
v
self
.
_p_changed
=
1
self
.
setLastModified
()
def
__getitem__
(
self
,
k
):
return
self
.
_container
[
k
]
def
__delitem__
(
self
,
k
):
del
self
.
_container
[
k
]
self
.
setLastModified
()
# -----------------------------------------------------------------
# TTWDictionary
#
set
=
__setitem__
def
delete
(
self
,
k
):
del
self
.
_container
[
k
]
self
.
_p_changed
=
1
__guarded_setitem__
=
__setitem__
delete
=
__delitem__
# -----------------------------------------------------------------
# Other non interface code
...
...
@@ -159,27 +172,58 @@ class TransientObject(Persistent, Implicit):
return
1
def
_p_resolveConflict
(
self
,
saved
,
state1
,
state2
):
attrs
=
[
'token'
,
'id'
,
'_created'
,
'_invalid'
]
# note that last_accessed and _container are the only attrs
# missing from this list. The only time we can clearly resolve
# the conflict is if everything but the last_accessed time and
# the contents are the same, so we make sure nothing else has
# changed. We're being slightly sneaky here by accepting
# possibly conflicting data in _container, but it's acceptable
# in this context.
LOG
(
'Transience'
,
BLATHER
,
'Resolving conflict in TransientObject'
)
for
attr
in
attrs
:
old
=
saved
.
get
(
attr
)
st1
=
state1
.
get
(
attr
)
st2
=
state2
.
get
(
attr
)
if
not
(
old
==
st1
==
st2
):
return
None
# return the object with the most recent last_accessed value.
if
state1
[
'_last_accessed'
]
>
state2
[
'_last_accessed'
]:
return
state1
else
:
return
state2
try
:
states
=
[
saved
,
state1
,
state2
]
# We can clearly resolve the conflict if one state is invalid,
# because it's a terminal state.
for
state
in
states
:
if
state
.
has_key
(
'_invalid'
):
LOG
(
'Transience'
,
BLATHER
,
'a state was invalid'
)
return
state
# The only other times we can clearly resolve the conflict is if
# the token, the id, or the creation time don't differ between
# the three states, so we check that here. If any differ, we punt
# by returning None. Returning None indicates that we can't
# resolve the conflict.
attrs
=
[
'token'
,
'id'
,
'_created'
]
for
attr
in
attrs
:
if
not
(
saved
.
get
(
attr
)
==
state1
.
get
(
attr
)
==
state2
.
get
(
attr
)):
LOG
(
'Transience'
,
BLATHER
,
'cant resolve conflict'
)
return
None
# Now we need to do real work.
#
# Data in our _container dictionaries might conflict. To make
# things simple, we intentionally create a race condition where the
# state which was last modified "wins". It would be preferable to
# somehow merge our _containers together, but as there's no
# generally acceptable way to union their states, there's not much
# we can do about it if we want to be able to resolve this kind of
# conflict.
# We return the state which was most recently modified, if
# possible.
states
.
sort
(
lastmodified_sort
)
if
states
[
0
].
get
(
'_last_modified'
):
LOG
(
'Transience'
,
BLATHER
,
'returning last mod state'
)
return
states
[
0
]
# If we can't determine which object to return on the basis
# of last modification time (no state has been modified), we return
# the object that was most recently accessed (last pulled out of
# our parent). This will return an essentially arbitrary state if
# all last_accessed values are equal.
states
.
sort
(
lastaccessed_sort
)
LOG
(
'Transience'
,
BLATHER
,
'returning last_accessed state'
)
return
states
[
0
]
except
:
LOG
(
'Transience'
,
INFO
,
'Conflict resolution error in TransientObject'
,
''
,
sys
.
exc_info
()
)
getName
=
getId
# this is for SQLSession compatibility
def
_generateUniqueId
(
self
):
...
...
@@ -192,4 +236,20 @@ class TransientObject(Persistent, Implicit):
self
.
id
,
self
.
token
,
`self.items()`
)
def
lastmodified_sort
(
d1
,
d2
):
""" sort dictionaries in descending order based on last mod time """
m1
=
d1
.
get
(
'_last_modified'
,
0
)
m2
=
d2
.
get
(
'_last_modified'
,
0
)
if
m1
==
m2
:
return
0
if
m1
>
m2
:
return
-
1
# d1 is "less than" d2
return
1
def
lastaccessed_sort
(
d1
,
d2
):
""" sort dictionaries in descending order based on last access time """
m1
=
d1
.
get
(
'_last_accessed'
,
0
)
m2
=
d2
.
get
(
'_last_accessed'
,
0
)
if
m1
==
m2
:
return
0
if
m1
>
m2
:
return
-
1
# d1 is "less than" d2
return
1
Globals
.
InitializeClass
(
TransientObject
)
lib/python/Products/Transience/tests/testTransientObject.py
View file @
7ad4e9ae
...
...
@@ -59,6 +59,21 @@ class TestTransientObject(TestCase):
ft
=
fauxtime
.
time
()
assert
t
.
getCreated
()
<=
ft
def
test_getLastModifiedUnset
(
self
):
t
=
self
.
t
.
new
(
'xyzzy'
)
assert
t
.
getLastModified
()
==
None
def
test_getLastModifiedSet
(
self
):
t
=
self
.
t
.
new
(
'xyzzy'
)
t
[
'a'
]
=
1
assert
t
.
getLastModified
()
is
not
None
def
testSetLastModified
(
self
):
t
=
self
.
t
.
new
(
'xyzzy'
)
ft
=
fauxtime
.
time
()
t
.
setLastModified
()
assert
t
.
getLastModified
()
is
not
None
def
test_setLastAccessed
(
self
):
t
=
self
.
t
.
new
(
'xyzzy'
)
ft
=
fauxtime
.
time
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment