
com.twitter.util.Future.scala Maven / Gradle / Ivy
The newest version!
package com.twitter.util
import com.twitter.concurrent.{Offer, Scheduler, Tx}
import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger, AtomicReference, AtomicReferenceArray}
import java.util.concurrent.{CancellationException, TimeUnit, Future => JavaFuture}
import scala.collection.JavaConversions.{asScalaBuffer, seqAsJavaList}
import scala.collection.mutable
import scala.runtime.NonLocalReturnControl
class FutureNonLocalReturnControl(cause: NonLocalReturnControl[_]) extends Exception(cause) {
override def getMessage: String = "Invalid use of `return` in closure passed to a Future"
}
object Future {
val DEFAULT_TIMEOUT = Duration.Top
val Unit = apply(())
val Void = apply[Void](null: Void)
val Done = Unit
val None: Future[Option[Nothing]] = new ConstFuture(Return.None)
val Nil: Future[Seq[Nothing]] = new ConstFuture(Return.Nil)
val True: Future[Boolean] = new ConstFuture(Return.True)
val False: Future[Boolean] = new ConstFuture(Return.False)
private val toUnit: Any => Future[Unit] = scala.Function.const(Unit)
private val toVoid: Any => Future[Void] = scala.Function.const(Void)
// Exception used to raise on Futures.
private[this] val RaiseException = new Exception with NoStacktrace
@inline private final def raiseException = RaiseException
/**
* Makes a Future with a constant result.
*/
def const[A](result: Try[A]): Future[A] = new ConstFuture[A](result)
/**
* Make a Future with a constant value. E.g., Future.value(1) is a Future[Int].
*/
def value[A](a: A): Future[A] = const[A](Return(a))
/**
* Make a Future with an error. E.g., Future.exception(new
* Exception("boo")).
*/
def exception[A](e: Throwable): Future[A] = const[A](Throw(e))
/**
* Make a Future with an error. E.g., Future.exception(new
* Exception("boo")). The exception is not wrapped in any way.
*/
def rawException[A](e: Throwable): Future[A] = const[A](Throw(e))
/**
* A new future that can never complete.
*/
val never: Future[Nothing] = new NoFuture
/**
* A unit future that completes after `howlong`.
*/
def sleep(howlong: Duration)(implicit timer: Timer): Future[Unit] = {
if (howlong == Duration.Zero)
return Future.Done
val p = new Promise[Unit]
val task = timer.schedule(howlong.fromNow) { p.setDone() }
p.setInterruptHandler {
case e =>
if (p.updateIfEmpty(Throw(e)))
task.cancel()
}
p
}
@deprecated("Prefer static Future.Void.", "5.x")
def void(): Future[Void] = value[Void](null)
/**
* A factory function to "lift" computations into the Future monad.
* It will catch nonfatal (see: [[com.twitter.util.NonFatal]])
* exceptions and wrap them in the Throw[_] type. Non-exceptional
* values are wrapped in the Return[_] type.
*/
def apply[A](a: => A): Future[A] = const(Try(a))
def unapply[A](f: Future[A]): Option[Try[A]] = f.poll
/**
* Run the computation {{mkFuture}} while installing a monitor that
* translates any exception thrown into an encoded one. If an
* exception is thrown anywhere, the underlying computation is
* interrupted with that exception.
*
* This function is usually called to wrap a computation that
* returns a Future (f0) whose value is satisfied by the invocation
* of an onSuccess/onFailure/ensure callbacks of another future
* (f1). If an exception happens in the callbacks on f1, f0 is
* never satisfied. In this example, `Future.monitored { f1
* onSuccess g; f0 }` will cancel f0 so that f0 never hangs.
*/
def monitored[A](mkFuture: => Future[A]): Future[A] = {
// We define this outside the scope of the following
// Promise to guarantee that it is not captured by any
// closures.
val promiseRef = new AtomicReference[Promise[A]]
val monitor = Monitor.mk { case exc =>
promiseRef.getAndSet(null) match {
case null => false
case p =>
p.raise(exc)
p.setException(exc)
true
}
}
val p = new Promise[A]
promiseRef.set(p)
monitor {
val f = mkFuture
p.forwardInterruptsTo(f)
f respond { r =>
promiseRef.getAndSet(null) match {
case null => ()
case p => p.update(r)
}
}
}
p
}
/**
* Flattens a nested future. Same as ffa.flatten, but easier to call from Java.
*/
def flatten[A](ffa: Future[Future[A]]): Future[A] = ffa.flatten
/**
* Take a sequence of Futures, wait till they all complete
* successfully. The future fails immediately if any of the joined
* Futures do, mimicking the semantics of exceptions.
*
* @param fs a sequence of Futures
* @return a Future[Unit] whose value is populated when all of the fs return.
*/
def join[A](fs: Seq[Future[A]]): Future[Unit] = {
if (fs.isEmpty) Unit else {
val count = new AtomicInteger(fs.size)
val p = Promise.interrupts[Unit](fs:_*)
for (f <- fs) {
f respond {
case Return(_) =>
if (count.decrementAndGet() == 0)
p.update(Return.Unit)
case Throw(cause) =>
p.updateIfEmpty(Throw(cause))
}
}
p
}
}
/* The following joins are generated with this code:
scala -e '
val meths = for (end <- ''b'' to ''v''; ps = ''a'' to end) yield
"""/**
* Join %d futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[%s](%s): Future[(%s)] = join(Seq(%s)) map { _ => (%s) }""".format(
ps.size,
ps map (_.toUpper) mkString ",",
ps map(p => "%c: Future[%c]".format(p, p.toUpper)) mkString ",",
ps map (_.toUpper) mkString ",",
ps mkString ",",
ps map(p => "Await.result("+p+")") mkString ","
)
meths foreach println
'
*/
/**
* Join 2 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B](a: Future[A],b: Future[B]): Future[(A,B)] = join(Seq(a,b)) map { _ => (Await.result(a),Await.result(b)) }
/**
* Join 3 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C](a: Future[A],b: Future[B],c: Future[C]): Future[(A,B,C)] = join(Seq(a,b,c)) map { _ => (Await.result(a),Await.result(b),Await.result(c)) }
/**
* Join 4 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D](a: Future[A],b: Future[B],c: Future[C],d: Future[D]): Future[(A,B,C,D)] = join(Seq(a,b,c,d)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d)) }
/**
* Join 5 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E]): Future[(A,B,C,D,E)] = join(Seq(a,b,c,d,e)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e)) }
/**
* Join 6 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F]): Future[(A,B,C,D,E,F)] = join(Seq(a,b,c,d,e,f)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f)) }
/**
* Join 7 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G]): Future[(A,B,C,D,E,F,G)] = join(Seq(a,b,c,d,e,f,g)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g)) }
/**
* Join 8 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H]): Future[(A,B,C,D,E,F,G,H)] = join(Seq(a,b,c,d,e,f,g,h)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h)) }
/**
* Join 9 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I]): Future[(A,B,C,D,E,F,G,H,I)] = join(Seq(a,b,c,d,e,f,g,h,i)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i)) }
/**
* Join 10 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J]): Future[(A,B,C,D,E,F,G,H,I,J)] = join(Seq(a,b,c,d,e,f,g,h,i,j)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j)) }
/**
* Join 11 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K]): Future[(A,B,C,D,E,F,G,H,I,J,K)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k)) }
/**
* Join 12 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L]): Future[(A,B,C,D,E,F,G,H,I,J,K,L)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l)) }
/**
* Join 13 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L,M](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L],m: Future[M]): Future[(A,B,C,D,E,F,G,H,I,J,K,L,M)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l,m)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l),Await.result(m)) }
/**
* Join 14 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L,M,N](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L],m: Future[M],n: Future[N]): Future[(A,B,C,D,E,F,G,H,I,J,K,L,M,N)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l,m,n)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l),Await.result(m),Await.result(n)) }
/**
* Join 15 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L],m: Future[M],n: Future[N],o: Future[O]): Future[(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l),Await.result(m),Await.result(n),Await.result(o)) }
/**
* Join 16 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L],m: Future[M],n: Future[N],o: Future[O],p: Future[P]): Future[(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l),Await.result(m),Await.result(n),Await.result(o),Await.result(p)) }
/**
* Join 17 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L],m: Future[M],n: Future[N],o: Future[O],p: Future[P],q: Future[Q]): Future[(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l),Await.result(m),Await.result(n),Await.result(o),Await.result(p),Await.result(q)) }
/**
* Join 18 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L],m: Future[M],n: Future[N],o: Future[O],p: Future[P],q: Future[Q],r: Future[R]): Future[(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l),Await.result(m),Await.result(n),Await.result(o),Await.result(p),Await.result(q),Await.result(r)) }
/**
* Join 19 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L],m: Future[M],n: Future[N],o: Future[O],p: Future[P],q: Future[Q],r: Future[R],s: Future[S]): Future[(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l),Await.result(m),Await.result(n),Await.result(o),Await.result(p),Await.result(q),Await.result(r),Await.result(s)) }
/**
* Join 20 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L],m: Future[M],n: Future[N],o: Future[O],p: Future[P],q: Future[Q],r: Future[R],s: Future[S],t: Future[T]): Future[(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l),Await.result(m),Await.result(n),Await.result(o),Await.result(p),Await.result(q),Await.result(r),Await.result(s),Await.result(t)) }
/**
* Join 21 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L],m: Future[M],n: Future[N],o: Future[O],p: Future[P],q: Future[Q],r: Future[R],s: Future[S],t: Future[T],u: Future[U]): Future[(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l),Await.result(m),Await.result(n),Await.result(o),Await.result(p),Await.result(q),Await.result(r),Await.result(s),Await.result(t),Await.result(u)) }
/**
* Join 22 futures. The returned future is complete when all
* underlying futures complete. It fails immediately if any of them
* do.
*/
def join[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V](a: Future[A],b: Future[B],c: Future[C],d: Future[D],e: Future[E],f: Future[F],g: Future[G],h: Future[H],i: Future[I],j: Future[J],k: Future[K],l: Future[L],m: Future[M],n: Future[N],o: Future[O],p: Future[P],q: Future[Q],r: Future[R],s: Future[S],t: Future[T],u: Future[U],v: Future[V]): Future[(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V)] = join(Seq(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v)) map { _ => (Await.result(a),Await.result(b),Await.result(c),Await.result(d),Await.result(e),Await.result(f),Await.result(g),Await.result(h),Await.result(i),Await.result(j),Await.result(k),Await.result(l),Await.result(m),Await.result(n),Await.result(o),Await.result(p),Await.result(q),Await.result(r),Await.result(s),Await.result(t),Await.result(u),Await.result(v)) }
/**
* Take a sequence of Futures, wait till they all complete
* successfully. The future fails immediately if any of the joined
* Futures do, mimicking the semantics of exceptions.
*
* @param fs a java.util.List of Futures
* @return a Future[Unit] whose value is populated when all of the fs return.
*/
def join[A](fs: java.util.List[Future[A]]): Future[Unit] = join(asScalaBuffer(fs))
/**
* Collect the results from the given futures into a new future of
* Seq[A]. If one or of the given Futures is exceptional, the resulting
* Future result will be the first exception encountered.
*
* @param fs a sequence of Futures
* @return a Future[Seq[A]] containing the collected values from fs.
*/
def collect[A](fs: Seq[Future[A]]): Future[Seq[A]] = {
if (fs.isEmpty) {
Future(Seq[A]())
} else {
val fsSize = fs.size
val results = new AtomicReferenceArray[A](fsSize)
val count = new AtomicInteger(fsSize)
val p = Promise.interrupts[Seq[A]](fs:_*)
for ((f,i) <- fs.iterator.zipWithIndex) {
f respond {
case Return(x) =>
results.set(i, x)
if (count.decrementAndGet() == 0) {
val resultsArray = new mutable.ArraySeq[A](fsSize)
var j = 0
while (j < fsSize) {
resultsArray(j) = results.get(j)
j += 1
}
p.setValue(resultsArray)
}
case Throw(cause) =>
p.updateIfEmpty(Throw(cause))
}
}
p
}
}
/**
* Collect the results from the given futures into a new future of
* Seq[A]. If one or of the given futures is exceptional, the resulting
* future result will be the first exception encountered.
*
* @param fs a java.util.List of Futures
* @return a Future[java.util.List[A]] containing the collected values from fs.
*/
def collect[A](fs: java.util.List[Future[A]]): Future[java.util.List[A]] =
collect(asScalaBuffer(fs)) map(seqAsJavaList(_))
/**
* Collect the results from the given futures into a new future of Seq[Try[A]]
*
* @param fs a sequence of Futures
* @return a Future[Seq[Try[A]]] containing the collected values from fs.
*/
def collectToTry[A](fs: Seq[Future[A]]): Future[Seq[Try[A]]] =
Future.collect(fs map(_.liftToTry))
/**
* Collect the results from the given futures into a new future of Seq[Try[A]]
*
* @param fs a java.util.List of Futures
* @return a Future[java.util.List[Try[A]]] containing the collected values from fs.
*/
def collectToTry[A](fs: java.util.List[Future[A]]): Future[java.util.List[Try[A]]] =
collectToTry(asScalaBuffer(fs)) map(seqAsJavaList(_))
/**
* "Select" off the first future to be satisfied. Return this as a
* result, with the remainder of the Futures as a sequence.
*
* @param fs a scala.collection.Seq
*/
def select[A](fs: Seq[Future[A]]): Future[(Try[A], Seq[Future[A]])] = {
if (fs.isEmpty) {
Future.exception(new IllegalArgumentException("empty future list!"))
} else {
val p = Promise.interrupts[(Try[A], Seq[Future[A]])](fs:_*)
fs foreach { f =>
f respond { res =>
if (!p.isDefined) {
val others = fs filterNot { _ eq f }
p.updateIfEmpty(Return((res, others)))
}
}
}
p
}
}
/**
* Select the index into `fs` of the first future to be satisfied.
*
* @param fs cannot be empty
*/
def selectIndex[A](fs: IndexedSeq[Future[A]]): Future[Int] = {
if (fs.isEmpty) {
Future.exception(new IllegalArgumentException("empty future list"))
} else {
val p = Promise.interrupts[Int](fs:_*)
var i = 0
while (i < fs.size) {
val ii = i
fs(i) respond { res =>
if (!p.isDefined)
p.updateIfEmpty(Return(ii))
}
i += 1
}
p
}
}
/**
* "Select" off the first future to be satisfied. Return this as a
* result, with the remainder of the Futures as a sequence.
*
* @param fs a java.util.List
* @return a Future[Tuple2[Try[A], java.util.List[Future[A]]]] representing the first future
* to be satisfied and the rest of the futures.
*/
def select[A](fs: java.util.List[Future[A]]): Future[(Try[A], java.util.List[Future[A]])] = {
select(asScalaBuffer(fs)) map { case (first, rest) =>
(first, seqAsJavaList(rest))
}
}
/**
* Repeat a computation that returns a Future some number of times, after each
* computation completes.
*/
def times[A](n: Int)(f: => Future[A]): Future[Unit] = {
val count = new AtomicInteger(0)
whileDo(count.getAndIncrement() < n)(f)
}
/**
* Perform the effects of the supplied Future only when the provided
* flag is true.
*/
def when[A](p: Boolean)(f: => Future[A]): Future[Unit] =
if (p) f.unit else Future.Unit
/**
* Repeat a computation that returns a Future while some predicate obtains,
* after each computation completes.
*/
def whileDo[A](p: => Boolean)(f: => Future[A]): Future[Unit] = {
def loop(): Future[Unit] = {
if (p) f flatMap { _ => loop() }
else Future.Unit
}
loop()
}
def parallel[A](n: Int)(f: => Future[A]): Seq[Future[A]] = {
(0 until n) map { i => f }
}
/**
* Creates a "batched" Future that, given a function
* `Seq[In] => Future[Seq[Out]]`, returns a `In => Future[Out]` interface
* that batches the underlying asynchronous operations. Thus, one can
* incrementally submit tasks to be performed when the criteria for batch
* flushing is met.
*
* Example:
*
* val timer = new JavaTimer(true)
* def processBatch(reqs: Seq[Request]): Future[Seq[Response]]
* val batcher = Future.batched(sizeThreshold = 10) {
* processBatch
* }
* val response: Future[Response] = batcher(new Request)
*
* `batcher` will wait until 10 requests have been submitted, then delegate
* to the `processBatch` method to compute the responses.
*
* Batchers can be constructed with both size- or time-based thresholds:
*
* val batcher = Future.batched(sizeThreshold = 10, timeThreshold = 10.milliseconds) {
* ...
* }
*
* A batcher's size can be controlled at runtime with the `sizePercentile`
* function argument. This function returns a float between 0.0 and 1.0,
* representing the fractional size of the `sizeThreshold` that should be
* used for the next batch to be collected.
*/
def batched[In, Out](
sizeThreshold: Int,
timeThreshold: Duration = Duration.Top,
sizePercentile: => Float = 1.0f
)(
f: Seq[In] => Future[Seq[Out]]
)(
implicit timer: Timer
): In => Future[Out] = {
new BatchExecutor[In, Out](sizeThreshold, timeThreshold, sizePercentile, f)
}
}
class FutureCancelledException
extends Exception("The future was cancelled with Future.cancel")
/**
* An alternative interface for handling Future Events. This
* interface is designed to be friendly to Java users since it does
* not require creating many small Function objects.
*/
trait FutureEventListener[T] {
/**
* Invoked if the computation completes successfully
*/
def onSuccess(value: T): Unit
/**
* Invoked if the computation completes unsuccessfully
*/
def onFailure(cause: Throwable): Unit
}
/**
* An alternative interface for performing Future transformations;
* that is, converting a Future[A] to a Future[B]. This interface is
* designed to be friendly to Java users since it does not require
* creating many small Function objects. It is used in conjunction
* with `transformedBy`.
*
* You must override one of `{map, flatMap}`. If you override both
* `map` and `flatMap`, `flatMap` takes precedence. If you fail to
* override one of `{map, flatMap}`, an `AbstractMethodError` will be
* thrown at Runtime.
*
* '''Note:''' an exception e thrown in any of
* map/flatMap/handle/rescue will make the result of transformedBy be
* equivalent to Future.exception(e).
*/
abstract class FutureTransformer[-A, +B] {
/**
* Invoked if the computation completes successfully. Returns the
* new transformed value in a Future.
*/
def flatMap(value: A): Future[B] = Future.value(map(value))
/**
* Invoked if the computation completes successfully. Returns the
* new transformed value.
*
* ''Note'': this method will throw an `AbstractMethodError` if it is not overridden.
*/
def map(value: A): B = throw new AbstractMethodError
/**
* Invoked if the computation completes unsuccessfully. Returns the
* new Future value.
*/
def rescue(throwable: Throwable): Future[B] = Future.value(handle(throwable))
/**
* Invoked if the computation fails. Returns the new transformed
* value.
*/
def handle(throwable: Throwable): B = throw throwable
}
/**
* A computation evaluated asynchronously. This implementation of
* Future does not assume any concrete implementation; in particular,
* it does not couple the user to a specific executor or event loop.
*
* Futures are also [[com.twitter.util.Cancellable]], but with
* special semantics: the cancellation signal is only guaranteed to
* be delivered when the promise has not yet completed.
*/
abstract class Future[+A] extends Awaitable[A] {
import com.twitter.util.Future.DEFAULT_TIMEOUT
/**
* When the computation completes, invoke the given callback
* function. Respond() yields a Try (either a Return or a Throw).
* This method is most useful for very generic code (like
* libraries). Otherwise, it is a best practice to use one of the
* alternatives (onSuccess(), onFailure(), etc.). Note that almost
* all methods on Future[_] are written in terms of respond(), so
* this is the essential template method for use in concrete
* subclasses.
*
* @return a chained Future[A]
*/
def respond(k: Try[A] => Unit): Future[A]
/**
* Invoked regardless of whether the computation completed successfully or unsuccessfully.
* Implemented in terms of `respond` so that subclasses control evaluation order. Returns a
* chained Future.
*/
def ensure(f: => Unit): Future[A] = respond { _ => f }
/**
* Block indefinitely, wait for the result of the Future to be available.
*/
@deprecated("Use Await.result", "6.2.x")
def apply(): A = apply(DEFAULT_TIMEOUT)
/**
* Block, but only as long as the given Timeout.
*/
@deprecated("Use Await.result", "6.2.x")
def apply(timeout: Duration): A = get(timeout)()
/**
* Alias for apply().
*/
@deprecated("Use Await.result", "6.2.x")
def get() = apply()
@deprecated("Use Await.result", "6.2.x")
def isReturn = get(DEFAULT_TIMEOUT) isReturn
@deprecated("Use Await.result", "6.2.x")
def isThrow = get(DEFAULT_TIMEOUT) isThrow
/**
* Is the result of the Future available yet?
*/
def isDefined: Boolean = poll.isDefined
/**
* Checks whether a Unit-typed Future is done. By
* convention, futures of type Future[Unit] are used
* for signalling.
*/
def isDone(implicit ev: this.type <:< Future[Unit]) =
ev(this).poll == Some(Return.Unit)
/**
* Demands that the result of the future be available within
* `timeout`. The result is a Return[_] or Throw[_] depending upon
* whether the computation finished in time.
*/
@deprecated("Use Await.result", "6.2.x")
final def get(timeout: Duration): Try[A] =
try {
Return(Await.result(this, timeout))
} catch {
// For legacy reasons, we catch even
// fatal exceptions.
case e: Throwable => Throw(e)
}
/**
* Polls for an available result. If the Future has been
* satisfied, returns Some(result), otherwise None.
*/
def poll: Option[Try[A]]
/**
* Raise the given throwable as an interrupt. Interrupts are
* one-shot and latest-interrupt wins. That is, the last interrupt
* to have been raised is delivered exactly once to the Promise
* responsible for making progress on the future (multiple such
* promises may be involved in `flatMap` chains).
*
* Raising an interrupt does not alter the externally observable
* state of the Future. They are used to signal to the ''producer''
* of the future's value that the result is no longer desired (for
* whatever reason given in the passed Throwable).
*/
def raise(interrupt: Throwable)
@deprecated("Provided for API compatibility; use raise() instead.", "6.0.0")
def cancel() { raise(new FutureCancelledException) }
/**
* Same as the other raiseWithin, but with an implicit timer. Sometimes this is more convenient.
*
* ''Note'': On timeout, the underlying future is interrupted.
*/
def raiseWithin(timeout: Duration)(implicit timer: Timer): Future[A] =
raiseWithin(timer, timeout, new TimeoutException(timeout.toString))
/**
* Same as the other raiseWithin, but with an implicit timer. Sometimes this is more convenient.
*
* ''Note'': On timeout, the underlying future is interrupted.
*/
def raiseWithin(timeout: Duration, exc: Throwable)(implicit timer: Timer): Future[A] =
raiseWithin(timer, timeout, exc)
/**
* Returns a new Future that will error if this Future does not return in time.
*
* ''Note'': On timeout, the underlying future is interrupted.
*/
def raiseWithin(timer: Timer, timeout: Duration, exc: Throwable): Future[A] = {
if (timeout == Duration.Top || isDefined)
return this
within(timer, timeout, Future.raiseException) rescue {
case e if e eq Future.raiseException =>
this.raise(exc)
Future.exception(exc)
}
}
/**
* Same as the other within, but with an implicit timer. Sometimes this is more convenient.
*
* ''Note'': On timeout, the underlying future is not interrupted.
*/
def within(timeout: Duration)(implicit timer: Timer): Future[A] =
within(timer, timeout)
/**
* Returns a new Future that will error if this Future does not return in time.
*
* ''Note'': On timeout, the underlying future is not interrupted.
*/
def within(timer: Timer, timeout: Duration): Future[A] =
within(timer, timeout, new TimeoutException(timeout.toString))
/**
* Returns a new Future that will error if this Future does not return in time.
*
* ''Note'': On timeout, the underlying future is not interrupted.
*
* @param timer to run timeout on.
* @param timeout indicates how long you are willing to wait for the result to be available.
* @param exc exception to throw.
*/
def within(timer: Timer, timeout: Duration, exc: => Throwable): Future[A] = {
if (timeout == Duration.Top || isDefined)
return this
val p = Promise.interrupts[A](this)
val task = timer.schedule(timeout.fromNow) {
p.updateIfEmpty(Throw(exc))
}
respond { r =>
task.cancel()
p.updateIfEmpty(r)
}
p
}
/**
* Delay the completion of this Future for at least
* `howlong` from now.
*/
def delayed(howlong: Duration)(implicit timer: Timer): Future[A] = {
if (howlong == Duration.Zero)
return this
val p = Promise.interrupts[A](this)
timer.schedule(howlong.fromNow) { p.become(this) }
p
}
def transform[B](f: Try[A] => Future[B]): Future[B]
/**
* If this, the original future, succeeds, run f on the result.
*
* The returned result is a Future that is satisfied when the original future
* and the callback, f, are done.
* If the original future fails, this one will also fail, without executing f.
*
* @see map()
*/
def flatMap[B](f: A => Future[B]): Future[B] =
transform({
case Return(v) => f(v)
case Throw(t) => Future.rawException(t)
})
/**
* Sequentially compose `this` with `f`. This is as `flatMap`, but
* discards the result of `this`. Note that this applies only
* `Unit`-valued Futures -- i.e. side-effects..
*/
def before[B](f: => Future[B])(implicit ev: this.type <:< Future[Unit]): Future[B] =
transform({
case Return(_) => f
case Throw(t) => Future.rawException(t)
})
def rescue[B >: A](
rescueException: PartialFunction[Throwable, Future[B]]
): Future[B] = transform({
case Throw(t) if rescueException.isDefinedAt(t) => rescueException(t)
case _ => this
})
/**
* Invoke the callback only if the Future returns successfully. Useful for Scala `for`
* comprehensions. Use `onSuccess` instead of this method for more readable code.
*/
def foreach(k: A => Unit) = onSuccess(k)
/**
* If this, the original future, succeeds, run f on the result.
*
* The returned result is a Future that is satisfied when the original future
* and the callback, f, are done.
* If the original future fails, this one will also fail, without executing f.
*
* @see flatMap()
*/
def map[B](f: A => B): Future[B] = flatMap { a => Future { f(a) } }
def filter(p: A => Boolean): Future[A] = transform { x: Try[A] => Future.const(x.filter(p)) }
def withFilter(p: A => Boolean): Future[A] = filter(p)
/**
* Invoke the function on the result, if the computation was
* successful. Returns a chained Future as in `respond`.
*
* @return chained Future
*/
def onSuccess(f: A => Unit): Future[A] =
respond({
case Return(value) => f(value)
case _ =>
})
/**
* Invoke the function on the error, if the computation was
* unsuccessful. Returns a chained Future as in `respond`.
*
* @return chained Future
*/
def onFailure(rescueException: Throwable => Unit): Future[A] =
respond({
case Throw(throwable) => rescueException(throwable)
case _ =>
})
/**
* Register a FutureEventListener to be invoked when the
* computation completes. This method is typically used by Java
* programs because it avoids the use of small Function objects.
*
* Compare this method to `transformedBy`. The difference is that
* `addEventListener` is used to perform a simple action when a
* computation completes, such as recording data in a log-file. It
* analogous to a `void` method in Java: it has side-effects and no
* return value. `transformedBy`, on the other hand, is used to
* transform values from one type to another, or to chain a series
* of asynchronous calls and return the result. It is analogous to
* methods in Java that have a return-type. Note that
* `transformedBy` and `addEventListener` are not mutually
* exclusive and may be profitably combined.
*/
def addEventListener(listener: FutureEventListener[_ >: A]) = respond({
case Throw(cause) => listener.onFailure(cause)
case Return(value) => listener.onSuccess(value)
})
/**
* Transform the Future[A] into a Future[B] using the
* FutureTransformer. The FutureTransformer handles both success
* (Return) and failure (Throw) values by implementing map/flatMap
* and handle/rescue. This method is typically used by Java
* programs because it avoids the use of small Function objects.
*
* Compare this method to `addEventListener`. The difference is
* that `addEventListener` is used to perform a simple action when
* a computation completes, such as recording data in a log-file.
* It analogous to a `void` method in Java: it has side-effects and
* no return value. `transformedBy`, on the other hand, is used to
* transform values from one type to another, or to chain a series
* of asynchronous calls and return the result. It is analogous to
* methods in Java that have a return-type. Note that
* `transformedBy` and `addEventListener` are not mutually
* exclusive and may be profitably combined.
*
* ''Note'': The FutureTransformer must implement either `flatMap`
* or `map` and may optionally implement `handle`. Failing to
* implement a method will result in a run-time (AbstractMethod)
* error.
*/
def transformedBy[B](transformer: FutureTransformer[A, B]): Future[B] =
transform {
case Return(v) => transformer.flatMap(v)
case Throw(t) => transformer.rescue(t)
}
def handle[B >: A](rescueException: PartialFunction[Throwable, B]): Future[B] = rescue {
case e: Throwable if rescueException.isDefinedAt(e) => Future(rescueException(e))
case e: Throwable => this
}
/**
* Choose the first Future to be satisfied.
*
* @param other another Future
* @return a new Future whose result is that of the first of this and other to return
*/
def select[U >: A](other: Future[U]): Future[U] = {
val p = Promise.interrupts[U](other, this)
other respond { p.updateIfEmpty(_) }
this respond { p.updateIfEmpty(_) }
p
}
/**
* A synonym for select(): Choose the first Future to be satisfied.
*/
def or[U >: A](other: Future[U]): Future[U] = select(other)
/**
* Combines two Futures into one Future of the Tuple of the two results.
*/
def join[B](other: Future[B]): Future[(A, B)] = {
val p = Promise.interrupts[(A, B)](this, other)
this.respond {
case Throw(t) => p() = Throw(t)
case Return(a) => other respond {
case Throw(t) => p() = Throw(t)
case Return(b) => p() = Return((a, b))
}
}
p
}
/**
* Convert this Future[A] to a Future[Unit] by discarding the result.
*/
def unit: Future[Unit] = flatMap(Future.toUnit)
/**
* Convert this Future[A] to a Future[Void] by discarding the result.
*/
def voided: Future[Void] = flatMap(Future.toVoid)
@deprecated("'void' is a reserved word in javac.", "5.x")
def void: Future[Void] = voided
/**
* Send updates from this Future to the other.
* ``other'' must not yet be satisfied.
*/
def proxyTo[B >: A](other: Promise[B]) {
respond { other() = _ }
}
/**
* An offer for this future. The offer is activated when the future
* is satisfied.
*/
def toOffer: Offer[Try[A]] = new Offer[Try[A]] {
def prepare() = transform { res: Try[A] =>
val tx = new Tx[Try[A]] {
def ack() = Future.value(Tx.Commit(res))
def nack() {}
}
Future.value(tx)
}
}
/**
* Convert a Twitter Future to a Java native Future. This should
* match the semantics of a Java Future as closely as possible to
* avoid issues with the way another API might use them. See:
*
* http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html#cancel(boolean)
*/
def toJavaFuture: JavaFuture[_ <: A] = {
val f = this
new JavaFuture[A] {
val wasCancelled = new AtomicBoolean(false)
override def cancel(mayInterruptIfRunning: Boolean): Boolean = {
if (wasCancelled.compareAndSet(false, true))
f.raise(new CancellationException)
true
}
override def isCancelled: Boolean = wasCancelled.get
override def isDone: Boolean = isCancelled || f.isDefined
override def get(): A = {
if (isCancelled)
throw new CancellationException
Await.result(f)
}
override def get(time: Long, timeUnit: TimeUnit): A = {
if (isCancelled)
throw new CancellationException
Await.result(f, Duration.fromTimeUnit(time, timeUnit))
}
}
}
/**
* Converts a Future[Future[B]] into a Future[B]
*/
def flatten[B](implicit ev: A <:< Future[B]): Future[B] =
flatMap[B] { x => x }
/**
* Returns an identical future except that it ignores interrupts which match a predicate
*/
def mask(pred: PartialFunction[Throwable, Boolean]): Future[A] = {
val p = Promise[A]()
p.setInterruptHandler {
case t if !PartialFunction.cond(t)(pred) => this.raise(t)
}
this.proxyTo(p)
p
}
/**
* Returns an identical future that ignores all interrupts
*/
def masked: Future[A] = mask {
case _ => true
}
/**
* Returns a Future[Boolean] indicating whether two Futures are equivalent. Note that
* Future.exception(e).willEqual(Future.exception(e)) == Future.value(true).
*/
def willEqual[B](that: Future[B]) = {
val areEqual = new Promise[Boolean]
this respond { thisResult =>
that respond { thatResult =>
areEqual.setValue(thisResult == thatResult)
}
}
areEqual
}
/**
* Returns the result of the computation as a Future[Try[A]].
*/
def liftToTry: Future[Try[A]] = transform(Future.value)
}
/**
* A Future that is already completed. These are cheap in
* construction compared to Promises.
*/
class ConstFuture[A](result: Try[A]) extends Future[A] {
def respond(k: Try[A] => Unit): Future[A] = {
val saved = Local.save()
Scheduler.submit(new Runnable {
def run() {
val current = Local.save()
Local.restore(saved)
try Monitor { k(result) } finally Local.restore(current)
}
})
this
}
def raise(interrupt: Throwable) {}
def transform[B](f: Try[A] => Future[B]): Future[B] = {
val p = new Promise[B]
respond({ r =>
val result = try f(r) catch {
case e: NonLocalReturnControl[_] => Future.exception(new FutureNonLocalReturnControl(e))
case NonFatal(e) => Future.exception(e)
}
p.become(result)
})
p
}
def poll: Option[Try[A]] = Some(result)
override def isDefined = true
// Awaitable
@throws(classOf[TimeoutException])
@throws(classOf[InterruptedException])
def ready(timeout: Duration)(implicit permit: Awaitable.CanAwait): this.type = this
@throws(classOf[Exception])
def result(timeout: Duration)(implicit permit: Awaitable.CanAwait): A = result()
def isReady(implicit permit: Awaitable.CanAwait) = true
}
/**
* A future with no future (never completes).
*/
class NoFuture extends Future[Nothing] {
def respond(k: Try[Nothing] => Unit): Future[Nothing] = this
def transform[B](f: Try[Nothing] => Future[B]): Future[B] = this
def raise(interrupt: Throwable) {}
// Awaitable
@throws(classOf[TimeoutException])
@throws(classOf[InterruptedException])
def ready(timeout: Duration)(implicit permit: Awaitable.CanAwait): this.type = {
Thread.sleep(timeout.inMilliseconds)
throw new TimeoutException(timeout.toString)
}
@throws(classOf[Exception])
def result(timeout: Duration)(implicit permit: Awaitable.CanAwait): Nothing = {
Thread.sleep(timeout.inMilliseconds)
throw new TimeoutException(timeout.toString)
}
def poll: Option[Try[Nothing]] = None
def isReady(implicit permit: Awaitable.CanAwait) = false
}
class FutureTask[A](fn: => A) extends Promise[A] with Runnable {
def run() {
update(Try(fn))
}
}
object FutureTask {
def apply[A](fn: => A) = new FutureTask[A](fn)
}
private[util] object FutureBenchmark {
/**
* Admittedly, this is not very good microbenchmarking technique.
*/
import com.twitter.conversions.storage._
private[this] val NumIters = 100.million
private[this] def bench[A](numIters: Long)(f: => A): Long = {
val begin = System.currentTimeMillis()
(0L until numIters) foreach { _ => f }
System.currentTimeMillis() - begin
}
private[this] def run[A](name: String)(work: => A) {
printf("Warming up %s.. ", name)
val warmupTime = bench(NumIters)(work)
printf("%d ms\n", warmupTime)
printf("Running .. ")
val runTime = bench(NumIters)(work)
printf(
"%d ms, %d %s/sec\n",
runTime, 1000 * NumIters / runTime, name)
}
def main(args: Array[String]) {
run("respond") {
val promise = new Promise[Unit]
promise respond { res => () }
promise() = Return.Unit
}
run("flatMaps") {
val promise = new Promise[Unit]
promise flatMap { _ => Future.value(()) }
promise() = Return.Unit
}
}
}
private[util] object Leaky {
def main(args: Array[String]) {
def loop(i: Int): Future[Int] = Future.value(i) flatMap { count =>
if (count % 1000000 == 0) {
System.gc()
println("iter %d %dMB".format(
count, Runtime.getRuntime().totalMemory()>>20))
}
loop(count + 1)
}
loop(1)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy