Skip to content

Commit

Permalink
Let the MergingCounter be reset to 0.
Browse files Browse the repository at this point in the history
Fixes #6
  • Loading branch information
jamadden committed Aug 6, 2020
1 parent e2e5c12 commit 6b6b0e3
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
the ``increment`` method. See `issue 7
<https://github.com/NextThought/nti.zodb/issues/7>`_.

- The merging counter does the right thing when reset to zero by two
conflicting transactions. See `issue 6
<https://github.com/NextThought/nti.zodb/issues/6>`_.

1.1.0 (2020-07-15)
==================

Expand Down
10 changes: 10 additions & 0 deletions src/nti/zodb/minmax.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ class MergingCounter(AbstractNumericValue):
A :mod:`zope.minmax` item that resolves conflicts by
merging the numeric value of the difference in magnitude of changes.
Intented to be used for monotonically increasing counters.
As a special case, if the counter is reset to zero by both transactions,
that becomes the new state.
.. versionchanged:: 1.2.0
Special case setting the counter to zero.
"""

def increment(self, amount=1):
Expand All @@ -160,6 +167,9 @@ def increment(self, amount=1):
return self

def _p_resolveConflict(self, oldState, savedState, newState): # pylint:disable=arguments-differ
if savedState == newState == 0:
return 0

saveDiff = savedState - oldState
newDiff = newState - oldState
savedState = oldState + saveDiff + newDiff
Expand Down
9 changes: 6 additions & 3 deletions src/nti/zodb/tests/test_minmax.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,13 @@ def test_numeric_counter_interface(self):
validly_provides(interfaces.INumericCounter))

def test_merge_resolve(self):
assert_that(MergingCounter()._p_resolveConflict(0, 0, 1), is_(1))
# (original state, currently committed, desired)
mc = self._makeOne()
assert_that(mc._p_resolveConflict(0, 0, 1), is_(1))
# simultaneous increment adds
assert_that(MergingCounter()._p_resolveConflict(0, 1, 1), is_(2))

assert_that(mc._p_resolveConflict(0, 1, 1), is_(2))
# In the special case that both set it to zero, it becomes 0
assert_that(mc._p_resolveConflict(10, 0, 0), is_(0))

def test_str(self):

Expand Down

0 comments on commit 6b6b0e3

Please sign in to comment.