blob: e2974fcc307d3c8cee2b11b440b80112fb993a7e [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;
import org.apache.slider.api.types.ComponentInformation;
import org.apache.slider.providers.PlacementPolicy;
import org.apache.slider.providers.ProviderRole;
import java.io.Serializable;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/**
* Models the ongoing status of all nodes in
* Nothing here is synchronized: grab the whole instance to update.
*/
public final class RoleStatus implements Cloneable {
private final String name;
/**
* Role priority
*/
private final int key;
private final ProviderRole providerRole;
private int desired, actual, requested, releasing;
private int failed, startFailed;
private int started, completed, totalRequested;
private final AtomicLong preempted = new AtomicLong(0);
private final AtomicLong nodeFailed = new AtomicLong(0);
private final AtomicLong failedRecently = new AtomicLong(0);
private final AtomicLong limitsExceeded = new AtomicLong(0);
private String failureMessage = "";
public RoleStatus(ProviderRole providerRole) {
this.providerRole = providerRole;
this.name = providerRole.name;
this.key = providerRole.id;
}
public String getName() {
return name;
}
public int getKey() {
return key;
}
public int getPriority() {
return getKey();
}
/**
* Get the placement policy enum, from the values in
* {@link PlacementPolicy}
* @return the placement policy for this role
*/
public int getPlacementPolicy() {
return providerRole.placementPolicy;
}
public long getPlacementTimeoutSeconds() {
return providerRole.placementTimeoutSeconds;
}
/**
* The number of failures on a specific node that can be tolerated
* before selecting a different node for placement
* @return
*/
public int getNodeFailureThreshold() {
return providerRole.nodeFailureThreshold;
}
public boolean isExcludeFromFlexing() {
return hasPlacementPolicy(PlacementPolicy.EXCLUDE_FROM_FLEXING);
}
public boolean isStrictPlacement() {
return hasPlacementPolicy(PlacementPolicy.STRICT);
}
public boolean isAntiAffinePlacement() {
return hasPlacementPolicy(PlacementPolicy.ANTI_AFFINITY_REQUIRED);
}
public boolean hasPlacementPolicy(int policy) {
return 0 != (getPlacementPolicy() & policy);
}
public boolean isPlacementDesired() {
return !hasPlacementPolicy(PlacementPolicy.NO_DATA_LOCALITY);
}
public synchronized int getDesired() {
return desired;
}
public synchronized void setDesired(int desired) {
this.desired = desired;
}
public synchronized int getActual() {
return actual;
}
public synchronized int incActual() {
return ++actual;
}
public synchronized int decActual() {
actual = Math.max(0, actual - 1);
return actual;
}
public synchronized int getRequested() {
return requested;
}
public synchronized int incRequested() {
totalRequested++;
return ++requested;
}
public synchronized int cancel(int count) {
requested = Math.max(0, requested - count);
return requested;
}
public synchronized int decRequested() {
return cancel(1);
}
public synchronized int getReleasing() {
return releasing;
}
public synchronized int incReleasing() {
return ++releasing;
}
public synchronized int decReleasing() {
releasing = Math.max(0, releasing - 1);
return releasing;
}
public synchronized int getFailed() {
return failed;
}
public synchronized long getFailedRecently() {
return failedRecently.get();
}
/**
* Reset the recent failure
* @return the number of failures in the "recent" window
*/
public long resetFailedRecently() {
return failedRecently.getAndSet(0);
}
public long getLimitsExceeded() {
return limitsExceeded.get();
}
/**
* Note that a role failed, text will
* be used in any diagnostics if an exception
* is later raised.
* @param startupFailure flag to indicate this was a startup event
* @param text text about the failure
* @param outcome outcome of the container
*/
public synchronized void noteFailed(boolean startupFailure, String text,
ContainerOutcome outcome) {
if (text != null) {
failureMessage = text;
}
switch (outcome) {
case Preempted:
preempted.incrementAndGet();
break;
case Node_failure:
nodeFailed.incrementAndGet();
failed++;
break;
case Failed_limits_exceeded: // exceeded memory or CPU; app/configuration related
limitsExceeded.incrementAndGet();
// fall through
case Failed: // application failure, possibly node related, possibly not
default: // anything else (future-proofing)
failed++;
failedRecently.incrementAndGet();
//have a look to see if it short lived
if (startupFailure) {
incStartFailed();
}
break;
}
}
public synchronized int getStartFailed() {
return startFailed;
}
public synchronized void incStartFailed() {
startFailed++;
}
public synchronized String getFailureMessage() {
return failureMessage;
}
public synchronized int getCompleted() {
return completed;
}
public synchronized void setCompleted(int completed) {
this.completed = completed;
}
public synchronized int incCompleted() {
return completed ++;
}
public synchronized int getStarted() {
return started;
}
public synchronized void incStarted() {
started++;
}
public synchronized int getTotalRequested() {
return totalRequested;
}
public long getPreempted() {
return preempted.get();
}
public long getNodeFailed() {
return nodeFailed.get();
}
/**
* Get the number of roles we are short of.
* nodes released are ignored.
* @return the positive or negative number of roles to add/release.
* 0 means "do nothing".
*/
public synchronized int getDelta() {
int inuse = getActualAndRequested();
//don't know how to view these. Are they in-use or not?
int delta = desired - inuse;
if (delta < 0) {
//if we are releasing, remove the number that are already released.
delta += releasing;
//but never switch to a positive
delta = Math.min(delta, 0);
}
return delta;
}
/**
* Get count of actual and requested containers
* @return the size of the application when outstanding requests are included
*/
public synchronized int getActualAndRequested() {
return actual + requested;
}
@Override
public synchronized String toString() {
return "RoleStatus{" +
"name='" + name + '\'' +
", key=" + key +
", desired=" + desired +
", actual=" + actual +
", requested=" + requested +
", releasing=" + releasing +
", failed=" + failed +
", failed recently=" + failedRecently.get() +
", node failed=" + nodeFailed.get() +
", pre-empted=" + preempted.get() +
", started=" + started +
", startFailed=" + startFailed +
", completed=" + completed +
", failureMessage='" + failureMessage + '\'' +
'}';
}
@Override
public synchronized Object clone() throws CloneNotSupportedException {
return super.clone();
}
/**
* Get the provider role
* @return the provider role
*/
public ProviderRole getProviderRole() {
return providerRole;
}
/**
* Build the statistics map from the current data
* @return a map for use in statistics reports
*/
public Map<String, Integer> buildStatistics() {
ComponentInformation componentInformation = serialize();
return componentInformation.buildStatistics();
}
/**
* Produced a serialized form which can be served up as JSON
* @return a summary of the current role status.
*/
public synchronized ComponentInformation serialize() {
ComponentInformation info = new ComponentInformation();
info.name = name;
info.priority = getPriority();
info.desired = desired;
info.actual = actual;
info.requested = requested;
info.releasing = releasing;
info.failed = failed;
info.startFailed = startFailed;
info.placementPolicy = getPlacementPolicy();
info.failureMessage = failureMessage;
info.totalRequested = totalRequested;
info.failedRecently = failedRecently.intValue();
info.nodeFailed = nodeFailed.intValue();
info.preempted = preempted.intValue();
return info;
}
/**
* Compare two role status entries by name
*/
public static class CompareByName implements Comparator<RoleStatus>,
Serializable {
@Override
public int compare(RoleStatus o1, RoleStatus o2) {
return o1.getName().compareTo(o2.getName());
}
}
/**
* Compare two role status entries by key
*/
public static class CompareByKey implements Comparator<RoleStatus>,
Serializable {
@Override
public int compare(RoleStatus o1, RoleStatus o2) {
return (o1.getKey() < o2.getKey() ? -1 : (o1.getKey() == o2.getKey() ? 0 : 1));
}
}
}