Beispiel #1
0
    def mergeJoinDispatch(self, event, obj):
        """ Performs a merge join on the pending fan-in dispatches.

        @param event: an event that is being merge joined (destination state must be a fan in)
        @return: a list (possibly empty) of FSMContext instances
        """
        # this assertion comes from _queueDispatchFanIn - we never want fan-out info in a fan-in context
        assert not self.get(constants.GEN_PARAM)
        assert not self.get(constants.FORK_PARAM)

        # the work package index is stored in the url of the Task/FSMContext
        index = self.get(constants.INDEX_PARAM)
        self.logger.debug('Index: %s', index)
        taskNameBase = self.getTaskName(event, fanIn=True)

        # see comment (***) in self._queueDispatchFanIn
        #
        # in the case of failing to acquire a read lock (due to failed release of write lock)
        # we have decided to keep retrying
        raiseOnFail = False
        if self._getTaskRetryLimit() is not None:
            raiseOnFail = (self._getTaskRetryLimit() > self.__obj[constants.RETRY_COUNT_PARAM])

        rwlock = ReadWriteLock(taskNameBase, self)
        rwlock.acquireReadLock(index, raiseOnFail=raiseOnFail)

        # and return the FSMContexts list
        class FSMContextList(list):
            """ A list that supports .logger.info(), .logger.warning() etc.for fan-in actions """
            def __init__(self, context, contexts, guarded=False):
                """ setup a self.logger for fan-in actions """
                super(FSMContextList, self).__init__(contexts)
                self.logger = Logger(context)
                self.instanceName = context.instanceName
                self.guarded = guarded

        # see comment (A) in self._queueDispatchFanIn(...)
        time.sleep(constants.DATASTORE_ASYNCRONOUS_INDEX_WRITE_WAIT_TIME)

        # the following step ensure that fan-in only ever operates one time over a list of data
        # the entity is created in State.dispatch(...) _after_ all the actions have executed
        # successfully
        khash = knuthHash(index)
        self.logger.debug('knuthHash of index: %s', khash)
        workIndex = '%s-%d' % (taskNameBase, khash)
        if obj[constants.RETRY_COUNT_PARAM] > 0:
            semaphore = RunOnceSemaphore(workIndex, self)
            if semaphore.readRunOnceSemaphore(payload=self.__obj[constants.TASK_NAME_PARAM]):
                self.logger.info("Fan-in idempotency guard for workIndex '%s', not processing any work items.",
                                 workIndex)
                return FSMContextList(self, [], guarded=True) # don't operate over the data again

        # fetch all the work packages in the current group for processing
        query = _FantasmFanIn.all(namespace='') \
                             .filter('workIndex =', workIndex) \
                             .order('__key__')

        # construct a list of FSMContexts
        contexts = [self.clone(replaceData=r.context) for r in query]
        return FSMContextList(self, contexts)
Beispiel #2
0
 def test_acquireReadLock_before_acquireWriteLock(self):
     lock = ReadWriteLock('foo', self.context)
     index = lock.currentIndex()
     self.assertEqual(None, memcache.get(lock.lockKey(index)))
     lock.acquireReadLock(index)
     self.assertEqual(None, memcache.get(lock.lockKey(index)))
     self.assertEqual([], self.loggingDouble.messages['debug'])
     self.assertEqual([], self.loggingDouble.messages['critical'])
Beispiel #3
0
 def test_acquireReadLock_before_acquireWriteLock(self):
     lock = ReadWriteLock('foo', self.context)
     index = lock.currentIndex()
     self.assertEqual(None, memcache.get(lock.lockKey(index)))
     lock.acquireReadLock(index)
     self.assertEqual(None, memcache.get(lock.lockKey(index)))
     self.assertEqual([], self.loggingDouble.messages['debug'])
     self.assertEqual([], self.loggingDouble.messages['critical'])
Beispiel #4
0
 def test_acquireWriteLock_failure(self):
     lock = ReadWriteLock('foo', self.context)
     index = lock.currentIndex()
     self.assertEqual(None, memcache.get(lock.lockKey(index)))
     lock.acquireWriteLock(index) # need to call before acquireReadLock
     self.assertEqual(65537, memcache.get(lock.lockKey(index)))
     lock.acquireReadLock(index)
     self.assertEqual(32769, memcache.get(lock.lockKey(index)))
     self.assertRaises(FanInWriteLockFailureRuntimeError, lock.acquireWriteLock, index)
Beispiel #5
0
 def test_acquireWriteLock_failure(self):
     lock = ReadWriteLock('foo', self.context)
     index = lock.currentIndex()
     self.assertEqual(None, memcache.get(lock.lockKey(index)))
     lock.acquireWriteLock(index)  # need to call before acquireReadLock
     self.assertEqual('65537', memcache.get(lock.lockKey(index)))
     lock.acquireReadLock(index)
     self.assertEqual('32769', memcache.get(lock.lockKey(index)))
     self.assertRaises(FanInWriteLockFailureRuntimeError,
                       lock.acquireWriteLock, index)
Beispiel #6
0
 def test_acquireReadLock_gave_up(self):
     lock = ReadWriteLock('foo', self.context)
     index = lock.currentIndex()
     self.assertEqual(None, memcache.get(lock.lockKey(index)))
     lock.acquireWriteLock(index)
     self.assertEqual(65537, memcache.get(lock.lockKey(index)))
     lock.acquireReadLock(index)
     self.assertEqual(32769, memcache.get(lock.lockKey(index)))
     self.assertEqual(["Tried to acquire read lock 'foo-lock-3626764237' 1 times...",
                       "Tried to acquire read lock 'foo-lock-3626764237' 2 times..."],
                       self.loggingDouble.messages['debug'])
     self.assertEqual(["Gave up waiting for all fan-in work items with read lock 'foo-lock-3626764237'."],
                      self.loggingDouble.messages['critical'])
Beispiel #7
0
 def test_acquireReadLock_gave_up(self):
     lock = ReadWriteLock('foo', self.context)
     index = lock.currentIndex()
     self.assertEqual(None, memcache.get(lock.lockKey(index)))
     lock.acquireWriteLock(index)
     self.assertEqual('65537', memcache.get(lock.lockKey(index)))
     lock.acquireReadLock(index)
     self.assertEqual('32769', memcache.get(lock.lockKey(index)))
     self.assertEqual([
         "Tried to acquire read lock 'foo-lock-3626764237' 1 times...",
         "Tried to acquire read lock 'foo-lock-3626764237' 2 times..."
     ], self.loggingDouble.messages['debug'])
     self.assertEqual([
         "Gave up waiting for all fan-in work items with read lock 'foo-lock-3626764237'."
     ], self.loggingDouble.messages['critical'])
Beispiel #8
0
 def test_acquireReadLock_one_wait_iter(self):
     lock = ReadWriteLock('foo', self.context)
     index = lock.currentIndex()
     self.assertEqual(None, memcache.get(lock.lockKey(index)))
     lock.acquireWriteLock(index)
     self.assertEqual(65537, memcache.get(lock.lockKey(index)))
     def sleepAndRelease(seconds): # pylint: disable=W0613
         lock.releaseWriteLock(index)
     mock('time.sleep', returns_func=sleepAndRelease, tracker=None)
     lock.acquireReadLock(index)
     self.assertEqual(32768, memcache.get(lock.lockKey(index)))
     self.assertEqual(["Tried to acquire read lock 'foo-lock-3626764237' 1 times..."],
                      self.loggingDouble.messages['debug'])
     self.assertEqual(["Gave up waiting for all fan-in work items with read lock 'foo-lock-3626764237'."],
                      self.loggingDouble.messages['critical'])
Beispiel #9
0
    def test_acquireReadLock_one_wait_iter(self):
        lock = ReadWriteLock('foo', self.context)
        index = lock.currentIndex()
        self.assertEqual(None, memcache.get(lock.lockKey(index)))
        lock.acquireWriteLock(index)
        self.assertEqual('65537', memcache.get(lock.lockKey(index)))

        def sleepAndRelease(seconds):  # pylint: disable-msg=W0613
            lock.releaseWriteLock(index)

        mock('time.sleep', returns_func=sleepAndRelease, tracker=None)
        lock.acquireReadLock(index)
        self.assertEqual('32768', memcache.get(lock.lockKey(index)))
        self.assertEqual(
            ["Tried to acquire read lock 'foo-lock-3626764237' 1 times..."],
            self.loggingDouble.messages['debug'])
        self.assertEqual([
            "Gave up waiting for all fan-in work items with read lock 'foo-lock-3626764237'."
        ], self.loggingDouble.messages['critical'])