Merge lp:~divmod-dev/divmod.org/829879-pypy-finalization-semantics into lp:divmod.org

Proposed by Tristan Seligmann
Status: Superseded
Proposed branch: lp:~divmod-dev/divmod.org/829879-pypy-finalization-semantics
Merge into: lp:divmod.org
Diff against target: 153 lines (+38/-32)
3 files modified
Axiom/axiom/_fincache.py (+32/-28)
Axiom/axiom/store.py (+5/-3)
Axiom/axiom/test/test_reference.py (+1/-1)
To merge this branch: bzr merge lp:~divmod-dev/divmod.org/829879-pypy-finalization-semantics
Reviewer Review Type Date Requested Status
Laurens Van Houtven Pending
Review via email: mp+172946@code.launchpad.net

This proposal supersedes a proposal from 2011-08-20.

This proposal has been superseded by a proposal from 2013-07-04.

Description of the change

Resubmitting without the "optional-pycrypto" dependency, as this is only relevant to Mantissa.

To post a comment you must log in.
Revision history for this message
Laurens Van Houtven (lvh) wrote : Posted in a previous version of this proposal

LGTM, and makes my exception go away:

https://gist.github.com/lvh/9059ae79bc3ba7b10f73

Some notes:

- this doesn't appear to have any tests.
- is the API sufficiently internal remove the "has" method?

review: Needs Fixing
Revision history for this message
Jean-Paul Calderone (exarkun) wrote : Posted in a previous version of this proposal

The change also introduces new `assert` statements. We have since learned that the way these new statements are being used is not helpful. If you want an exception to be raised, raise an exception (and document it and test it).

Revision history for this message
Laurens Van Houtven (lvh) wrote : Posted in a previous version of this proposal

I'm not sure it really introduces any *new* ones: it just keeps the old one. (I only count three assert statements in the diff: one is just diff context; the other two are in the old and new versions of the "uncache" method -- that's the old one being kept.)

That doesn't mean changing the assertion to something else isn't a good idea, of course. That said, this is probably the minimal change that closes this ticket. Would you be okay with the assertions being changed in a different ticket? If you'd like, I will file a bug for and fix it, assuming that gets this ticket moving along :)

Revision history for this message
Tristan Seligmann (mithrandi) wrote :

I still need to rebase the actual branch on trunk, of course. *facepalm* I'll try to look at this soon.

Revision history for this message
Laurens Van Houtven (lvh) wrote :

My only remaining point is that I'm not sure about is the behavior of get. I understand this class isn't a dict, but get() mirrored dict behavior by returning a value or None. Returning a value or raising an exception is the behavior of __getitem__ :)

2703. By Jonathan Jacobs

Accept varargs in Divmod.UnitTest.TestCase.assertThrows.

Author: jjacobs
Reviewer: exarkun

Pass varargs to assertThrows on to the callable, matching the way Python's assertRaises works.

Revision history for this message
Tristan Seligmann (mithrandi) wrote :

The API of get() is not changed in this branch, unless I missed something?

2704. By Tristan Seligmann

Tolerate less strict finalization semantics.

2705. By Tristan Seligmann

Replace assert with raise, and repeat the "dead weakref" check logic.

2706. By Tristan Seligmann

