001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.reef.runtime.common.driver.resourcemanager;
020
021import org.apache.reef.annotations.audience.DriverSide;
022import org.apache.reef.annotations.audience.Private;
023import org.apache.reef.proto.ReefServiceProtos;
024import org.apache.reef.runtime.common.driver.DriverStatusManager;
025import org.apache.reef.runtime.common.driver.idle.DriverIdleManager;
026import org.apache.reef.runtime.common.driver.idle.DriverIdlenessSource;
027import org.apache.reef.runtime.common.driver.idle.IdleMessage;
028import org.apache.reef.tang.InjectionFuture;
029import org.apache.reef.wake.EventHandler;
030
031import javax.inject.Inject;
032import java.util.logging.Level;
033import java.util.logging.Logger;
034
035/**
036 * Manages the status of the Resource Manager.
037 */
038@DriverSide
039@Private
040public final class ResourceManagerStatus implements EventHandler<RuntimeStatusEvent>,
041    DriverIdlenessSource {
042  private static final Logger LOG = Logger.getLogger(ResourceManagerStatus.class.getName());
043
044  private static final String COMPONENT_NAME = "ResourceManager";
045  private static final IdleMessage IDLE_MESSAGE = new IdleMessage(COMPONENT_NAME, "No outstanding requests or allocations", true);
046
047  private final ResourceManagerErrorHandler resourceManagerErrorHandler;
048  private final DriverStatusManager driverStatusManager;
049  private final InjectionFuture<DriverIdleManager> driverIdleManager;
050
051  // Mutable state.
052  private ReefServiceProtos.State state = ReefServiceProtos.State.INIT;
053  private int outstandingContainerRequests = 0;
054  private int containerAllocationCount = 0;
055
056  @Inject
057  ResourceManagerStatus(final ResourceManagerErrorHandler resourceManagerErrorHandler,
058                        final DriverStatusManager driverStatusManager,
059                        final InjectionFuture<DriverIdleManager> driverIdleManager) {
060    this.resourceManagerErrorHandler = resourceManagerErrorHandler;
061    this.driverStatusManager = driverStatusManager;
062    this.driverIdleManager = driverIdleManager;
063  }
064
065  @Override
066  public synchronized void onNext(final RuntimeStatusEvent runtimeStatusEvent) {
067    final ReefServiceProtos.State newState = runtimeStatusEvent.getState();
068    LOG.log(Level.FINEST, "Runtime status " + runtimeStatusEvent);
069    this.outstandingContainerRequests = runtimeStatusEvent.getOutstandingContainerRequests().get();
070    this.containerAllocationCount = runtimeStatusEvent.getContainerAllocationList().size();
071    this.setState(runtimeStatusEvent.getState());
072
073    switch (newState) {
074      case FAILED:
075        this.onRMFailure(runtimeStatusEvent);
076        break;
077      case DONE:
078        this.onRMDone(runtimeStatusEvent);
079        break;
080      case RUNNING:
081        this.onRMRunning(runtimeStatusEvent);
082        break;
083    }
084  }
085
086  /**
087   * Change the state of the Resource Manager to be RUNNING.
088   */
089  public synchronized void setRunning() {
090    this.setState(ReefServiceProtos.State.RUNNING);
091  }
092
093  /**
094   * @return idle, if there are no outstanding requests or allocations. Not idle else.
095   */
096  @Override
097  public synchronized IdleMessage getIdleStatus() {
098    if (this.isIdle()) {
099      return IDLE_MESSAGE;
100    } else {
101      final String message = new StringBuilder("There are ")
102          .append(this.outstandingContainerRequests)
103          .append(" outstanding container requests and ")
104          .append(this.containerAllocationCount)
105          .append(" allocated containers")
106          .toString();
107      return new IdleMessage(COMPONENT_NAME, message, false);
108    }
109  }
110
111
112  private synchronized void onRMFailure(final RuntimeStatusEvent runtimeStatusEvent) {
113    assert (runtimeStatusEvent.getState() == ReefServiceProtos.State.FAILED);
114    this.resourceManagerErrorHandler.onNext(runtimeStatusEvent.getError().get());
115  }
116
117  private synchronized void onRMDone(final RuntimeStatusEvent runtimeStatusEvent) {
118    assert (runtimeStatusEvent.getState() == ReefServiceProtos.State.DONE);
119    LOG.log(Level.INFO, "Resource Manager shutdown happened. Triggering Driver shutdown.");
120    this.driverStatusManager.onComplete();
121  }
122
123  private synchronized void onRMRunning(final RuntimeStatusEvent runtimeStatusEvent) {
124    assert (runtimeStatusEvent.getState() == ReefServiceProtos.State.RUNNING);
125    if (this.isIdle()) {
126      this.driverIdleManager.get().onPotentiallyIdle(IDLE_MESSAGE);
127    }
128  }
129
130
131  private synchronized boolean isIdle() {
132    return this.hasNoOutstandingRequests()
133        && this.hasNoContainersAllocated();
134  }
135
136  private synchronized boolean isRunning() {
137    return ReefServiceProtos.State.RUNNING.equals(this.state);
138  }
139
140
141  private synchronized void setState(ReefServiceProtos.State state) {
142    // TODO: Add state transition check
143    this.state = state;
144  }
145
146
147  private synchronized boolean hasNoOutstandingRequests() {
148    return this.outstandingContainerRequests == 0;
149  }
150
151  private synchronized boolean hasNoContainersAllocated() {
152    return this.containerAllocationCount == 0;
153  }
154
155}