blob: c8ab2a7cd9e3b3d398c311b38cc46313d72fe413 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.slider.server.appmaster.state;
/**
* Information about the state of a role on a specific node instance.
* No fields are synchronized; sync on the instance to work with it
*
The two fields `releasing` and `requested` are used to track the ongoing
state of YARN requests; they do not need to be persisted across freeze/thaw
cycles. They may be relevant across AM restart, but without other data
structures in the AM, not enough to track what the AM was up to before
it was restarted. The strategy will be to ignore unexpected allocation
responses (which may come from pre-restart) requests, while treating
unexpected container release responses as failures.
The `active` counter is only decremented after a container release response
has been received.
Accesses are synchronized.
*/
public class NodeEntry {
public final int index;
public NodeEntry(int index) {
this.index = index;
}
/**
* instance explicitly requested on this node: it's OK if an allocation
* comes in that has not been (and when that happens, this count should
* not drop)
*/
private int requested;
private int starting;
private int startFailed;
private int failed;
/**
* Number of live nodes.
*/
private int live;
private int releasing;
private long lastUsed;
/**
* Is the node available for assignments. This does not track
* whether or not there are any outstanding requests for this node
* @return true if there are no role instances here
* other than some being released.
*/
public synchronized boolean isAvailable() {
return getActive() == 0 && (requested == 0) && starting == 0;
}
/**
* return no of active instances -those that could be released as they
* are live and not already being released
* @return a number, possibly 0
*/
public synchronized int getActive() {
return (live - releasing);
}
/**
* Return true if the node is not busy, and it
* has not been used since the absolute time
* @param absoluteTime time
* @return true if the node could be cleaned up
*/
public synchronized boolean notUsedSince(long absoluteTime) {
return isAvailable() && lastUsed < absoluteTime;
}
public synchronized int getLive() {
return live;
}
public int getStarting() {
return starting;
}
/**
* Set the live value directly -used on AM restart
* @param v value
*/
public synchronized void setLive(int v) {
live = v;
}
private void incLive() {
++live;
}
private synchronized void decLive() {
live = RoleHistoryUtils.decToFloor(live);
}
public synchronized void onStarting() {
++starting;
}
private void decStarting() {
starting = RoleHistoryUtils.decToFloor(starting);
}
public synchronized void onStartCompleted() {
decStarting();
incLive();
}
/**
* start failed -decrement the starting flag.
* @return true if the node is now available
*/
public synchronized boolean onStartFailed() {
decStarting();
++startFailed;
++failed;
return isAvailable();
}
/**
* no of requests made of this role of this node. If it goes above
* 1 there's a problem
*/
public synchronized int getRequested() {
return requested;
}
/**
* request a node:
*/
public synchronized void request() {
++requested;
}
/**
* A request made explicitly to this node has completed
*/
public synchronized void requestCompleted() {
requested = RoleHistoryUtils.decToFloor(requested);
}
/**
* No of instances in release state
*/
public synchronized int getReleasing() {
return releasing;
}
/**
* Release an instance -which is no longer marked as active
*/
public synchronized void release() {
releasing++;
}
/**
* completion event, which can be a planned or unplanned
* planned: dec our release count
* unplanned: dec our live count
* @param wasReleased true if this was planned
* @return true if this node is now available
*/
public synchronized boolean containerCompleted(boolean wasReleased) {
if (wasReleased) {
releasing = RoleHistoryUtils.decToFloor(releasing);
} else {
++failed;
}
decLive();
return isAvailable();
}
/**
* Time last used.
*/
public synchronized long getLastUsed() {
return lastUsed;
}
public synchronized void setLastUsed(long lastUsed) {
this.lastUsed = lastUsed;
}
public int getStartFailed() {
return startFailed;
}
public synchronized int getFailed() {
return failed;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("NodeEntry{");
sb.append("requested=").append(requested);
sb.append(", starting=").append(starting);
sb.append(", live=").append(live);
sb.append(", failed=").append(failed);
sb.append(", startFailed=").append(startFailed);
sb.append(", releasing=").append(releasing);
sb.append(", lastUsed=").append(lastUsed);
sb.append('}');
return sb.toString();
}
}