Docstrings, comments, and better argument names.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Axiom/axiom/_fincache.py'
2--- Axiom/axiom/_fincache.py 2006-04-01 19:46:29 +0000
3+++ Axiom/axiom/_fincache.py 2013-07-04 16:05:30 +0000
4@@ -1,4 +1,3 @@
5-
6 from weakref import ref
7 from traceback import print_exc
8
9@@ -6,11 +5,12 @@
10
11 from axiom import iaxiom
12
13-class CacheFault(RuntimeError):
14- """
15- A serious problem has occurred within the cache. This error is internal
16- and should never really be trapped.
17- """
18+class CacheFault(KeyError):
19+ """
20+ An item has fallen out of cache, but the weakref callback has not yet run.
21+ """
22+
23+
24
25 def logErrorNoMatterWhat():
26 try:
27@@ -27,6 +27,8 @@
28 # to. Don't bother.
29 return
30
31+
32+
33 def createCacheRemoveCallback(w, k, f):
34 def remove(self):
35 # Weakref callbacks cannot raise exceptions or DOOM ensues
36@@ -37,12 +39,16 @@
37 try:
38 self = w()
39 if self is not None:
40- del self.data[k]
41+ try:
42+ del self.data[k]
43+ except KeyError:
44+ # Already gone
45+ pass
46 except:
47 logErrorNoMatterWhat()
48 return remove
49
50-PROFILING = False
51+
52
53 class FinalizingCache:
54 """Possibly useful for infrastructure? This would be a nice addition (or
55@@ -50,9 +56,7 @@
56 """
57 def __init__(self):
58 self.data = {}
59- if not PROFILING:
60- # see docstring for 'has'
61- self.has = self.data.has_key
62+
63
64 def cache(self, key, value):
65 fin = value.__finalizer__()
66@@ -61,28 +65,28 @@
67 ref(self), key, fin))
68 return value
69
70+
71 def uncache(self, key, value):
72- assert self.get(key) is value
73- del self.data[key]
74-
75- def has(self, key):
76- """Does the cache have this key?
77-
78- (This implementation is only used if the system is being profiled, due
79- to bugs in Python's old profiler and its interaction with weakrefs.
80- Set the module attribute PROFILING to True at startup for this.)
81- """
82- if key in self.data:
83- o = self.data[key]()
84- if o is None:
85- del self.data[key]
86- return False
87- return True
88- return False
89+ """
90+ Remove a key from the cache.
91+
92+ As a sanity check, if the specified key is present in the cache, it
93+ must have the given value.
94+
95+ @param key: The key to remove.
96+ @param value: The expected value for the key.
97+ """
98+ try:
99+ assert self.get(key) is value
100+ del self.data[key]
101+ except KeyError:
102+ pass
103+
104
105 def get(self, key):
106 o = self.data[key]()
107 if o is None:
108+ del self.data[key]
109 raise CacheFault(
110 "FinalizingCache has %r but its value is no more." % (key,))
111 log.msg(interface=iaxiom.IStatEvent, stat_cache_hits=1, key=key)
112
113=== modified file 'Axiom/axiom/store.py'
114--- Axiom/axiom/store.py 2012-08-04 11:07:11 +0000
115+++ Axiom/axiom/store.py 2013-07-04 16:05:30 +0000
116@@ -1747,10 +1747,10 @@
117 self.executeSQL(sql, insertArgs)
118
119 def _loadedItem(self, itemClass, storeID, attrs):
120- if self.objectCache.has(storeID):
121+ try:
122 result = self.objectCache.get(storeID)
123 # XXX do checks on consistency between attrs and DB object, maybe?
124- else:
125+ except KeyError:
126 result = itemClass.existingInStore(self, storeID, attrs)
127 if not result.__legacy__:
128 self.objectCache.cache(storeID, result)
129@@ -2205,8 +2205,10 @@
130 type(storeID).__name__,))
131 if storeID == STORE_SELF_ID:
132 return self
133- if self.objectCache.has(storeID):
134+ try:
135 return self.objectCache.get(storeID)
136+ except KeyError:
137+ pass
138 log.msg(interface=iaxiom.IStatEvent, stat_cache_misses=1, key=storeID)
139 results = self.querySchemaSQL(_schema.TYPEOF_QUERY, [storeID])
140 assert (len(results) in [1, 0]),\
141
142=== modified file 'Axiom/axiom/test/test_reference.py'
143--- Axiom/axiom/test/test_reference.py 2009-07-06 12:35:46 +0000
144+++ Axiom/axiom/test/test_reference.py 2013-07-04 16:05:30 +0000
145@@ -186,7 +186,7 @@
146 store = Store()
147 t = nonUpgradedItem(store=store)
148 self.assertEquals(t.__legacy__, True)
149- self.assertFalse(store.objectCache.has(t.storeID))
150+ self.assertRaises(KeyError, store.objectCache.get, t.storeID)
151 t2 = store.getItemByID(t.storeID)
152 self.assertNotIdentical(t, t2)
153 self.assertTrue(isinstance(t2, UpgradedItem))

Subscribers

People subscribed via source and target branches

to all changes: