Ejemplo n.º 1
0
 def testMultiFuture_Repr(self):
     mf = tasklets.MultiFuture('info')
     r1 = repr(mf)
     mf.putq(1)
     r2 = repr(mf)
     f2 = Future()
     f2.set_result(2)
     mf.putq(2)
     r3 = repr(mf)
     self.ev.run()
     r4 = repr(mf)
     f3 = Future()
     mf.putq(f3)
     r5 = repr(mf)
     mf.complete()
     r6 = repr(mf)
     f3.set_result(3)
     self.ev.run()
     r7 = repr(mf)
     for r in r1, r2, r3, r4, r5, r6, r7:
         self.assertTrue(
             re.match(
                 r'<MultiFuture [\da-f]+ created by '
                 r'(testMultiFuture_Repr\(tasklets_test.py:\d+\)|\?) for info; ',
                 r))
         if r is r7:
             self.assertTrue('result' in r)
         else:
             self.assertTrue('pending' in r)
Ejemplo n.º 2
0
  def map_query(self, query, callback, options=None, merge_future=None):
    mfut = merge_future
    if mfut is None:
      mfut = tasklets.MultiFuture('map_query')

    @tasklets.tasklet
    def helper():
      try:
        inq = tasklets.SerialQueueFuture()
        query.run_to_queue(inq, self._conn, options)
        is_ancestor_query = query.ancestor is not None
        while True:
          try:
            batch, i, ent = yield inq.getq()
          except EOFError:
            break
          if isinstance(ent, model.Key):
            pass  # It was a keys-only query and ent is really a Key.
          else:
            key = ent._key
            if key in self._cache:
              hit = self._cache[key]
              if hit is not None and hit.key != key:
                # The cached entry has been mutated to have a different key.
                # That's a false hit.  Get rid of it.  See issue #13.
                del self._cache[key]
            if key in self._cache:
              # Assume the cache is more up to date.
              if self._cache[key] is None:
                # This is a weird case.  Apparently this entity was
                # deleted concurrently with the query.  Let's just
                # pretend the delete happened first.
                logging.info('Conflict: entity %s was deleted', key)
                continue
              # Replace the entity the callback will see with the one
              # from the cache.
              if ent != self._cache[key]:
                logging.info('Conflict: entity %s was modified', key)
              ent = self._cache[key]
            else:
              # Cache the entity only if this is an ancestor query;
              # non-ancestor queries may return stale results, since in
              # the HRD these queries are "eventually consistent".
              # TODO: Shouldn't we check this before considering cache hits?
              if is_ancestor_query and self._use_cache(key, options):
                self._cache[key] = ent
          if callback is None:
            val = ent
          else:
            # TODO: If the callback raises, log and ignore.
            if options is not None and options.produce_cursors:
              val = callback(batch, i, ent)
            else:
              val = callback(ent)
          mfut.putq(val)
      except Exception, err:
        _, _, tb = sys.exc_info()
        mfut.set_exception(err, tb)
        raise
      else:
Ejemplo n.º 3
0
 def testRunToQueue(self):
   qry = Foo.query()
   queue = tasklets.MultiFuture()
   qry.run_to_queue(queue, self.conn).check_success()
   results = queue.get_result()
   self.assertEqual(len(results), 3)
   self.assertEqual(results[0][2], self.joe)
   self.assertEqual(results[1][2], self.jill)
   self.assertEqual(results[2][2], self.moe)
Ejemplo n.º 4
0
 def testMultiFuture_PreCompleted(self):
   @tasklets.tasklet
   def foo():
     yield tasklets.sleep(0.01)
     raise tasklets.Return(42)
   mfut = tasklets.MultiFuture()
   dep = foo()
   dep.wait()
   mfut.add_dependent(dep)
   mfut.complete()
   eventloop.run()
   self.assertTrue(mfut.done())
   self.assertEqual(mfut.get_result(), [42])
Ejemplo n.º 5
0
    def map_query(self, query, callback, options=None, merge_future=None):
        mfut = merge_future
        if mfut is None:
            mfut = tasklets.MultiFuture('map_query')

        @tasklets.tasklet
        def helper():
            inq = tasklets.SerialQueueFuture()
            query.run_to_queue(inq, self._conn, options)
            is_ancestor_query = query.ancestor is not None
            while True:
                try:
                    batch, i, ent = yield inq.getq()
                except EOFError:
                    break
                if isinstance(ent, model.Key):
                    pass  # It was a keys-only query and ent is really a Key.
                else:
                    key = ent._key
                    if key in self._cache:
                        # Assume the cache is more up to date.
                        if self._cache[key] is None:
                            # This is a weird case.  Apparently this entity was
                            # deleted concurrently with the query.  Let's just
                            # pretend the delete happened first.
                            logging.info('Conflict: entity %s was deleted',
                                         key)
                            continue
                        # Replace the entity the callback will see with the one
                        # from the cache.
                        if ent != self._cache[key]:
                            logging.info('Conflict: entity %s was modified',
                                         key)
                        ent = self._cache[key]
                    else:
                        if is_ancestor_query and self.should_cache(key):
                            self._cache[key] = ent
                if callback is None:
                    val = ent
                else:
                    # TODO: If the callback raises, log and ignore.
                    if options is not None and options.produce_cursors:
                        val = callback(batch, i, ent)
                    else:
                        val = callback(ent)
                mfut.putq(val)
            mfut.complete()

        helper()
        return mfut
Ejemplo n.º 6
0
 def testMultiFuture_ItemException(self):
     mf = tasklets.MultiFuture()
     f1 = Future()
     f2 = Future()
     f3 = Future()
     f2.set_result(2)
     mf.putq(f1)
     f1.set_exception(ZeroDivisionError())
     mf.putq(f2)
     mf.putq(f3)
     f3.set_result(3)
     self.ev.run()
     mf.complete()
     self.assertRaises(ZeroDivisionError, mf.get_result)
Ejemplo n.º 7
0
 def testMultiFuture(self):
   @tasklets.tasklet
   def foo(dt):
     yield tasklets.sleep(dt)
     raise tasklets.Return('foo-%s' % dt)
   @tasklets.tasklet
   def bar(n):
     for i in range(n):
       yield tasklets.sleep(0.01)
     raise tasklets.Return('bar-%d' % n)
   bar5 = bar(5)
   futs = [foo(0.05), foo(0.01), foo(0.03), bar(3), bar5, bar5]
   mfut = tasklets.MultiFuture()
   for fut in futs:
     mfut.add_dependent(fut)
   mfut.complete()
   results = mfut.get_result()
   self.assertEqual(set(results),
                    set(['foo-0.01', 'foo-0.03', 'foo-0.05',
                         'bar-3', 'bar-5']))
Ejemplo n.º 8
0
 def testRunToQueueError(self):
   qry = Foo.query(Foo.name > '', Foo.rate > 0)
   queue = tasklets.MultiFuture()
   fut = qry.run_to_queue(queue, self.conn)
   self.assertRaises(datastore_errors.BadRequestError, fut.check_success)
   self.assertRaises(datastore_errors.BadRequestError, queue.check_success)