http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreHelper.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreHelper.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreHelper.java new file mode 100644 index 0000000..8410d9b --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreHelper.java @@ -0,0 +1,76 @@ +/* + * 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.internal.admin.api.impl; + +import java.io.File; +import java.util.Map; +import java.util.Set; + +import org.apache.geode.cache.persistence.PersistentID; +import org.apache.geode.distributed.DistributedLockService; +import org.apache.geode.distributed.DistributedMember; +import org.apache.geode.distributed.internal.DM; +import org.apache.geode.internal.Assert; + +public class BackupDataStoreHelper { + + public static String LOCK_SERVICE_NAME = BackupDataStoreHelper.class.getSimpleName(); + + private static String LOCK_NAME = LOCK_SERVICE_NAME + "_token"; + + private static Object LOCK_SYNC = new Object(); + + @SuppressWarnings("rawtypes") + public static BackupDataStoreResult backupAllMembers( + DM dm, Set recipients, File targetDir, File baselineDir) { + FlushToDiskRequest.send(dm, recipients); + + boolean abort= true; + Map<DistributedMember, Set<PersistentID>> successfulMembers; + Map<DistributedMember, Set<PersistentID>> existingDataStores; + try { + existingDataStores = PrepareBackupRequest.send(dm, recipients); + abort = false; + } finally { + successfulMembers = FinishBackupRequest.send(dm, recipients, targetDir, baselineDir, abort); + } + return new BackupDataStoreResult(existingDataStores, successfulMembers); + } + + private static DistributedLockService getLockService(DM dm) { + DistributedLockService dls = DistributedLockService.getServiceNamed(LOCK_SERVICE_NAME); + if (dls == null) { + synchronized (LOCK_SYNC) { + dls = DistributedLockService.getServiceNamed(LOCK_SERVICE_NAME); + if (dls == null) { + // Create the DistributedLockService + dls = DistributedLockService.create(LOCK_SERVICE_NAME, dm.getSystem()); + } + } + } + Assert.assertTrue(dls != null); + return dls; + } + + public static boolean obtainLock(DM dm) { + return getLockService(dm).lock(LOCK_NAME, 0, -1); + } + + public static void releaseLock(DM dm) { + getLockService(dm).unlock(LOCK_NAME); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreResult.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreResult.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreResult.java new file mode 100644 index 0000000..ae425d2 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupDataStoreResult.java @@ -0,0 +1,57 @@ +/* + * 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.internal.admin.api.impl; + +import java.util.Map; +import java.util.Set; + +import org.apache.geode.cache.persistence.PersistentID; +import org.apache.geode.distributed.DistributedMember; + +public class BackupDataStoreResult { + + private Map<DistributedMember, Set<PersistentID>> existingDataStores; + + private Map<DistributedMember, Set<PersistentID>> successfulMembers; + + public BackupDataStoreResult( + Map<DistributedMember, Set<PersistentID>> existingDataStores, + Map<DistributedMember, Set<PersistentID>> successfulMembers) { + this.existingDataStores = existingDataStores; + this.successfulMembers = successfulMembers; + } + + public Map<DistributedMember, Set<PersistentID>> getExistingDataStores() { + return this.existingDataStores; + } + + public Map<DistributedMember, Set<PersistentID>> getSuccessfulMembers() { + return this.successfulMembers; + } + + public String toString() { + return new StringBuilder() + .append(getClass().getSimpleName()) + .append("[") + .append("existingDataStores=") + .append(this.existingDataStores) + .append("; successfulMembers=") + .append(this.successfulMembers) + .append("]") + .toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupStatusImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupStatusImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupStatusImpl.java new file mode 100644 index 0000000..e4ff89d --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/BackupStatusImpl.java @@ -0,0 +1,61 @@ +/* + * 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.internal.admin.api.impl; + +import java.io.Serializable; +import java.util.Map; +import java.util.Set; + +import org.apache.geode.internal.admin.api.BackupStatus; +import org.apache.geode.cache.persistence.PersistentID; +import org.apache.geode.distributed.DistributedMember; + +/** + * Holds the result of a backup operation. + * + * + */ +public class BackupStatusImpl implements BackupStatus, Serializable { + private static final long serialVersionUID = 3704162840296921840L; + + private Map<DistributedMember, Set<PersistentID>> backedUpDiskStores; + private Set<PersistentID> offlineDiskStores; + + public BackupStatusImpl( + Map<DistributedMember, Set<PersistentID>> backedUpDiskStores, + Set<PersistentID> offlineDiskStores) { + super(); + this.backedUpDiskStores = backedUpDiskStores; + this.offlineDiskStores = offlineDiskStores; + } + + public Map<DistributedMember, Set<PersistentID>> getBackedUpDiskStores() { + return backedUpDiskStores; + } + + public Set<PersistentID> getOfflineDiskStores() { + return offlineDiskStores; + } + + @Override + public String toString() { + return "BackupStatus[backedUpDiskStores=" + backedUpDiskStores + ", offlineDiskStores=" + offlineDiskStores + "]"; + } + + + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthConfigImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthConfigImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthConfigImpl.java new file mode 100644 index 0000000..b0afdb4 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthConfigImpl.java @@ -0,0 +1,91 @@ +/* + * 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.internal.admin.api.impl; + +import org.apache.geode.internal.admin.api.CacheHealthConfig; + +/** + * The implementation of <code>CacheHealthConfig</code> + * + * + * @since GemFire 3.5 + */ +public abstract class CacheHealthConfigImpl + extends MemberHealthConfigImpl implements CacheHealthConfig { + + /** The maximum number of milliseconds a + * <code>netSearch</code> operation can take before the cache member + * is considered to be unhealthy. */ + private long maxNetSearchTime = DEFAULT_MAX_NET_SEARCH_TIME; + + /** The maximum mumber of milliseconds a cache + * <code>load</code> operation can take before the cache member is + * considered to be unhealthy. */ + private long maxLoadTime = DEFAULT_MAX_LOAD_TIME; + + /** The minimum hit ratio of a healthy cache member. */ + private double minHitRatio = DEFAULT_MIN_HIT_RATIO; + + /** The maximum number of entries in the event delivery queue + * of a healthy cache member. */ + private long maxEventQueueSize = DEFAULT_MAX_EVENT_QUEUE_SIZE; + + /////////////////////// Constructors /////////////////////// + + /** + * Creates a new <code>CacheHealthConfigImpl</code> with the default + * configuration. + */ + CacheHealthConfigImpl() { + + } + + ////////////////////// Instance Methods ///////////////////// + + public long getMaxNetSearchTime() { + return this.maxNetSearchTime; + } + + public void setMaxNetSearchTime(long maxNetSearchTime) { + this.maxNetSearchTime = maxNetSearchTime; + } + + public long getMaxLoadTime() { + return this.maxLoadTime; + } + + public void setMaxLoadTime(long maxLoadTime) { + this.maxLoadTime = maxLoadTime; + } + + public double getMinHitRatio() { + return this.minHitRatio; + } + + public void setMinHitRatio(double minHitRatio) { + this.minHitRatio = minHitRatio; + } + + public long getMaxEventQueueSize() { + return this.maxEventQueueSize; + } + + public void setMaxEventQueueSize(long maxEventQueueSize) { + this.maxEventQueueSize = maxEventQueueSize; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthEvaluator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthEvaluator.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthEvaluator.java new file mode 100644 index 0000000..9f105d9 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheHealthEvaluator.java @@ -0,0 +1,323 @@ +/* + * 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.internal.admin.api.impl; + +import java.util.List; + +import org.apache.logging.log4j.Logger; + +import org.apache.geode.CancelException; +import org.apache.geode.internal.admin.api.CacheHealthConfig; +import org.apache.geode.internal.admin.api.GemFireHealthConfig; +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.distributed.internal.DM; +import org.apache.geode.distributed.internal.InternalDistributedSystem; +import org.apache.geode.internal.OSProcess; +import org.apache.geode.internal.cache.CacheLifecycleListener; +import org.apache.geode.internal.cache.CachePerfStats; +import org.apache.geode.internal.cache.GemFireCacheImpl; +import org.apache.geode.internal.i18n.LocalizedStrings; +import org.apache.geode.internal.logging.LogService; + +/** + * Contains the logic for evaluating the health of a GemFire + * <code>Cache</code> instance according to the thresholds provided in + * a {@link CacheHealthConfig}. + * + * + * @since GemFire 3.5 + */ +class CacheHealthEvaluator extends AbstractHealthEvaluator + implements CacheLifecycleListener { + + private static final Logger logger = LogService.getLogger(); + + /** The config from which we get the evaulation criteria */ + private CacheHealthConfig config; + + /** The description of the cache being evaluated */ + private String description; + + /** Statistics about the <code>Cache</code> instance. If no cache + * has been created in this VM, this field will be <code>null</code> + */ + private CachePerfStats cacheStats; + + /** The previous value of the netsearchTime stat (in nanoseconds) */ + private long prevNetsearchTime; + + /** The previous value of the netsearchedCompleted stat */ + private long prevNetsearchesCompleted; + + /** The previous value of the loadTime stat (in nanoseconds) */ + private long prevLoadTime; + + /** The previous value of the loadedCompleted stat */ + private long prevLoadsCompleted; + + /** The previous value of the gets stat */ + private long prevGets; + + ////////////////////// Constructors ////////////////////// + + /** + * Creates a new <code>CacheHealthEvaluator</code> + */ + CacheHealthEvaluator(GemFireHealthConfig config, + DM dm) { + super(config, dm); + + this.config = config; + InternalDistributedSystem system = dm.getSystem(); + GemFireCacheImpl cache; + try { + cache = (GemFireCacheImpl) CacheFactory.getInstance(system); + + } catch (CancelException ex) { + // No cache in this VM + cache = null; + } + + initialize(cache, dm); + GemFireCacheImpl.addCacheLifecycleListener(this); + } + + //////////////////// Instance Methods //////////////////// + + @Override + protected String getDescription() { + return this.description; + } + + /** + * Initializes the state of this evaluator based on the given cache + * instance. + */ + private void initialize(GemFireCacheImpl cache, DM dm) { + StringBuffer sb = new StringBuffer(); + if (cache != null) { + this.cacheStats = cache.getCachePerfStats(); + + sb.append("Cache \""); + sb.append(cache.getName()); + sb.append("\""); + + } else { + sb.append("No Cache"); + } + + sb.append(" in member "); + sb.append(dm.getId()); + int pid = OSProcess.getId(); + if (pid != 0) { + sb.append(" with pid "); + sb.append(pid); + } + this.description = sb.toString(); + } + + public void cacheCreated(GemFireCacheImpl cache) { + InternalDistributedSystem system = + (InternalDistributedSystem) cache.getDistributedSystem(); + DM dm = system.getDistributionManager(); + initialize(cache, dm); + } + + /** + * Checks to make sure that the average <code>netSearch</code> time + * during the previous health check interval is less than the + * {@linkplain CacheHealthConfig#getMaxNetSearchTime threshold}. If + * not, the status is "okay" health. + * + * @see CachePerfStats#getNetsearchTime + * @see CachePerfStats#getNetsearchesCompleted + */ + void checkNetSearchTime(List status) { + if (this.cacheStats == null || isFirstEvaluation() || + this.cacheStats.isClosed()) { + return; + } + + long deltaNetsearchTime = + this.cacheStats.getNetsearchTime() - this.prevNetsearchTime; + long deltaNetsearchesCompleted = + this.cacheStats.getNetsearchesCompleted() - + this.prevNetsearchesCompleted; + + if (deltaNetsearchesCompleted != 0) { + long ratio = deltaNetsearchTime / deltaNetsearchesCompleted; + ratio /= 1000000; + long threshold = this.config.getMaxNetSearchTime(); + + if (ratio > threshold) { + String s = LocalizedStrings.CacheHealthEvaluator_THE_AVERAGE_DURATION_OF_A_CACHE_NETSEARCH_0_MS_EXCEEDS_THE_THRESHOLD_1_MS.toLocalizedString(new Object[] { ratio, threshold }); + status.add(okayHealth(s)); + } + } + } + + /** + * Checks to make sure that the average <code>load</code> time + * during the previous health check interval is less than the + * {@linkplain CacheHealthConfig#getMaxLoadTime threshold}. If + * not, the status is "okay" health. + * + * @see CachePerfStats#getLoadTime + * @see CachePerfStats#getLoadsCompleted + */ + void checkLoadTime(List status) { + if (this.cacheStats == null || isFirstEvaluation() || + this.cacheStats.isClosed()) { + return; + } + + if (!isFirstEvaluation()) { + long deltaLoadTime = + this.cacheStats.getLoadTime() - this.prevLoadTime; + long deltaLoadsCompleted = + this.cacheStats.getLoadsCompleted() - + this.prevLoadsCompleted; + + if (logger.isDebugEnabled()) { + logger.debug("Completed {} loads in {} ms", deltaLoadsCompleted, (deltaLoadTime / 1000000)); + } + + if (deltaLoadsCompleted != 0) { + long ratio = deltaLoadTime / deltaLoadsCompleted; + ratio /= 1000000; + long threshold = this.config.getMaxLoadTime(); + + if (ratio > threshold) { + String s = LocalizedStrings.CacheHealthEvaluator_THE_AVERAGE_DURATION_OF_A_CACHE_LOAD_0_MS_EXCEEDS_THE_THRESHOLD_1_MS.toLocalizedString(new Object[] { ratio, threshold }); + if (logger.isDebugEnabled()) { + logger.debug(s); + } + status.add(okayHealth(s)); + } + } + } + } + + /** + * Checks to make sure that the cache hit ratio during the previous + * health check interval is less than the {@linkplain + * CacheHealthConfig#getMinHitRatio threshold}. If not, the status + * is "okay" health. + * + * <P> + * + * The following formula is used to compute the hit ratio: + * + * <PRE> + * hitRatio = (gets - (loadsCompleted + netsearchesCompleted)) / (gets) + * </PRE> + * + * + * @see CachePerfStats#getGets + * @see CachePerfStats#getLoadsCompleted + * @see CachePerfStats#getNetsearchesCompleted + */ + void checkHitRatio(List status) { + if (this.cacheStats == null || isFirstEvaluation() || + this.cacheStats.isClosed()) { + return; + } + + long deltaGets = this.cacheStats.getGets() - this.prevGets; + if (deltaGets != 0) { + long deltaLoadsCompleted = + this.cacheStats.getLoadsCompleted() - this.prevLoadsCompleted; + long deltaNetsearchesCompleted = + this.cacheStats.getNetsearchesCompleted() - + this.prevNetsearchesCompleted; + + double hits = + (deltaGets - + (deltaLoadsCompleted + deltaNetsearchesCompleted)); + double hitRatio = hits / deltaGets; + double threshold = this.config.getMinHitRatio(); + if (hitRatio < threshold) { + String s = "The hit ratio of this Cache (" + hitRatio + + ") is below the threshold (" + threshold + ")"; + status.add(okayHealth(s)); + } + } + } + + /** + * Checks to make sure that the {@linkplain + * CachePerfStats#getEventQueueSize cache event queue size} does + * not exceed the {@linkplain CacheHealthConfig#getMaxEventQueueSize + * threshold}. If it does, the status is "okay" health. + */ + void checkEventQueueSize(List status) { + if (this.cacheStats == null || isFirstEvaluation() || + this.cacheStats.isClosed()) { + return; + } + + long eventQueueSize = this.cacheStats.getEventQueueSize(); + long threshold = this.config.getMaxEventQueueSize(); + if (eventQueueSize > threshold) { + String s = LocalizedStrings.CacheHealthEvaluator_THE_SIZE_OF_THE_CACHE_EVENT_QUEUE_0_MS_EXCEEDS_THE_THRESHOLD_1_MS.toLocalizedString(new Object[] { Long.valueOf(eventQueueSize), Long.valueOf(threshold) }); + status.add(okayHealth(s)); + } + } + + + /** + * Updates the previous values of statistics + */ + private void updatePrevious() { + if (this.cacheStats != null && !this.cacheStats.isClosed()) { + this.prevLoadTime = this.cacheStats.getLoadTime(); + this.prevLoadsCompleted = this.cacheStats.getLoadsCompleted(); + this.prevNetsearchTime = this.cacheStats.getNetsearchTime(); + this.prevNetsearchesCompleted = + this.cacheStats.getNetsearchesCompleted(); + this.prevGets = this.cacheStats.getGets(); + + } else { + this.prevLoadTime = 0L; + this.prevLoadsCompleted = 0L; + this.prevNetsearchTime = 0L; + this.prevNetsearchesCompleted = 0L; + this.prevGets = 0L; + } + } + + @Override + protected void check(List status) { + + checkNetSearchTime(status); + checkLoadTime(status); + checkHitRatio(status); + checkEventQueueSize(status); + + updatePrevious(); + } + + @Override + public void close() { + GemFireCacheImpl.removeCacheLifecycleListener(this); + } + + @Override + public void cacheClosed(GemFireCacheImpl cache) { + // do nothing + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerConfigImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerConfigImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerConfigImpl.java new file mode 100644 index 0000000..7e4ef15 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerConfigImpl.java @@ -0,0 +1,136 @@ +/* + * 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.internal.admin.api.impl; + +import org.apache.geode.internal.admin.api.CacheServerConfig; +import org.apache.geode.internal.admin.api.CacheVmConfig; +import org.apache.geode.internal.admin.GemFireVM; + +import static org.apache.geode.distributed.ConfigurationProperties.*; + +/** + * An implementation of <code>CacheVmConfig</code> + * + * @since GemFire 4.0 + */ +public class CacheServerConfigImpl extends ManagedEntityConfigImpl + implements CacheVmConfig, CacheServerConfig { + + /** Declarative caching XML file that is used to initialize the + * Cache in the cache server. */ + private String cacheXMLFile; + + /** Extra classpath for the cache server */ + private String classpath; + + /////////////////////// Constructors /////////////////////// + + /** + * Creates a new <code>CacheServerConfigImpl</code> with the default + * configuration settings. + */ + public CacheServerConfigImpl() { + this.cacheXMLFile = null; + this.classpath = null; + } + + /** + * Creates a new <code>CacheServerConfigImpl</code> for a running + * cache server. + */ + public CacheServerConfigImpl(GemFireVM vm) { + super(vm); + + String name = CACHE_XML_FILE; + this.cacheXMLFile = vm.getConfig().getAttribute(name); + this.classpath = null; + } + + /** + * Copy constructor + */ + public CacheServerConfigImpl(CacheServerConfig other) { + super(other); + this.cacheXMLFile = other.getCacheXMLFile(); + this.classpath = other.getClassPath(); + } + + /** + * Copy constructor + */ + public CacheServerConfigImpl(CacheVmConfig other) { + super(other); + this.cacheXMLFile = other.getCacheXMLFile(); + this.classpath = other.getClassPath(); + } + + ////////////////////// Instance Methods ////////////////////// + + public String getCacheXMLFile() { + return this.cacheXMLFile; + } + + public void setCacheXMLFile(String cacheXMLFile) { + checkReadOnly(); + this.cacheXMLFile = cacheXMLFile; + configChanged(); + } + + public String getClassPath() { + return this.classpath; + } + + public void setClassPath(String classpath) { + checkReadOnly(); + this.classpath = classpath; + configChanged(); + } + + @Override + public void validate() { + super.validate(); + + // Nothing to validate really. Cache.xml file could live on + // different file system. + } + + /** + * Currently, listeners are not supported on the locator config. + */ + @Override + protected void configChanged() { + + } + + @Override + public Object clone() throws CloneNotSupportedException { + return new CacheServerConfigImpl((CacheVmConfig)this); + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(super.toString()); + sb.append(" cacheXMLFile="); + sb.append(this.getCacheXMLFile()); + sb.append(" classPath="); + sb.append(this.getClassPath()); + + return sb.toString(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerImpl.java new file mode 100644 index 0000000..8046406 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/CacheServerImpl.java @@ -0,0 +1,205 @@ +/* + * 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.internal.admin.api.impl; + +import org.apache.geode.distributed.internal.DM; +import org.apache.geode.distributed.internal.DistributionManager; +import org.apache.geode.internal.admin.GemFireVM; +import org.apache.geode.internal.admin.api.AdminException; +import org.apache.geode.internal.admin.api.CacheServer; +import org.apache.geode.internal.admin.api.CacheServerConfig; +import org.apache.geode.internal.admin.api.CacheVm; +import org.apache.geode.internal.admin.api.CacheVmConfig; +import org.apache.geode.internal.admin.api.ManagedEntityConfig; +import org.apache.geode.internal.admin.api.SystemMemberType; +import org.apache.geode.internal.admin.remote.RemoteApplicationVM; + +import static org.apache.geode.distributed.ConfigurationProperties.*; + +/** + * Implements the administrative interface to a cache server. + * + * @since GemFire 3.5 + */ +public class CacheServerImpl extends ManagedSystemMemberImpl + implements CacheVm, CacheServer { + + /** How many new <code>CacheServer</code>s have been created? */ + private static int newCacheServers = 0; + + /////////////////////// Instance Fields /////////////////////// + + /** The configuration object for this cache server */ + private final CacheServerConfigImpl config; + + ///////////////////////// Constructors //////////////////////// + + /** + * Creates a new <code>CacheServerImpl</code> that represents a + * non-existsing (unstarted) cache server in a given distributed + * system. + */ + public CacheServerImpl(AdminDistributedSystemImpl system, + CacheVmConfig config) + throws AdminException { + + super(system, config); + + this.config = (CacheServerConfigImpl) config; + this.config.setManagedEntity(this); + } + + /** + * Creates a new <code>CacheServerImpl</code> that represents an + * existing dedicated cache server in a given distributed system. + */ + public CacheServerImpl(AdminDistributedSystemImpl system, + GemFireVM vm) + throws AdminException { + + super(system, vm); + this.config = new CacheServerConfigImpl(vm); + } + + ////////////////////// Instance Methods ////////////////////// + + @Override + public SystemMemberType getType() { + return SystemMemberType.CACHE_VM; + } + + public String getNewId() { + synchronized (CacheServerImpl.class) { + return "CacheVm" + (++newCacheServers); + } + } + + public void start() throws AdminException { + if (!needToStart()) { + return; + } + + this.config.validate(); + this.controller.start(this); + this.config.setManagedEntity(this); + } + + public void stop() { + if (!needToStop()) { + return; + } + + this.controller.stop(this); + // NOTE: DistributedSystem nodeLeft will then set this.manager to null + this.config.setManagedEntity(null); + } + + public boolean isRunning() { + DM dm = ((AdminDistributedSystemImpl)getDistributedSystem()).getDistributionManager(); + if(dm == null) { + try { + return this.controller.isRunning(this); + } + catch (IllegalStateException e) { + return false; + } + } + return ((DistributionManager)dm).getDistributionManagerIdsIncludingAdmin().contains(getDistributedMember()); + } + + public CacheServerConfig getConfig() { + return this.config; + } + + public CacheVmConfig getVmConfig() { + return this.config; + } + + //////////////////////// Command execution //////////////////////// + + public ManagedEntityConfig getEntityConfig() { + return this.getConfig(); + } + + public String getEntityType() { + // Fix bug 32564 + return "Cache Vm"; + } + + public String getStartCommand() { + StringBuffer sb = new StringBuffer(); + sb.append(this.controller.getProductExecutable(this, "cacheserver")); + sb.append(" start -dir="); + sb.append(this.getConfig().getWorkingDirectory()); + + String file = this.getConfig().getCacheXMLFile(); + if (file != null && file.length() > 0) { + sb.append(" "); + sb.append(CACHE_XML_FILE); + sb.append("="); + sb.append(file); + } + + String classpath = this.getConfig().getClassPath(); + if (classpath != null && classpath.length() > 0) { + sb.append(" -classpath="); + sb.append(classpath); + } + + appendConfiguration(sb); + + return sb.toString().trim(); + } + + public String getStopCommand() { + StringBuffer sb = new StringBuffer(); + sb.append(this.controller.getProductExecutable(this, "cacheserver")); + sb.append(" stop -dir="); + sb.append(this.getConfig().getWorkingDirectory()); + + return sb.toString().trim(); + } + + public String getIsRunningCommand() { + StringBuffer sb = new StringBuffer(); + sb.append(this.controller.getProductExecutable(this, "cacheserver")); + sb.append(" status -dir="); + sb.append(this.getConfig().getWorkingDirectory()); + + return sb.toString().trim(); + } + + /** + * Find whether this server is primary for given client (durableClientId) + * + * @param durableClientId - + * durable-id of the client + * @return true if the server is primary for given client + * + * @since GemFire 5.6 + */ + public boolean isPrimaryForDurableClient(String durableClientId) + { + RemoteApplicationVM vm = (RemoteApplicationVM)this.getGemFireVM(); + boolean isPrimary = false; + if (vm != null) { + isPrimary = vm.isPrimaryForDurableClient(durableClientId); +} + return isPrimary; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterImpl.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterImpl.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterImpl.java new file mode 100755 index 0000000..fe61760 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterImpl.java @@ -0,0 +1,280 @@ +/* + * 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.internal.admin.api.impl; + +import org.apache.geode.internal.admin.api.ConfigurationParameter; +import org.apache.geode.internal.admin.api.UnmodifiableConfigurationException; +import org.apache.geode.internal.i18n.LocalizedStrings; + +import java.io.File; +//import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * A single configuration parameter of a system member. + * + * @since GemFire 3.5 + * + */ +public class ConfigurationParameterImpl +implements ConfigurationParameter { + + /** Identifying name of this configuration parameter */ + protected String name; + /** Full description of this configuration parameter */ + protected String description; + /** The current value */ + protected Object value; + /** Class type of the value */ + protected Class type; + /** True if this is modifiable; false if read-only */ + protected boolean userModifiable; + /** List of listeners to notify when value changes */ + private final List listeners = new ArrayList(); + + // ------------------------------------------------------------------------- + // Constructor(s) + // ------------------------------------------------------------------------- + + /** + * Constructs new <code>ConfigurationParameterImpl</code>. + * + * @param name the name of this parameter which cannot change + * @param description full description to use + * @param value the value of this parameter + * @param type the class type of the value + * @param userModifiable true if this is modifiable; false if read-only + */ + protected ConfigurationParameterImpl(String name, + String description, + Object value, + Class type, + boolean userModifiable) { + if (name == null || name.length() == 0) { + throw new IllegalArgumentException(LocalizedStrings.ConfigurationParameterImpl_CONFIGURATIONPARAMETER_NAME_MUST_BE_SPECIFIED.toLocalizedString()); + } + + this.name = name; + setInternalState(description, value, type, userModifiable); + } + + /** + * Constructs new <code>ConfigurationParameterImpl</code>. + * + * @param name the name of this parameter which cannot change + * @param value the value of this parameter + */ + protected ConfigurationParameterImpl(String name, + Object value) { + if (name == null || name.length() == 0) { + throw new IllegalArgumentException(LocalizedStrings.ConfigurationParameterImpl_CONFIGURATIONPARAMETER_NAME_MUST_BE_SPECIFIED.toLocalizedString()); + } + + this.name = name; + setInternalState(name, value, value.getClass(), true); + } + + /** Constructor to allow serialization by subclass */ + protected ConfigurationParameterImpl() {} + + // ------------------------------------------------------------------------- + // Attribute accessors and mutators + // ------------------------------------------------------------------------- + + public String getName() { + return this.name; + } + + public String getDescription() { + return this.description; + } + + public Object getValue() { + return this.value; + } + + public String getValueAsString() { + if (isString()) { + return (String) this.value; + } + else if (isInetAddress()) { + return InetAddressUtil.toString(this.value); + } + else if (isFile()) { + return this.value.toString(); + } + else if (isOctal()) { + String strVal = Integer.toOctalString(((Integer) this.value).intValue()); + if (!strVal.startsWith("0")) { + strVal = "0" + strVal; + } + return strVal; + } + else if (isArray()) { + List list = Arrays.asList((Object[]) this.value); + return list.toString(); + } + else { + return this.value.toString(); + } + } + + public Class getValueType() { + return this.type; + } + + public boolean isModifiable() { + return this.userModifiable; + } + + public boolean isArray() { + return "manager-parameters".equals(this.name) || + "manager-classpaths".equals(this.name); + } + public boolean isInetAddress() { + return java.net.InetAddress.class.isAssignableFrom(this.type); + } + public boolean isFile() { + return java.io.File.class.equals(this.type); + } + public boolean isOctal() { + return "shared-memory-permissions".equals(this.name); + } + public boolean isString() { + return java.lang.String.class.equals(this.type); + } + + public void setValue(Object value) throws UnmodifiableConfigurationException { + if (!isModifiable()) { + throw new UnmodifiableConfigurationException(LocalizedStrings.ConfigurationParameterImpl_0_IS_NOT_A_MODIFIABLE_CONFIGURATION_PARAMETER.toLocalizedString(getName())); + } + if (value == null) { + throw new IllegalArgumentException(LocalizedStrings.ConfigurationParameterImpl_UNABLE_TO_SET_0_TO_NULL_VALUE.toLocalizedString(getName())); + } + if (!getValueType().equals(value.getClass())) { + throw new IllegalArgumentException(LocalizedStrings.ConfigurationParameterImpl_UNABLE_TO_SET_TYPE_0_WITH_TYPE_1.toLocalizedString(new Object[] {getValueType().getName(), value.getClass().getName()})); + } + + if (value instanceof String && !isString()) { + // we need to check what the type should be and convert to it... + setValueFromString((String) value); + } + else { + this.value = value; + } + fireConfigurationParameterValueChanged(this); + } + + // ------------------------------------------------------------------------- + // Operations for handling the registration of listeners + // Note: this is only for use within impl pkg and subclass pkgs + // ------------------------------------------------------------------------- + + /** Adds the listener for any changes to this configuration parameter. */ + public void addConfigurationParameterListener(ConfigurationParameterListener listener) { + if (!this.listeners.contains(listener)) { + this.listeners.add(listener); + } + } + + /** Removes the listener if it's currently registered. */ + public void removeConfigurationParameterListener(ConfigurationParameterListener listener) { + if (this.listeners.contains(listener)) { + this.listeners.remove(listener); + } + } + + // ------------------------------------------------------------------------- + // Implementation methods + // ------------------------------------------------------------------------- + + protected void setValueFromString(String newValue) { + if (newValue == null) { + throw new IllegalArgumentException(LocalizedStrings.ConfigurationParameterImpl_UNABLE_TO_SET_0_TO_NULL_VALUE.toLocalizedString(getName())); + } + + if (isInetAddress()) { + this.value = InetAddressUtil.toInetAddress(newValue); + } + else if (isFile()) { + this.value = new File(newValue); + } + else if (isOctal()) { + if (!newValue.startsWith("0")) { + newValue = "0" + newValue; + } + this.value = Integer.valueOf(Integer.parseInt(newValue, 8)); + } + else if (isArray()) { + // parse it TODO + throw new IllegalArgumentException(LocalizedStrings.ConfigurationParameterImpl_SETTING_ARRAY_VALUE_FROM_DELIMITED_STRING_IS_NOT_SUPPORTED.toLocalizedString()); + } + else { + this.value = newValue; + } + } + + /** + * Fires changed configuration parameter to registered listeners. + * + * @param parm the configuration parameter the changed + */ + protected void fireConfigurationParameterValueChanged(ConfigurationParameter parm) { + ConfigurationParameterListener[] listeners = + (ConfigurationParameterListener[]) this.listeners.toArray( + new ConfigurationParameterListener[0]); + for (int i = 0; i < listeners.length; i++) { + listeners[i].configurationParameterValueChanged(parm); + } + } + + /** + * Sets the internal state of this configuration parameter. + * + * @param description full description to use + * @param value the value of this parameter + * @param type the class type of the value + * @param userModifiable true if this is modifiable; false if read-only + */ + protected void setInternalState(String description, + Object value, + Class type, + boolean userModifiable) { + if (description == null || description.length() == 0) { + throw new IllegalArgumentException(LocalizedStrings.ConfigurationParameterImpl_CONFIGURATIONPARAMETER_DESCRIPTION_MUST_BE_SPECIFIED.toLocalizedString()); + } + this.description = description; + this.type = type; + this.userModifiable = userModifiable; + + if (value == null) { + throw new IllegalArgumentException(LocalizedStrings.ConfigurationParameterImpl_UNABLE_TO_SET_0_TO_NULL_VALUE.toLocalizedString(getName())); + } + + this.value = value; + } + + @Override + public String toString() { + return this.name; + } + +} + http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterListener.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterListener.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterListener.java new file mode 100755 index 0000000..7508da9 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/ConfigurationParameterListener.java @@ -0,0 +1,34 @@ +/* + * 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.internal.admin.api.impl; + +import org.apache.geode.internal.admin.api.ConfigurationParameter; + +/** + * Listens to value changes of a + * {@link ConfigurationParameter}. This is for + * internal use only to allow a {@link SystemMemberImpl} to keep track of + * configuration changes made through + * {@link ConfigurationParameterImpl#setValue}. + * + * @since GemFire 3.5 + * + */ +public interface ConfigurationParameterListener { + public void configurationParameterValueChanged(ConfigurationParameter parm); +} + http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/096b622d/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DisabledManagedEntityController.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DisabledManagedEntityController.java b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DisabledManagedEntityController.java new file mode 100755 index 0000000..f9044a3 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/admin/api/impl/DisabledManagedEntityController.java @@ -0,0 +1,91 @@ +/* + * 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.internal.admin.api.impl; + +import org.apache.logging.log4j.Logger; + +import org.apache.geode.internal.admin.api.DistributedSystemConfig; +import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.logging.log4j.LogMarker; + +/** + * This is a disabled implementation of ManagedEntityController for bug #47909. + * + * The old ManagedEntityController was a concrete class which has been renamed + * to ManagedEntityControllerImpl. The build.xml now skips building + * ManagedEntityControllerImpl. If ManagedEntityControllerImpl is not found + * in the classpath then the code uses DisabledManagedEntityController as a + * place holder. + * + */ +class DisabledManagedEntityController implements ManagedEntityController { + + private static final Logger logger = LogService.getLogger(); + + private static final String EXCEPTION_MESSAGE = "Local and remote OS command invocations are disabled for the Admin API."; + + DisabledManagedEntityController() { + } + + @Override + public void start(InternalManagedEntity entity) { + if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)){ + logger.warn(LogMarker.MANAGED_ENTITY, "DisabledManagedEntityController#start {}", EXCEPTION_MESSAGE); + } + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + + @Override + public void stop(InternalManagedEntity entity) { + if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)){ + logger.warn(LogMarker.MANAGED_ENTITY, "DisabledManagedEntityController#stop {}", EXCEPTION_MESSAGE); + } + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + + @Override + public boolean isRunning(InternalManagedEntity entity) { + if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)){ + logger.warn(LogMarker.MANAGED_ENTITY, "DisabledManagedEntityController#isRunning {}", EXCEPTION_MESSAGE); + } + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + + @Override + public String getLog(DistributionLocatorImpl locator) { + if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)){ + logger.warn(LogMarker.MANAGED_ENTITY, "DisabledManagedEntityController#getLog {}", EXCEPTION_MESSAGE); + } + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + + @Override + public String buildSSLArguments(DistributedSystemConfig config) { + if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)){ + logger.warn(LogMarker.MANAGED_ENTITY, "DisabledManagedEntityController#buildSSLArguments {}", EXCEPTION_MESSAGE); + } + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } + + @Override + public String getProductExecutable(InternalManagedEntity entity, String executable) { + if (logger.isTraceEnabled(LogMarker.MANAGED_ENTITY)){ + logger.warn(LogMarker.MANAGED_ENTITY, "DisabledManagedEntityController#getProductExecutable {}", EXCEPTION_MESSAGE); + } + throw new UnsupportedOperationException(EXCEPTION_MESSAGE); + } +}