/*
* 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.geode.admin.internal;
import org.apache.geode.admin.DistributedSystemHealthConfig;
import org.apache.geode.distributed.internal.DM;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.DistributionManager;
import org.apache.geode.distributed.internal.MembershipListener;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.i18n.LocalizedStrings;
import java.util.List;
import java.util.Set;
/**
* Contains the logic for evaluating the health of an entire GemFire distributed system according to
* the thresholds provided in a {@link DistributedSystemHealthConfig}.
*
* <P>
*
* Note that unlike other evaluators, the <code>DistributedSystemHealthEvaluator</code> resides in
* the "administrator" VM and not in the member VMs. This is because there only needs to be one
* <code>DistributedSystemHealthEvaluator</code> per distributed system.
*
*
* @since GemFire 3.5
*/
class DistributedSystemHealthEvaluator extends AbstractHealthEvaluator
implements MembershipListener {
/** The config from which we get the evaluation criteria */
private DistributedSystemHealthConfig config;
/**
* The distribution manager with which this MembershipListener is registered
*/
private DM dm;
/** The description of the distributed system being evaluated */
private String description;
/**
* The number of application members that have unexpectedly left since the previous evaluation
*/
private int crashedApplications;
/////////////////////// Constructors ///////////////////////
/**
* Creates a new <code>DistributedSystemHealthEvaluator</code>
*/
DistributedSystemHealthEvaluator(DistributedSystemHealthConfig config, DM dm) {
super(null, dm);
this.config = config;
this.dm = dm;
this.dm.addMembershipListener(this);
StringBuffer sb = new StringBuffer();
sb.append("Distributed System ");
String desc = null;
if (dm instanceof DistributionManager) {
desc = ((DistributionManager) dm).getDistributionConfigDescription();
}
if (desc != null) {
sb.append(desc);
} else {
DistributionConfig dsc = dm.getSystem().getConfig();
String locators = dsc.getLocators();
if (locators == null || locators.equals("")) {
sb.append("using multicast ");
sb.append(dsc.getMcastAddress());
sb.append(":");
sb.append(dsc.getMcastPort());
} else {
sb.append("using locators ");
sb.append(locators);
}
}
this.description = sb.toString();
}
//////////////////// Instance Methods ////////////////////
@Override
protected String getDescription() {
return this.description;
}
/**
* Checks to make sure that the number of application members of the distributed system that have
* left unexpected since the last evaluation is less than the
* {@linkplain DistributedSystemHealthConfig#getMaxDepartedApplications threshold}. If not, the
* status is "poor" health.
*/
void checkDepartedApplications(List status) {
synchronized (this) {
long threshold = this.config.getMaxDepartedApplications();
if (this.crashedApplications > threshold) {
String s =
LocalizedStrings.DistributedSystemHealth_THE_NUMBER_OF_APPLICATIONS_THAT_HAVE_LEFT_THE_DISTRIBUTED_SYSTEM_0_EXCEEDS_THE_THRESHOLD_1
.toLocalizedString(
new Object[] {Long.valueOf(this.crashedApplications), Long.valueOf(threshold)});
status.add(poorHealth(s));
}
this.crashedApplications = 0;
}
}
@Override
protected void check(List status) {
checkDepartedApplications(status);
}
@Override
void close() {
this.dm.removeMembershipListener(this);
}
public void memberJoined(InternalDistributedMember id) {
}
/**
* Keeps track of which members depart unexpectedly
*/
public void memberDeparted(InternalDistributedMember id, boolean crashed) {
if (!crashed)
return;
synchronized (this) {
int kind = id.getVmKind();
switch (kind) {
case DistributionManager.LOCATOR_DM_TYPE:
case DistributionManager.NORMAL_DM_TYPE:
this.crashedApplications++;
break;
default:
break;
}
} // synchronized
}
public void quorumLost(Set<InternalDistributedMember> failures,
List<InternalDistributedMember> remaining) {}
public void memberSuspect(InternalDistributedMember id, InternalDistributedMember whoSuspected,
String reason) {}
}