Commit 40bac312 authored by Julien Muchembled's avatar Julien Muchembled

Fix sorting of delayed events

The initial intention was to rely on stable sorting when several events have
the same key. For this to happen, sorting must not continue the comparison with
the second item of events.

This could lead to data corruption (conflict resolution with wrong base):

  FAIL: testNotifyReplicated (neo.tests.threaded.test.Test)
  ----------------------------------------------------------------------
  Traceback (most recent call last):
    File "neo/tests/threaded/__init__.py", line 1093, in wrapper
      return wrapped(self, cluster, *args, **kw)
    File "neo/tests/threaded/test.py", line 2019, in testNotifyReplicated
      self.assertEqual([15, 11, 13, 16], [r[x].value for x in 'abcd'])
    File "neo/tests/__init__.py", line 187, in assertEqual
      return super(NeoTestBase, self).assertEqual(first, second, msg=msg)
  failureException: Lists differ: [15, 11, 13, 16] != [19, 11, 13, 16]

  First differing element 0:
  15
  19

  - [15, 11, 13, 16]
  ?   ^

  + [19, 11, 13, 16]
  ?   ^
parent 6841e2f2
......@@ -16,6 +16,7 @@
import sys
from collections import deque
from operator import itemgetter
from . import logging
from .connection import ConnectionClosed
from .protocol import (
......@@ -317,16 +318,19 @@ class EventQueue(object):
self._event_queue = []
self._executing_event = -1
sortQueuedEvents = (lambda key=itemgetter(0): lambda self:
self._event_queue.sort(key=key))()
def queueEvent(self, func, conn=None, args=(), key=None):
assert self._executing_event < 0, self._executing_event
self._event_queue.append((key, func if conn is None else
_DelayedConnectionEvent(func, conn, args)))
if key is not None:
self._event_queue.sort()
self.sortQueuedEvents()
def sortAndExecuteQueuedEvents(self):
if self._executing_event < 0:
self._event_queue.sort()
self.sortQueuedEvents()
self.executeQueuedEvents()
else:
# We can't sort events when they're being processed.
......@@ -359,9 +363,10 @@ class EventQueue(object):
while done:
del queue[done.pop()]
self._executing_event = 0
# What sortQueuedEvents could not do immediately is done here:
# What sortAndExecuteQueuedEvents could not do immediately
# is done here:
if event[0] is not None:
queue.sort()
self.sortQueuedEvents()
self._executing_event = -1
def logQueuedEvents(self):
......
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