You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@mesos.apache.org by "Benjamin Mahler (JIRA)" <ji...@apache.org> on 2014/03/28 21:03:14 UTC

[jira] [Updated] (MESOS-1160) Support flattening from {Try,Result} into Future.

     [ https://issues.apache.org/jira/browse/MESOS-1160?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Benjamin Mahler updated MESOS-1160:
-----------------------------------

    Description: 
We should consider adding support for constructing a Future<T> from a Try<T>, the flattening is rather straightforward:
* Try is SOME, then Future is READY.
* Try is ERROR, then Future is FAILED.

Ideally we should consider consolidating terminology (Error vs. Failed / Failure) as well, but the flattening in itself is beneficial.

Consider the following code:

{code}
void Slave::checkDiskUsage()
{
  // TODO(vinod): We are making usage a Future, so that we can plug in
  // fs::usage() into async.
  Future<Try<double> >(fs::usage(flags.work_dir))
    .onAny(defer(self(), &Slave::_checkDiskUsage, lambda::_1));
}


void Slave::_checkDiskUsage(const Future<Try<double> >& usage)
{
  if (!usage.isReady()) {
    LOG(ERROR) << "Failed to get disk usage: "
               << (usage.isFailed() ? usage.failure() : "future discarded");
  } else {
    Try<double> result = usage.get();

    if (result.isSome()) {
      double use = result.get();

      LOG(INFO) << "Current usage " << std::setiosflags(std::ios::fixed)
                << std::setprecision(2) << 100 * use << "%."
                << " Max allowed age: " << age(use);

      // We prune all directories whose deletion time is within
      // the next 'gc_delay - age'. Since a directory is always
      // scheduled for deletion 'gc_delay' into the future, only directories
      // that are at least 'age' old are deleted.
      gc.prune(flags.gc_delay - age(use));
    } else {
      LOG(WARNING) << "Unable to get disk usage: " << result.error();
    }
  }
  delay(flags.disk_watch_interval, self(), &Slave::checkDiskUsage);
}
{code}

With flattening this code becomes:
{code}
void Slave::checkDiskUsage()
{
  // TODO(vinod): We are making usage a Future, so that we can plug in
  // fs::usage() into async.
  Future<double>(fs::usage(flags.work_dir))
    .onAny(defer(self(), &Slave::_checkDiskUsage, lambda::_1));
}


void Slave::_checkDiskUsage(const Future<double>& usage)
{
  if (!usage.isReady()) {
    LOG(WARNING) << "Failed to get disk usage: "
               << (usage.isFailed() ? usage.failure() : "future discarded");
  } else {
    LOG(INFO) << "Current usage " << std::setiosflags(std::ios::fixed)
              << std::setprecision(2) << 100 * usage.get() << "%."
              << " Max allowed age: " << age(usage.get());

    // We prune all directories whose deletion time is within
    // the next 'gc_delay - age'. Since a directory is always
    // scheduled for deletion 'gc_delay' into the future, only directories
    // that are at least 'age' old are deleted.
    gc.prune(flags.gc_delay - age(usage.get()));
  }
  delay(flags.disk_watch_interval, self(), &Slave::checkDiskUsage);
}
{code}

For Result, the conversion is a bit less clear but logically a Result<T> maps to a Future<Option<T> >:
* Result is SOME, then Future is READY and Option is SOME.
* Result is NONE, then Future is READY and Option is SOME.
* Result is ERROR, then Future is FAILED.

  was:
We should consider adding support for constructing a Future<T> from a Try<T>, the flattening is rather straightforward:
* Try is SOME, then Future is READY.
* Try is ERROR, then Future is FAILED.

Ideally we should consider consolidating terminology (Error vs. Failed / Failure) as well, but the flattening in itself is beneficial.

Consider the following code:

{code}
void Slave::checkDiskUsage()
{
  // TODO(vinod): We are making usage a Future, so that we can plug in
  // fs::usage() into async.
  Future<Try<double> >(fs::usage(flags.work_dir))
    .onAny(defer(self(), &Slave::_checkDiskUsage, lambda::_1));
}


void Slave::_checkDiskUsage(const Future<Try<double> >& usage)
{
  if (!usage.isReady()) {
    LOG(ERROR) << "Failed to get disk usage: "
               << (usage.isFailed() ? usage.failure() : "future discarded");
  } else {
    Try<double> result = usage.get();

    if (result.isSome()) {
      double use = result.get();

      LOG(INFO) << "Current usage " << std::setiosflags(std::ios::fixed)
                << std::setprecision(2) << 100 * use << "%."
                << " Max allowed age: " << age(use);

      // We prune all directories whose deletion time is within
      // the next 'gc_delay - age'. Since a directory is always
      // scheduled for deletion 'gc_delay' into the future, only directories
      // that are at least 'age' old are deleted.
      gc.prune(flags.gc_delay - age(use));
    } else {
      LOG(WARNING) << "Unable to get disk usage: " << result.error();
    }
  }
  delay(flags.disk_watch_interval, self(), &Slave::checkDiskUsage);
}
{code}

With flattening this code becomes:
{code}
void Slave::checkDiskUsage()
{
  // TODO(vinod): We are making usage a Future, so that we can plug in
  // fs::usage() into async.
  Future<double>(fs::usage(flags.work_dir))
    .onAny(defer(self(), &Slave::_checkDiskUsage, lambda::_1));
}


void Slave::_checkDiskUsage(const Future<double>& usage)
{
  if (!usage.isReady()) {
    LOG(WARNING) << "Failed to get disk usage: "
               << (usage.isFailed() ? usage.failure() : "future discarded");
  } else {
    LOG(INFO) << "Current usage " << std::setiosflags(std::ios::fixed)
              << std::setprecision(2) << 100 * usage.get() << "%."
              << " Max allowed age: " << age(usage.get());

    // We prune all directories whose deletion time is within
    // the next 'gc_delay - age'. Since a directory is always
    // scheduled for deletion 'gc_delay' into the future, only directories
    // that are at least 'age' old are deleted.
    gc.prune(flags.gc_delay - age(usage.get()));
  }
  delay(flags.disk_watch_interval, self(), &Slave::checkDiskUsage);
}
{code}


> Support flattening from {Try,Result} into Future.
> -------------------------------------------------
>
>                 Key: MESOS-1160
>                 URL: https://issues.apache.org/jira/browse/MESOS-1160
>             Project: Mesos
>          Issue Type: Improvement
>          Components: libprocess
>            Reporter: Benjamin Mahler
>              Labels: newbie
>
> We should consider adding support for constructing a Future<T> from a Try<T>, the flattening is rather straightforward:
> * Try is SOME, then Future is READY.
> * Try is ERROR, then Future is FAILED.
> Ideally we should consider consolidating terminology (Error vs. Failed / Failure) as well, but the flattening in itself is beneficial.
> Consider the following code:
> {code}
> void Slave::checkDiskUsage()
> {
>   // TODO(vinod): We are making usage a Future, so that we can plug in
>   // fs::usage() into async.
>   Future<Try<double> >(fs::usage(flags.work_dir))
>     .onAny(defer(self(), &Slave::_checkDiskUsage, lambda::_1));
> }
> void Slave::_checkDiskUsage(const Future<Try<double> >& usage)
> {
>   if (!usage.isReady()) {
>     LOG(ERROR) << "Failed to get disk usage: "
>                << (usage.isFailed() ? usage.failure() : "future discarded");
>   } else {
>     Try<double> result = usage.get();
>     if (result.isSome()) {
>       double use = result.get();
>       LOG(INFO) << "Current usage " << std::setiosflags(std::ios::fixed)
>                 << std::setprecision(2) << 100 * use << "%."
>                 << " Max allowed age: " << age(use);
>       // We prune all directories whose deletion time is within
>       // the next 'gc_delay - age'. Since a directory is always
>       // scheduled for deletion 'gc_delay' into the future, only directories
>       // that are at least 'age' old are deleted.
>       gc.prune(flags.gc_delay - age(use));
>     } else {
>       LOG(WARNING) << "Unable to get disk usage: " << result.error();
>     }
>   }
>   delay(flags.disk_watch_interval, self(), &Slave::checkDiskUsage);
> }
> {code}
> With flattening this code becomes:
> {code}
> void Slave::checkDiskUsage()
> {
>   // TODO(vinod): We are making usage a Future, so that we can plug in
>   // fs::usage() into async.
>   Future<double>(fs::usage(flags.work_dir))
>     .onAny(defer(self(), &Slave::_checkDiskUsage, lambda::_1));
> }
> void Slave::_checkDiskUsage(const Future<double>& usage)
> {
>   if (!usage.isReady()) {
>     LOG(WARNING) << "Failed to get disk usage: "
>                << (usage.isFailed() ? usage.failure() : "future discarded");
>   } else {
>     LOG(INFO) << "Current usage " << std::setiosflags(std::ios::fixed)
>               << std::setprecision(2) << 100 * usage.get() << "%."
>               << " Max allowed age: " << age(usage.get());
>     // We prune all directories whose deletion time is within
>     // the next 'gc_delay - age'. Since a directory is always
>     // scheduled for deletion 'gc_delay' into the future, only directories
>     // that are at least 'age' old are deleted.
>     gc.prune(flags.gc_delay - age(usage.get()));
>   }
>   delay(flags.disk_watch_interval, self(), &Slave::checkDiskUsage);
> }
> {code}
> For Result, the conversion is a bit less clear but logically a Result<T> maps to a Future<Option<T> >:
> * Result is SOME, then Future is READY and Option is SOME.
> * Result is NONE, then Future is READY and Option is SOME.
> * Result is ERROR, then Future is FAILED.



--
This message was sent by Atlassian JIRA
(v6.2#6252)