GEODE-2012: always write stat types to archive * refactor classes to make testing easier * write additional tests for stat archive rolling * expose bug GEODE-2012 in StatTypesAreRolledOverRegressionTest * fix bug exposed by StatTypesAreRolledOverRegressionTest
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/3bdd1049 Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/3bdd1049 Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/3bdd1049 Branch: refs/heads/develop Commit: 3bdd104972489000edf5592b497d22b89c6ea307 Parents: 820f33e Author: Kirk Lund <[email protected]> Authored: Mon Oct 31 13:36:53 2016 -0700 Committer: Kirk Lund <[email protected]> Committed: Tue Nov 1 10:43:09 2016 -0700 ---------------------------------------------------------------------- .../org/apache/geode/internal/NanoTimer.java | 6 +- .../geode/internal/i18n/LocalizedStrings.java | 2 +- .../io/MainWithChildrenRollingFileHandler.java | 243 ++++++++++++++ .../geode/internal/io/RollingFileHandler.java | 36 +++ .../internal/logging/ManagerLogWriter.java | 322 +++---------------- .../internal/statistics/HostStatSampler.java | 33 +- .../internal/statistics/SampleCollector.java | 23 +- .../internal/statistics/SimpleStatSampler.java | 7 +- .../internal/statistics/StatArchiveHandler.java | 99 +++--- .../internal/statistics/StatArchiveWriter.java | 20 +- .../internal/statistics/StatMonitorHandler.java | 39 ++- .../concurrent/StoppableCountDownLatch.java | 8 +- .../DiskSpaceLimitIntegrationTest.java | 201 ++++++++++++ .../FileSizeLimitIntegrationTest.java | 170 ++++++++++ .../statistics/SampleCollectorTest.java | 4 +- .../statistics/StatMonitorHandlerTest.java | 70 +--- ...itorHandlerWithEnabledMonitorThreadTest.java | 140 ++++++++ .../StatTypesAreRolledOverRegressionTest.java | 205 ++++++++++++ .../statistics/StatisticsMonitorTest.java | 4 +- .../statistics/ValueMonitorIntegrationTest.java | 40 +-- 20 files changed, 1217 insertions(+), 455 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/NanoTimer.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/NanoTimer.java b/geode-core/src/main/java/org/apache/geode/internal/NanoTimer.java index 12e91f8..247f9a9 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/NanoTimer.java +++ b/geode-core/src/main/java/org/apache/geode/internal/NanoTimer.java @@ -38,7 +38,7 @@ package org.apache.geode.internal; * </pre> * */ -public final class NanoTimer { +public class NanoTimer { public static final long NANOS_PER_MILLISECOND = 1000000; @@ -73,7 +73,7 @@ public final class NanoTimer { /** * For unit testing */ - NanoTimer(TimeService ts) { + protected NanoTimer(TimeService ts) { this.timeService = ts; this.lastResetTime = ts.getTime(); this.constructionTime = this.lastResetTime; @@ -164,7 +164,7 @@ public final class NanoTimer { /** * Allows unit tests to insert a deterministic clock for testing. */ - interface TimeService { + public interface TimeService { /** * Returns the current time. */ http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/i18n/LocalizedStrings.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/i18n/LocalizedStrings.java b/geode-core/src/main/java/org/apache/geode/internal/i18n/LocalizedStrings.java index 210539b..7638cb3 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/i18n/LocalizedStrings.java +++ b/geode-core/src/main/java/org/apache/geode/internal/i18n/LocalizedStrings.java @@ -1265,7 +1265,7 @@ public class LocalizedStrings { "Could not free space in {0} directory. The space used is {1} which exceeds the configured limit of {2}."); public static final StringId ManagerLogWriter_DELETED_INACTIVE__0___1_ = - new StringId(1797, "Deleted inactive {0} \"{1}\"."); + new StringId(1797, "Deleted inactive {0} \"{1}\"."); public static final StringId ManagerLogWriter_SWITCHING_TO_LOG__0 = new StringId(1798, "Switching to log {0}"); http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/io/MainWithChildrenRollingFileHandler.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/io/MainWithChildrenRollingFileHandler.java b/geode-core/src/main/java/org/apache/geode/internal/io/MainWithChildrenRollingFileHandler.java new file mode 100644 index 0000000..20d1c4f --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/io/MainWithChildrenRollingFileHandler.java @@ -0,0 +1,243 @@ +/* + * 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.io; + +import org.apache.geode.i18n.LogWriterI18n; +import org.apache.geode.internal.FileUtil; +import org.apache.geode.internal.i18n.LocalizedStrings; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.Arrays; +import java.util.Comparator; +import java.util.regex.Pattern; + +/** + * Extracted from ManagerLogWriter. MainWithChildrenRollingFileHandler is used for both rolling of + * log files and stat archive files. + */ +public class MainWithChildrenRollingFileHandler implements RollingFileHandler { + + private static final Pattern MAIN_ID_PATTERN = Pattern.compile(".+-\\d+-\\d+\\..+"); + private static final Pattern META_ID_PATTERN = Pattern.compile("meta-.+-\\d+\\..+"); + private static final Pattern CHILD_ID_PATTERN = Pattern.compile(".+-\\d+-\\d+\\..+"); + + public MainWithChildrenRollingFileHandler() {} + + @Override + public int calcNextChildId(final File file, final int mainId) { + int result = 0; + File dir = getParentFile(file.getAbsoluteFile()); + int endIdx1 = file.getName().indexOf('-'); + int endIdx2 = file.getName().lastIndexOf('.'); + String baseName = file.getName(); + if (endIdx1 != -1) { + baseName = file.getName().substring(0, endIdx1); + } else { + baseName = file.getName().substring(0, endIdx2); + } + File[] children = findChildren(dir, CHILD_ID_PATTERN); + + /* Search child logs */ + + for (File child : children) { + String name = child.getName(); + // only compare the child id among the same set of files. + if (!name.startsWith(baseName)) { + continue; + } + int endIdIdx = name.lastIndexOf('-'); + int startIdIdx = name.lastIndexOf('-', endIdIdx - 1); + String id = name.substring(startIdIdx + 1, endIdIdx); + + int startChild = name.lastIndexOf("-"); + int endChild = name.lastIndexOf("."); + if (startChild > 0 && endChild > 0) { + String childId = name.substring(startChild + 1, endChild); + + try { + int mainLogId = Integer.parseInt(id); + int childLogId = Integer.parseInt(childId); + if (mainLogId == mainId && childLogId > result) { + result = childLogId; + } + } catch (NumberFormatException ignore) { + } + } + } + result++; + return result; + } + + @Override + public int calcNextMainId(final File dir, final boolean toCreateNew) { + int result = 0; + File[] children = findChildren(dir, MAIN_ID_PATTERN); + + /* Search child logs */ + for (File child : children) { + String name = child.getName(); + int endIdIdx = name.lastIndexOf('-'); + int startIdIdx = name.lastIndexOf('-', endIdIdx - 1); + String id = name.substring(startIdIdx + 1, endIdIdx); + try { + int mid = Integer.parseInt(id); + if (mid > result) { + result = mid; + } + } catch (NumberFormatException ignore) { + } + } + + /* And search meta logs */ + if (toCreateNew) { + File[] metaFiles = findChildren(dir, META_ID_PATTERN); + for (File metaFile : metaFiles) { + String name = metaFile.getName(); + int endIdIdx = name.lastIndexOf('.'); + int startIdIdx = name.lastIndexOf('-', endIdIdx - 1); + String id = name.substring(startIdIdx + 1, endIdIdx); + try { + int mid = Integer.parseInt(id); + if (mid > result) { + result = mid; + } + } catch (NumberFormatException ignore) { + } + } + result++; + } + + return result; + } + + @Override + public void checkDiskSpace(final String type, final File newFile, final long spaceLimit, + final File dir, final LogWriterI18n logger) { + checkDiskSpace(type, newFile, spaceLimit, dir, getFilePattern(newFile.getName()), logger); + } + + private void checkDiskSpace(final String type, final File newFile, final long spaceLimit, + final File dir, final Pattern pattern, final LogWriterI18n logger) { + if (spaceLimit == 0 || pattern == null) { + return; + } + File[] children = findChildrenExcept(dir, pattern, newFile); + if (children == null) { + if (dir.isDirectory()) { + logger.warning( + LocalizedStrings.ManagerLogWriter_COULD_NOT_CHECK_DISK_SPACE_ON_0_BECAUSE_JAVAIOFILELISTFILES_RETURNED_NULL_THIS_COULD_BE_CAUSED_BY_A_LACK_OF_FILE_DESCRIPTORS, + dir); + } + return; + } + Arrays.sort(children, new Comparator() { + @Override + public int compare(Object o1, Object o2) { + File f1 = (File) o1; + File f2 = (File) o2; + long diff = f1.lastModified() - f2.lastModified(); + if (diff < 0) { + return -1; + } else if (diff > 0) { + return 1; + } else { + return 0; + } + } + }); + long spaceUsed = 0; + for (File child : children) { + spaceUsed += child.length(); + } + int idx = 0; + while (spaceUsed >= spaceLimit && idx < children.length) { // check array index to 37388 + long childSize = children[idx].length(); + if (delete(children[idx])) { + spaceUsed -= childSize; + logger.info(LocalizedStrings.ManagerLogWriter_DELETED_INACTIVE__0___1_, + new Object[] {type, children[idx]}); + } else { + logger.warning(LocalizedStrings.ManagerLogWriter_COULD_NOT_DELETE_INACTIVE__0___1_, + new Object[] {type, children[idx]}); + } + idx++; + } + if (spaceUsed > spaceLimit) { + logger.warning( + LocalizedStrings.ManagerLogWriter_COULD_NOT_FREE_SPACE_IN_0_DIRECTORY_THE_SPACE_USED_IS_1_WHICH_EXCEEDS_THE_CONFIGURED_LIMIT_OF_2, + new Object[] {type, Long.valueOf(spaceUsed), Long.valueOf(spaceLimit)}); + } + } + + protected boolean delete(final File file) { + return file.delete(); + } + + @Override + public String formatId(final int id) { + StringBuffer result = new StringBuffer(10); + result.append('-'); + if (id < 10) { + result.append('0'); + } + result.append(id); + return result.toString(); + } + + @Override + public File getParentFile(final File file) { + File tmp = file.getAbsoluteFile().getParentFile(); + if (tmp == null) { + tmp = new File("."); // as a fix for bug #41474 we use "." if getParentFile returns null + } + return tmp; + } + + private Pattern getFilePattern(String name) { + int extIdx = name.lastIndexOf('.'); + String ext = ""; + if (extIdx != -1) { + ext = "\\Q" + name.substring(extIdx) + "\\E"; + name = name.substring(0, extIdx); + } + name = "\\Q" + name + "\\E" + "-\\d+-\\d+" + ext; + return Pattern.compile(name); + } + + private File[] findChildren(final File dir, final Pattern pattern) { + return FileUtil.listFiles(dir, new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return pattern.matcher(name).matches(); + } + }); + } + + private File[] findChildrenExcept(final File dir, final Pattern pattern, final File exception) { + final String exceptionName = (exception == null) ? null : exception.getName(); + return FileUtil.listFiles(dir, new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + if (name.equals(exceptionName)) { + return false; + } else { + return pattern.matcher(name).matches(); + } + } + }); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/io/RollingFileHandler.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/io/RollingFileHandler.java b/geode-core/src/main/java/org/apache/geode/internal/io/RollingFileHandler.java new file mode 100644 index 0000000..288ca39 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/io/RollingFileHandler.java @@ -0,0 +1,36 @@ +/* + * 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.io; + +import org.apache.geode.i18n.LogWriterI18n; + +import java.io.File; + +/** + * Defines the constants and methods for rolling files (logs and stat archives). + */ +public interface RollingFileHandler { + + int calcNextMainId(final File dir, final boolean toCreateNew); + + int calcNextChildId(final File file, final int mainId); + + File getParentFile(final File file); + + String formatId(final int id); + + void checkDiskSpace(final String type, final File newFile, final long spaceLimit, final File dir, + final LogWriterI18n logger); +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriter.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriter.java b/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriter.java index a000d2c..4b333ed 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriter.java +++ b/geode-core/src/main/java/org/apache/geode/internal/logging/ManagerLogWriter.java @@ -15,22 +15,24 @@ package org.apache.geode.internal.logging; import org.apache.geode.distributed.internal.DistributionConfig; -import org.apache.geode.distributed.internal.DistributionManager; import org.apache.geode.i18n.LogWriterI18n; -import org.apache.geode.internal.FileUtil; import org.apache.geode.internal.OSProcess; import org.apache.geode.internal.i18n.LocalizedStrings; +import org.apache.geode.internal.io.MainWithChildrenRollingFileHandler; +import org.apache.geode.internal.io.RollingFileHandler; import org.apache.geode.internal.logging.log4j.AlertAppender; import org.apache.geode.internal.util.LogFileUtils; -import java.io.*; -import java.util.Arrays; -import java.util.Comparator; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; import java.util.Date; -import java.util.regex.Pattern; /** - * Implementation of {@link LogWriterI18n} for distributed system members. Its just like + * Implementation of {@link LogWriterI18n} for distributed system members. It's just like * {@link LocalLogWriter} except it has support for rolling and alerts. * * @since Geode 1.0 @@ -42,10 +44,27 @@ public class ManagerLogWriter extends LocalLogWriter { private final boolean fileSizeLimitInKB; + private final RollingFileHandler rollingFileHandler; + private LogConfig cfg = null; - private DistributionManager dm = null; - // Constructors + private LocalLogWriter mainLogger = this; + + private File logDir = null; + private int mainLogId = -1; + private int childId = 0; + private boolean useChildLogging = false; + + /** + * Set to true when roll is in progress + */ + private boolean rolling = false; + private boolean mainLog = true; + + private File activeLogFile = null; + + private boolean started = false; + /** * Creates a writer that logs to <code>System.out</code>. * @@ -69,16 +88,7 @@ public class ManagerLogWriter extends LocalLogWriter { public ManagerLogWriter(int level, PrintStream out, String connectionName) { super(level, out, connectionName); this.fileSizeLimitInKB = Boolean.getBoolean(TEST_FILE_SIZE_LIMIT_IN_KB_PROPERTY); - } - - private LocalLogWriter mainLogger = this; - - /** - * Gets the logger that writes to the main log file. This logger may differ from the current - * logger when rolling logs are used. - */ - public LogWriterI18n getMainLogger() { - return this.mainLogger; + this.rollingFileHandler = new MainWithChildrenRollingFileHandler(); } /** @@ -98,13 +108,12 @@ public class ManagerLogWriter extends LocalLogWriter { && cfg.getLogFileSizeLimit() != 0; if (useChildLogging()) { - childLogPattern = getLogPattern(this.cfg.getLogFile().getName()); - logDir = getParentFile(this.cfg.getLogFile()); + logDir = rollingFileHandler.getParentFile(this.cfg.getLogFile()); // let archive id always follow main log id, not the vice versa // e.g. in getArchiveName(), it's using mainArchiveId = calcNextMainId(archiveDir); // This is the only place we assign mainLogId. // mainLogId is only referenced when useChildLogging==true - mainLogId = calcNextMainId(logDir, true); + mainLogId = rollingFileHandler.calcNextMainId(logDir, true); } if (started) { if (useChildLogging()) { @@ -121,12 +130,6 @@ public class ManagerLogWriter extends LocalLogWriter { return this.activeLogFile; } - private Pattern childLogPattern = null; - private File logDir = null; - private int mainLogId = -1; - private int childId = 0; - - public File getLogDir() { return this.logDir; } @@ -135,16 +138,6 @@ public class ManagerLogWriter extends LocalLogWriter { return this.mainLogId; } - public static String formatId(int id) { - StringBuffer result = new StringBuffer(10); - result.append('-'); - if (id < 10) { - result.append('0'); - } - result.append(id); - return result.toString(); - } - private File getNextChildLogFile() { String path = this.cfg.getLogFile().getPath(); int extIdx = path.lastIndexOf('.'); @@ -153,7 +146,8 @@ public class ManagerLogWriter extends LocalLogWriter { ext = path.substring(extIdx); path = path.substring(0, extIdx); } - path = path + formatId(mainLogId) + formatId(this.childId) + ext; + path = path + rollingFileHandler.formatId(mainLogId) + rollingFileHandler.formatId(this.childId) + + ext; this.childId++; File result = new File(path); if (result.exists()) { @@ -164,18 +158,10 @@ public class ManagerLogWriter extends LocalLogWriter { } } - private boolean useChildLogging = false; - public boolean useChildLogging() { return this.useChildLogging; } - /** - * Set to true when roll is in progress - */ - private boolean rolling = false; - private boolean mainLog = true; - private long getLogFileSizeLimit() { if (rolling || mainLog) { return Long.MAX_VALUE; @@ -198,8 +184,7 @@ public class ManagerLogWriter extends LocalLogWriter { return result * (1024 * 1024); } - - private static String getMetaLogFileName(String baseLogFileName, int mainLogId) { + private String getMetaLogFileName(String baseLogFileName, int mainLogId) { String metaLogFile = null; int extIdx = baseLogFileName.lastIndexOf('.'); String ext = ""; @@ -210,15 +195,13 @@ public class ManagerLogWriter extends LocalLogWriter { String fileName = new File(metaLogFile).getName(); String parent = new File(metaLogFile).getParent(); - metaLogFile = "meta-" + fileName + formatId(mainLogId) + ext; + metaLogFile = "meta-" + fileName + rollingFileHandler.formatId(mainLogId) + ext; if (parent != null) { metaLogFile = parent + File.separator + metaLogFile; } return metaLogFile; } - private File activeLogFile = null; - private synchronized void switchLogs(File newLog, boolean newIsMain) { rolling = true; try { @@ -258,7 +241,7 @@ public class ManagerLogWriter extends LocalLogWriter { // For windows to work we need to redirect everything // to a temporary file so we can get oldFile closed down // so we can rename it. We don't actually write to this tmp file - File tmpLogDir = getParentFile(this.cfg.getLogFile()); + File tmpLogDir = rollingFileHandler.getParentFile(this.cfg.getLogFile()); tmpFile = File.createTempFile("mlw", null, tmpLogDir); // close the old guy down before we do the rename PrintStream tmpps = OSProcess.redirectOutput(tmpFile, @@ -326,25 +309,14 @@ public class ManagerLogWriter extends LocalLogWriter { } } - /** - * as a fix for bug #41474 we use "." if getParentFile returns null - */ - private static File getParentFile(File f) { - File tmp = f.getAbsoluteFile().getParentFile(); - if (tmp == null) { - tmp = new File("."); - } - return tmp; - } - - public static File getLogNameForOldMainLog(File log, boolean useOldFile) { /* * this is just searching for the existing logfile name we need to search for meta log file name * */ - File dir = getParentFile(log.getAbsoluteFile()); - int previousMainId = calcNextMainId(dir, true); + RollingFileHandler rollingFileHandler = new MainWithChildrenRollingFileHandler(); + File dir = rollingFileHandler.getParentFile(log.getAbsoluteFile()); + int previousMainId = rollingFileHandler.calcNextMainId(dir, true); if (useOldFile) { if (previousMainId > 0) { previousMainId--; @@ -354,225 +326,23 @@ public class ManagerLogWriter extends LocalLogWriter { previousMainId = 1; } - // comment out the following to fix bug 31789 - // if (previousMainId > 1) { - // previousMainId--; - // } File result = null; - int childId = calcNextChildId(log, previousMainId > 0 ? previousMainId : 0); + int childId = rollingFileHandler.calcNextChildId(log, previousMainId > 0 ? previousMainId : 0); StringBuffer buf = new StringBuffer(log.getPath()); int insertIdx = buf.lastIndexOf("."); if (insertIdx == -1) { - buf.append(formatId(previousMainId)).append(formatId(childId)); + buf.append(rollingFileHandler.formatId(previousMainId)) + .append(rollingFileHandler.formatId(childId)); } else { - buf.insert(insertIdx, formatId(childId)); - buf.insert(insertIdx, formatId(previousMainId)); + buf.insert(insertIdx, rollingFileHandler.formatId(childId)); + buf.insert(insertIdx, rollingFileHandler.formatId(previousMainId)); } result = new File(buf.toString()); return result; } - - private static Pattern getLogPattern(String name) { - int extIdx = name.lastIndexOf('.'); - String ext = ""; - if (extIdx != -1) { - ext = "\\Q" + name.substring(extIdx) + "\\E"; - name = name.substring(0, extIdx); - } - name = "\\Q" + name + "\\E" + "-\\d+-\\d+" + ext; - return Pattern.compile(name); - } - - protected static final Pattern mainIdPattern = Pattern.compile(".+-\\d+-\\d+\\..+"); - protected static final Pattern metaIdPattern = Pattern.compile("meta-.+-\\d+\\..+"); - - public static int calcNextMainId(File dir, boolean toCreateNew) { - int result = 0; - File[] childLogs = FileUtil.listFiles(dir, new FilenameFilter() { - public boolean accept(File d, String name) { - return mainIdPattern.matcher(name).matches(); - } - }); - - /* Search child logs */ - for (File childLog : childLogs) { - String name = childLog.getName(); - int endIdIdx = name.lastIndexOf('-'); - int startIdIdx = name.lastIndexOf('-', endIdIdx - 1); - String id = name.substring(startIdIdx + 1, endIdIdx); - try { - int mid = Integer.parseInt(id); - if (mid > result) { - result = mid; - } - } catch (NumberFormatException ignore) { - } - } - - /* And search meta logs */ - if (toCreateNew) { - File[] metaLogs = FileUtil.listFiles(dir, new FilenameFilter() { - public boolean accept(File d, String name) { - return metaIdPattern.matcher(name).matches(); - } - }); - for (File metaLog : metaLogs) { - String name = metaLog.getName(); - int endIdIdx = name.lastIndexOf('.'); - int startIdIdx = name.lastIndexOf('-', endIdIdx - 1); - String id = name.substring(startIdIdx + 1, endIdIdx); - try { - int mid = Integer.parseInt(id); - if (mid > result) { - result = mid; - } - } catch (NumberFormatException ignore) { - } - } - result++; - } - - return result; - } - - protected static final Pattern childIdPattern = Pattern.compile(".+-\\d+-\\d+\\..+"); - - - public static int calcNextChildId(File log, int mainId) { - int result = 0; - File dir = getParentFile(log.getAbsoluteFile()); - int endidx1 = log.getName().indexOf('-'); - int endidx2 = log.getName().lastIndexOf('.'); - String baseName = log.getName(); - if (endidx1 != -1) { - baseName = log.getName().substring(0, endidx1); - } else { - baseName = log.getName().substring(0, endidx2); - } - File[] childLogs = FileUtil.listFiles(dir, new FilenameFilter() { - public boolean accept(File d, String name) { - return childIdPattern.matcher(name).matches(); - } - }); - - /* Search child logs */ - - for (File childLog : childLogs) { - String name = childLog.getName(); - // only compare the childlogid among the same set of log files. - if (!name.startsWith(baseName)) { - continue; - } - int endIdIdx = name.lastIndexOf('-'); - int startIdIdx = name.lastIndexOf('-', endIdIdx - 1); - String id = name.substring(startIdIdx + 1, endIdIdx); - - int startChild = name.lastIndexOf("-"); - int endChild = name.lastIndexOf("."); - if (startChild > 0 && endChild > 0) { - String childId = name.substring(startChild + 1, endChild); - - try { - int mainLogId = Integer.parseInt(id); - int childLogId = Integer.parseInt(childId); - if (mainLogId == mainId && childLogId > result) { - result = childLogId; - } - } catch (NumberFormatException ignore) { - } - } - } - result++; - return result; - } - - - - // private static void debugLog(String msg, boolean stackDump) { - // try { - // FileOutputStream f = new FileOutputStream("debug.log", true); - // LogWriterI18n lw = new LocalLogWriter(ALL_LEVEL, new PrintStream(f)); - // if (stackDump) { - // lw.info(msg, new RuntimeException("STACK")); - // } else { - // lw.info(msg); - // } - // f.close(); - // } catch (IOException ignore) { - // } - // } - - public static void removeOldLogs(LogConfig cfg, File logFile) { - LogWriterI18n log = new LocalLogWriter(INFO_LEVEL, System.err); - checkDiskSpace("log", null, ((long) cfg.getLogDiskSpaceLimit()) * (1024 * 1024), - getParentFile(logFile), getLogPattern(logFile.getName()), log); - } - - public static void checkDiskSpace(String type, File newLog, long spaceLimit, File dir, - final Pattern logPattern, LogWriterI18n logger) { - if (spaceLimit == 0 || logPattern == null) { - return; - } - final String newLogName = (newLog == null) ? null : newLog.getName(); - File[] childLogs = FileUtil.listFiles(dir, new FilenameFilter() { - public boolean accept(File d, String name) { - if (name.equals(newLogName)) { - return false; - } else { - boolean result = logPattern.matcher(name).matches(); - return result; - } - } - }); - if (childLogs == null) { - if (dir.isDirectory()) { - logger.warning( - LocalizedStrings.ManagerLogWriter_COULD_NOT_CHECK_DISK_SPACE_ON_0_BECAUSE_JAVAIOFILELISTFILES_RETURNED_NULL_THIS_COULD_BE_CAUSED_BY_A_LACK_OF_FILE_DESCRIPTORS, - dir); - } - return; - } - Arrays.sort(childLogs, new Comparator() { - public int compare(Object o1, Object o2) { - File f1 = (File) o1; - File f2 = (File) o2; - long diff = f1.lastModified() - f2.lastModified(); - if (diff < 0) { - return -1; - } else if (diff > 0) { - return 1; - } else { - return 0; - } - } - }); - long spaceUsed = 0; - for (File childLog : childLogs) { - spaceUsed += childLog.length(); - } - int fIdx = 0; - while (spaceUsed >= spaceLimit && fIdx < childLogs.length) { // check array index to 37388 - long childSize = childLogs[fIdx].length(); - if (childLogs[fIdx].delete()) { - spaceUsed -= childSize; - logger.info(LocalizedStrings.ManagerLogWriter_DELETED_INACTIVE__0___1_, - new Object[] {type, childLogs[fIdx]}); - } else { - logger.warning(LocalizedStrings.ManagerLogWriter_COULD_NOT_DELETE_INACTIVE__0___1_, - new Object[] {type, childLogs[fIdx]}); - } - fIdx++; - } - if (spaceUsed > spaceLimit) { - logger.warning( - LocalizedStrings.ManagerLogWriter_COULD_NOT_FREE_SPACE_IN_0_DIRECTORY_THE_SPACE_USED_IS_1_WHICH_EXCEEDS_THE_CONFIGURED_LIMIT_OF_2, - new Object[] {type, Long.valueOf(spaceUsed), Long.valueOf(spaceLimit)}); - } - } - private void checkDiskSpace(File newLog) { - checkDiskSpace("log", newLog, getLogDiskSpaceLimit(), logDir, childLogPattern, mainLogger); + rollingFileHandler.checkDiskSpace("log", newLog, getLogDiskSpaceLimit(), logDir, mainLogger); } public void rollLog() { @@ -596,8 +366,6 @@ public class ManagerLogWriter extends LocalLogWriter { } } - private boolean started = false; - /** * Called when manager is done starting up. This is when a child log will be started if rolling is * configured. http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/statistics/HostStatSampler.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/HostStatSampler.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/HostStatSampler.java index 6d7b967..c3ed946 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/statistics/HostStatSampler.java +++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/HostStatSampler.java @@ -20,6 +20,7 @@ import org.apache.geode.Statistics; import org.apache.geode.SystemFailure; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.internal.NanoTimer; +import org.apache.geode.internal.io.MainWithChildrenRollingFileHandler; import org.apache.geode.internal.net.SocketCreator; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; @@ -89,12 +90,20 @@ public abstract class HostStatSampler private final CallbackSampler callbackSampler; + private final NanoTimer timer; + protected HostStatSampler(CancelCriterion stopper, StatSamplerStats samplerStats) { + this(stopper, samplerStats, new NanoTimer()); + } + + protected HostStatSampler(CancelCriterion stopper, StatSamplerStats samplerStats, + NanoTimer timer) { this.stopper = stopper; this.statSamplerInitializedLatch = new StoppableCountDownLatch(this.stopper, 1); this.samplerStats = samplerStats; this.fileSizeLimitInKB = Boolean.getBoolean(TEST_FILE_SIZE_LIMIT_IN_KB_PROPERTY); this.callbackSampler = new CallbackSampler(stopper, samplerStats); + this.timer = timer; } public final StatSamplerStats getStatSamplerStats() { @@ -171,8 +180,6 @@ public abstract class HostStatSampler */ @Override public final void run() { - NanoTimer timer = new NanoTimer(); - final boolean isDebugEnabled_STATISTICS = logger.isTraceEnabled(LogMarker.STATISTICS); if (isDebugEnabled_STATISTICS) { logger.trace(LogMarker.STATISTICS, "HostStatSampler started"); @@ -182,7 +189,8 @@ public abstract class HostStatSampler initSpecialStats(); this.sampleCollector = new SampleCollector(this); - this.sampleCollector.initialize(this, NanoTimer.getTime()); + this.sampleCollector.initialize(this, timer.getTime(), + new MainWithChildrenRollingFileHandler()); this.statSamplerInitializedLatch.countDown(); latchCountedDown = true; @@ -197,7 +205,7 @@ public abstract class HostStatSampler } final long nanosBeforeSleep = timer.getLastResetTime(); final long nanosToDelay = nanosLastTimeStamp + getNanoRate(); - delay(timer, nanosToDelay); + delay(nanosToDelay); nanosLastTimeStamp = timer.getLastResetTime(); if (!stopRequested() && isSamplingEnabled()) { final long nanosTimeStamp = timer.getLastResetTime(); @@ -371,11 +379,21 @@ public abstract class HostStatSampler * @since GemFire 7.0 */ public final boolean waitForInitialization(long ms) throws InterruptedException { - return this.statSamplerInitializedLatch.await(ms); + return awaitInitialization(ms, TimeUnit.MILLISECONDS); + } + + /** + * Awaits the initialization of special statistics. + * + * @see #initSpecialStats + */ + public final boolean awaitInitialization(final long timeout, final TimeUnit unit) + throws InterruptedException { + return this.statSamplerInitializedLatch.await(timeout, unit); } public final void changeArchive(File newFile) { - this.sampleCollector.changeArchive(newFile, NanoTimer.getTime()); + this.sampleCollector.changeArchive(newFile, timer.getTime()); } /** @@ -476,10 +494,9 @@ public abstract class HostStatSampler } /** - * @param timer a NanoTimer used to compute the elapsed delay * @param nanosToDelay the timestamp to delay until it is the current time */ - private void delay(NanoTimer timer, final long nanosToDelay) throws InterruptedException { + private void delay(final long nanosToDelay) throws InterruptedException { timer.reset(); long now = timer.getLastResetTime(); long remainingNanos = nanosToDelay - now; http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/statistics/SampleCollector.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/SampleCollector.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/SampleCollector.java index 610e848..9f1b343 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/statistics/SampleCollector.java +++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/SampleCollector.java @@ -24,6 +24,9 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import edu.umd.cs.findbugs.annotations.SuppressWarnings; + +import org.apache.geode.internal.io.RollingFileHandler; import org.apache.logging.log4j.Logger; import org.apache.geode.GemFireException; @@ -136,15 +139,17 @@ public class SampleCollector { * * @param config defines the configuration for the StatArchiveHandler * @param nanosTimeStamp the nanos time stamp to initialize stat archiver with + * @param rollingFileHandler provides file rolling behavior */ - @edu.umd.cs.findbugs.annotations.SuppressWarnings( - value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", + @SuppressWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "There is never more than one SampleCollector instance.") - public void initialize(StatArchiveHandlerConfig config, long nanosTimeStamp) { + public void initialize(final StatArchiveHandlerConfig config, final long nanosTimeStamp, + final RollingFileHandler rollingFileHandler) { synchronized (SampleCollector.class) { instance = this; synchronized (this.sampleHandlers) { - StatArchiveHandler newStatArchiveHandler = new StatArchiveHandler(config, this); + StatArchiveHandler newStatArchiveHandler = + new StatArchiveHandler(config, this, rollingFileHandler); this.statArchiveHandler = newStatArchiveHandler; addSampleHandler(newStatArchiveHandler); newStatArchiveHandler.initialize(nanosTimeStamp); @@ -366,7 +371,8 @@ public class SampleCollector { } // notify unmarked/new handlers but not marked/old handlers - notifyNewHandlersOfResources(handlers, this.resourceInstMap.values()); + notifyNewHandlersOfResources(handlers, this.resourceTypeMap.values(), + this.resourceInstMap.values()); } private ResourceType getResourceType(List<MarkableSampleHandler> handlers, Statistics statistics) @@ -489,7 +495,7 @@ public class SampleCollector { } private void notifyNewHandlersOfResources(List<MarkableSampleHandler> handlers, - Collection<ResourceInstance> resources) { + Collection<ResourceType> types, Collection<ResourceInstance> resources) { final boolean isDebugEnabled_STATISTICS = logger.isTraceEnabled(LogMarker.STATISTICS); if (isDebugEnabled_STATISTICS) { logger.trace(LogMarker.STATISTICS, @@ -509,6 +515,11 @@ public class SampleCollector { // allocatedResourceInstance... handler.allocatedResourceInstance(resourceInstance); } + for (ResourceType resourceType : types) { + if (!allocatedResourceTypes.contains(resourceType)) { + handler.allocatedResourceType(resourceType); + } + } handler.mark(); count++; } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/statistics/SimpleStatSampler.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/SimpleStatSampler.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/SimpleStatSampler.java index 7eaa1e0..1707397 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/statistics/SimpleStatSampler.java +++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/SimpleStatSampler.java @@ -19,6 +19,7 @@ import java.io.File; import org.apache.logging.log4j.Logger; import org.apache.geode.CancelCriterion; +import org.apache.geode.internal.NanoTimer; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.log4j.LocalizedMessage; @@ -58,7 +59,11 @@ public class SimpleStatSampler extends HostStatSampler { private final StatisticsManager sm; public SimpleStatSampler(CancelCriterion stopper, StatisticsManager sm) { - super(stopper, new StatSamplerStats(sm, sm.getId())); + this(stopper, sm, new NanoTimer()); + } + + public SimpleStatSampler(CancelCriterion stopper, StatisticsManager sm, NanoTimer timer) { + super(stopper, new StatSamplerStats(sm, sm.getId()), timer); this.sm = sm; logger.info(LogMarker.STATISTICS, LocalizedMessage .create(LocalizedStrings.SimpleStatSampler_STATSSAMPLERATE_0, getSampleRate())); http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandler.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandler.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandler.java index 5520936..3eb9730 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandler.java +++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveHandler.java @@ -14,27 +14,25 @@ */ package org.apache.geode.internal.statistics; -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.List; -import java.util.regex.Pattern; - -import org.apache.logging.log4j.Logger; - import org.apache.geode.GemFireException; import org.apache.geode.GemFireIOException; import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.internal.i18n.LocalizedStrings; +import org.apache.geode.internal.io.RollingFileHandler; import org.apache.geode.internal.logging.InternalLogWriter; import org.apache.geode.internal.logging.LogService; -import org.apache.geode.internal.logging.ManagerLogWriter; import org.apache.geode.internal.logging.log4j.LocalizedMessage; import org.apache.geode.internal.logging.log4j.LogMarker; import org.apache.geode.internal.logging.log4j.LogWriterAppender; import org.apache.geode.internal.logging.log4j.LogWriterAppenders; import org.apache.geode.internal.logging.log4j.LogWriterLogger; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; /** * Extracted from {@link HostStatSampler} and {@link GemFireStatSampler}. @@ -56,6 +54,8 @@ public class StatArchiveHandler implements SampleHandler { /** The collector responsible for sample statistics and notifying handlers. */ private final SampleCollector collector; + private final RollingFileHandler rollingFileHandler; + /** * Indicates if archiving has been disabled by specifying empty string for the archive file name. * Other threads may call in to changeArchiveFile to manipulate this flag. @@ -78,9 +78,11 @@ public class StatArchiveHandler implements SampleHandler { * Constructs a new instance. The {@link StatArchiveHandlerConfig} and {@link SampleCollector} * must not be null. */ - public StatArchiveHandler(StatArchiveHandlerConfig config, SampleCollector sampleCollector) { + public StatArchiveHandler(StatArchiveHandlerConfig config, SampleCollector sampleCollector, + RollingFileHandler rollingFileHandler) { this.config = config; this.collector = sampleCollector; + this.rollingFileHandler = rollingFileHandler; } /** @@ -465,13 +467,13 @@ public class StatArchiveHandler implements SampleHandler { if (!archiveDir.exists()) { archiveDir.mkdirs(); } - mainArchiveId = ManagerLogWriter.calcNextMainId(archiveDir, false); + mainArchiveId = this.rollingFileHandler.calcNextMainId(archiveDir, false); mainArchiveIdCalculated = true; } if (mainArchiveId == 0) { mainArchiveId = 1; } - archiveId = ManagerLogWriter.calcNextChildId(archive, mainArchiveId); + archiveId = this.rollingFileHandler.calcNextChildId(archive, mainArchiveId); if (archiveId > 0) { archiveId--; } @@ -482,11 +484,11 @@ public class StatArchiveHandler implements SampleHandler { StringBuffer buf = new StringBuffer(archive.getPath()); int insertIdx = buf.lastIndexOf("."); if (insertIdx == -1) { - buf.append(ManagerLogWriter.formatId(mainArchiveId)) - .append(ManagerLogWriter.formatId(archiveId)); + buf.append(this.rollingFileHandler.formatId(mainArchiveId)) + .append(this.rollingFileHandler.formatId(archiveId)); } else { - buf.insert(insertIdx, ManagerLogWriter.formatId(archiveId)); - buf.insert(insertIdx, ManagerLogWriter.formatId(mainArchiveId)); + buf.insert(insertIdx, this.rollingFileHandler.formatId(archiveId)); + buf.insert(insertIdx, this.rollingFileHandler.formatId(mainArchiveId)); } result = new File(buf.toString()); } while (result.exists()); @@ -499,8 +501,8 @@ public class StatArchiveHandler implements SampleHandler { markerName = markerName.substring(0, dotIdx); } StringBuffer buf = new StringBuffer(markerName); - buf.append(ManagerLogWriter.formatId(mainArchiveId)).append(ManagerLogWriter.formatId(0)) - .append(".marker"); + buf.append(this.rollingFileHandler.formatId(mainArchiveId)) + .append(this.rollingFileHandler.formatId(0)).append(".marker"); File marker = new File(buf.toString()); if (marker.exists()) { if (!marker.delete()) { @@ -520,8 +522,8 @@ public class StatArchiveHandler implements SampleHandler { markerName = markerName.substring(0, dotIdx); } StringBuffer buf = new StringBuffer(markerName); - buf.append(ManagerLogWriter.formatId(mainArchiveId)).append(ManagerLogWriter.formatId(0)) - .append(".marker"); + buf.append(this.rollingFileHandler.formatId(mainArchiveId)) + .append(this.rollingFileHandler.formatId(0)).append(".marker"); File marker = new File(buf.toString()); if (!marker.exists()) { try { @@ -555,7 +557,7 @@ public class StatArchiveHandler implements SampleHandler { if (!archiveDir.exists()) { archiveDir.mkdirs(); } - mainArchiveId = ManagerLogWriter.calcNextMainId(archiveDir, false); + mainArchiveId = this.rollingFileHandler.calcNextMainId(archiveDir, false); mainArchiveId++; mainArchiveIdCalculated = true; } @@ -572,8 +574,8 @@ public class StatArchiveHandler implements SampleHandler { markerName = markerName.substring(0, dotIdx); } StringBuffer buf = new StringBuffer(markerName); - buf.append(ManagerLogWriter.formatId(mainArchiveId)).append(ManagerLogWriter.formatId(0)) - .append(".marker"); + buf.append(this.rollingFileHandler.formatId(mainArchiveId)) + .append(this.rollingFileHandler.formatId(0)).append(".marker"); File marker = new File(buf.toString()); if (!marker.exists()) { try { @@ -596,9 +598,9 @@ public class StatArchiveHandler implements SampleHandler { * @return the modified archive file name to use; it is modified by applying the next main id if * any files in the dir already have a main id in the file name */ - private static File getRenameArchiveName(File archive) { + private File getRenameArchiveName(File archive) { File dir = archive.getAbsoluteFile().getParentFile(); - int previousMainId = ManagerLogWriter.calcNextMainId(dir, false); + int previousMainId = this.rollingFileHandler.calcNextMainId(dir, false); if (previousMainId == 0) { previousMainId = 1; } @@ -609,10 +611,11 @@ public class StatArchiveHandler implements SampleHandler { StringBuffer buf = new StringBuffer(archive.getPath()); int insertIdx = buf.lastIndexOf("."); if (insertIdx == -1) { - buf.append(ManagerLogWriter.formatId(previousMainId)).append(ManagerLogWriter.formatId(1)); + buf.append(this.rollingFileHandler.formatId(previousMainId)) + .append(this.rollingFileHandler.formatId(1)); } else { - buf.insert(insertIdx, ManagerLogWriter.formatId(1)); - buf.insert(insertIdx, ManagerLogWriter.formatId(previousMainId)); + buf.insert(insertIdx, this.rollingFileHandler.formatId(1)); + buf.insert(insertIdx, this.rollingFileHandler.formatId(previousMainId)); } result = new File(buf.toString()); } while (result.exists()); @@ -621,52 +624,26 @@ public class StatArchiveHandler implements SampleHandler { /** * Remove old versions of the specified archive file name in order to stay under the specified - * disk space limit. Old versions of the archive file are those that match based on using - * {@link #getArchivePattern(String)} which ignores mainArchiveId and archiveId. + * disk space limit. Old versions of the archive file are those that match based on using a + * pattern which ignores mainArchiveId and archiveId. * * @param archiveFile the archive file to remove old versions of * @param spaceLimit the disk space limit */ - private static void removeOldArchives(File archiveFile, long spaceLimit) { + private void removeOldArchives(File archiveFile, long spaceLimit) { if (spaceLimit == 0 || archiveFile == null || archiveFile.getPath().equals("")) { return; } File archiveDir = archiveFile.getAbsoluteFile().getParentFile(); - ManagerLogWriter.checkDiskSpace("archive", archiveFile, spaceLimit, archiveDir, - getArchivePattern(archiveFile.getName()), getOrCreateLogWriter()); + this.rollingFileHandler.checkDiskSpace("archive", archiveFile, spaceLimit, archiveDir, + getOrCreateLogWriter()); } - private static InternalLogWriter getOrCreateLogWriter() { + private InternalLogWriter getOrCreateLogWriter() { InternalLogWriter lw = InternalDistributedSystem.getStaticInternalLogWriter(); if (lw == null) { lw = LogWriterLogger.create(logger); } return lw; } - - /** - * Create a regex pattern which will match the specified archive file name even if it has a - * mainArchiveId and/or archiveId. - * - * @param name archive file name to create a regex pattern for - * @return regex pattern to use in finding matching file names - */ - private static Pattern getArchivePattern(String name) { - String ext = ""; - - int extIdx = name.lastIndexOf('.'); - if (extIdx != -1) { - ext = "\\Q" + name.substring(extIdx) + "\\E"; - name = name.substring(0, extIdx); - } - - /* name may have -DD-DD on the end of it. Trim that part off. */ - int dashIdx = name.indexOf('-'); - if (dashIdx != -1) { - name = name.substring(0, dashIdx); - } - - name = "\\Q" + name + "\\E" + "-\\d+-\\d+" + ext; - return Pattern.compile(name); - } } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveWriter.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveWriter.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveWriter.java index a4c15d1..4eabe3b 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveWriter.java +++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveWriter.java @@ -19,16 +19,28 @@ import org.apache.geode.InternalGemFireException; import org.apache.geode.StatisticDescriptor; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.internal.NanoTimer; -import org.apache.geode.internal.net.SocketCreator; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.logging.log4j.LogMarker; - +import org.apache.geode.internal.net.SocketCreator; import org.apache.logging.log4j.Logger; -import java.io.*; +import java.io.BufferedOutputStream; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; import java.net.UnknownHostException; -import java.util.*; +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TimeZone; import java.util.zip.GZIPOutputStream; /** http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/statistics/StatMonitorHandler.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatMonitorHandler.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatMonitorHandler.java index a2b0ae4..0c9583e 100755 --- a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatMonitorHandler.java +++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatMonitorHandler.java @@ -32,9 +32,10 @@ public class StatMonitorHandler implements SampleHandler { private static final Logger logger = LogService.getLogger(); - static final String ENABLE_MONITOR_THREAD = + protected static final String ENABLE_MONITOR_THREAD = DistributionConfig.GEMFIRE_PREFIX + "stats.enableMonitorThread"; - static final boolean enableMonitorThread = Boolean.getBoolean(ENABLE_MONITOR_THREAD); + + private final boolean enableMonitorThread; /** The registered monitors */ private volatile List<StatisticsMonitor> monitors = Collections.<StatisticsMonitor>emptyList(); @@ -43,7 +44,9 @@ public class StatMonitorHandler implements SampleHandler { private volatile StatMonitorNotifier notifier; /** Constructs a new StatMonitorHandler instance */ - public StatMonitorHandler() {} + public StatMonitorHandler() { + this.enableMonitorThread = Boolean.getBoolean(ENABLE_MONITOR_THREAD); + } /** Adds a monitor which will be notified of samples */ public boolean addMonitor(StatisticsMonitor monitor) { @@ -55,9 +58,8 @@ public class StatMonitorHandler implements SampleHandler { added = newMonitors.add(monitor); this.monitors = Collections.unmodifiableList(newMonitors); } - if (enableMonitorThread && !this.monitors.isEmpty() && this.notifier == null) { - this.notifier = new StatMonitorNotifier(); - this.notifier.start(); + if (!this.monitors.isEmpty()) { + startNotifier_IfEnabledAndNotRunning(); } return added; } @@ -73,9 +75,8 @@ public class StatMonitorHandler implements SampleHandler { removed = newMonitors.remove(monitor); this.monitors = Collections.unmodifiableList(newMonitors); } - if (enableMonitorThread && this.monitors.isEmpty() && this.notifier != null) { - this.notifier.stop(); - this.notifier = null; + if (this.monitors.isEmpty()) { + stopNotifier_IfEnabledAndRunning(); } return removed; } @@ -86,16 +87,14 @@ public class StatMonitorHandler implements SampleHandler { */ public void close() { synchronized (this) { - if (enableMonitorThread && this.notifier != null) { - this.notifier.stop(); - } + stopNotifier_IfEnabledAndRunning(); } } @Override public void sampled(long nanosTimeStamp, List<ResourceInstance> resourceInstances) { synchronized (this) { - if (enableMonitorThread) { + if (this.enableMonitorThread) { final StatMonitorNotifier thread = this.notifier; if (thread != null) { try { @@ -150,6 +149,20 @@ public class StatMonitorHandler implements SampleHandler { } } + private void startNotifier_IfEnabledAndNotRunning() { + if (this.enableMonitorThread && this.notifier == null) { + this.notifier = new StatMonitorNotifier(); + this.notifier.start(); + } + } + + private void stopNotifier_IfEnabledAndRunning() { + if (this.enableMonitorThread && this.notifier != null) { + this.notifier.stop(); + this.notifier = null; + } + } + /** * @since GemFire 7.0 */ http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/main/java/org/apache/geode/internal/util/concurrent/StoppableCountDownLatch.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/util/concurrent/StoppableCountDownLatch.java b/geode-core/src/main/java/org/apache/geode/internal/util/concurrent/StoppableCountDownLatch.java index 740fd7f..4726e51 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/util/concurrent/StoppableCountDownLatch.java +++ b/geode-core/src/main/java/org/apache/geode/internal/util/concurrent/StoppableCountDownLatch.java @@ -46,6 +46,7 @@ public class StoppableCountDownLatch { /** * @param count the number of times {@link #countDown} must be invoked before threads can pass * through {@link #await()} + * * @throws IllegalArgumentException if {@code count} is negative */ public StoppableCountDownLatch(CancelCriterion stopper, int count) { @@ -68,14 +69,19 @@ public class StoppableCountDownLatch { /** * @param msTimeout how long to wait in milliseconds + * * @return true if it was unlatched - * @throws InterruptedException */ public boolean await(long msTimeout) throws InterruptedException { stopper.checkCancelInProgress(null); return latch.await(msTimeout, TimeUnit.MILLISECONDS); } + public boolean await(final long timeout, final TimeUnit unit) throws InterruptedException { + stopper.checkCancelInProgress(null); + return latch.await(timeout, unit); + } + public synchronized void countDown() { latch.countDown(); } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/test/java/org/apache/geode/internal/statistics/DiskSpaceLimitIntegrationTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/statistics/DiskSpaceLimitIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/statistics/DiskSpaceLimitIntegrationTest.java new file mode 100644 index 0000000..2381a53 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/statistics/DiskSpaceLimitIntegrationTest.java @@ -0,0 +1,201 @@ +/* + * 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.statistics; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.apache.commons.io.FileUtils.moveFileToDirectory; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.geode.StatisticDescriptor; +import org.apache.geode.Statistics; +import org.apache.geode.StatisticsType; +import org.apache.geode.internal.NanoTimer; +import org.apache.geode.internal.io.MainWithChildrenRollingFileHandler; +import org.apache.geode.internal.io.RollingFileHandler; +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +@Category(IntegrationTest.class) +public class DiskSpaceLimitIntegrationTest { + + private static final long FILE_SIZE_LIMIT = 256; + private static final long DISK_SPACE_LIMIT = FILE_SIZE_LIMIT * 2; + + private File dir; + private File dirOfDeletedFiles; + + private String archiveFileName; + + private LocalStatisticsFactory factory; + private StatisticDescriptor[] statisticDescriptors; + private StatisticsType statisticsType; + private Statistics statistics; + + private SampleCollector sampleCollector; + private StatArchiveHandlerConfig config; + + private NanoTimer timer = new NanoTimer(); + private long nanosTimeStamp; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Rule + public TestName testName = new TestName(); + + @Before + public void setUp() throws Exception { + this.dir = this.temporaryFolder.getRoot(); + this.dirOfDeletedFiles = this.temporaryFolder.newFolder("deleted"); + + this.archiveFileName = + new File(this.dir, this.testName.getMethodName() + ".gfs").getAbsolutePath(); + + this.factory = new LocalStatisticsFactory(null); + this.statisticDescriptors = new StatisticDescriptor[] { + this.factory.createIntCounter("stat1", "description of stat1", "units", true)}; + this.statisticsType = + factory.createType("statisticsType1", "statisticsType1", this.statisticDescriptors); + this.statistics = factory.createAtomicStatistics(this.statisticsType, "statistics1", 1); + + StatisticsSampler sampler = mock(StatisticsSampler.class); + when(sampler.getStatistics()).thenReturn(this.factory.getStatistics()); + + this.config = mock(StatArchiveHandlerConfig.class); + when(this.config.getArchiveFileName()).thenReturn(new File(this.archiveFileName)); + when(this.config.getArchiveFileSizeLimit()).thenReturn(FILE_SIZE_LIMIT); + when(this.config.getSystemId()).thenReturn(1L); + when(this.config.getSystemStartTime()).thenReturn(System.currentTimeMillis()); + when(this.config.getSystemDirectoryPath()) + .thenReturn(this.temporaryFolder.getRoot().getAbsolutePath()); + when(this.config.getProductDescription()).thenReturn(this.testName.getMethodName()); + + RollingFileHandler rollingFileHandler = new TestableRollingFileHandler(); + + this.sampleCollector = new SampleCollector(sampler); + this.sampleCollector.initialize(this.config, NanoTimer.getTime(), rollingFileHandler); + + this.timer.reset(); + this.nanosTimeStamp = this.timer.getLastResetTime() - getNanoRate(); + } + + @After + public void tearDown() throws Exception { + StatisticsTypeFactoryImpl.clear(); + } + + @Test + public void zeroKeepsAllFiles() throws Exception { + when(this.config.getArchiveDiskSpaceLimit()).thenReturn(0L); + sampleUntilFileExists(archiveFile(1)); + sampleUntilFileExists(archiveFile(2)); + assertThat(archiveFile(1)).exists(); + assertThat(archiveFile(2)).exists(); + } + + @Test + public void sameKeepsOneFile() throws Exception { + when(this.config.getArchiveDiskSpaceLimit()).thenReturn(DISK_SPACE_LIMIT); + sampleUntilFileExists(archiveFile(1)); + sampleUntilFileExists(archiveFile(2)); + assertThat(archiveFile(1)).doesNotExist(); + assertThat(archiveFile(2)).exists(); + assertThat(everExisted(archiveFile(1))).isTrue(); + } + + private void sampleUntilFileExists(final File file) + throws InterruptedException, TimeoutException { + long minutes = 1; + long timeout = System.nanoTime() + MINUTES.toNanos(minutes); + int count = 0; + do { + sample(advanceNanosTimeStamp()); + count++; + Thread.sleep(10); + } while (!everExisted(file) && System.nanoTime() < timeout); + if (!everExisted(file)) { + throw new TimeoutException("File " + file + " does not exist after " + count + + " samples within " + minutes + " " + MINUTES); + } + System.out.println("Sampled " + count + " times to create " + file); + } + + private boolean everExisted(final File file) { + if (file.exists()) { + return true; + } else { // check dirOfDeletedFiles + String name = file.getName(); + File deleted = new File(this.dirOfDeletedFiles, name); + return deleted.exists(); + } + } + + private void sample(final long time) { + getSampleCollector().sample(time); + } + + private SampleCollector getSampleCollector() { + return this.sampleCollector; + } + + private long advanceNanosTimeStamp() { + this.nanosTimeStamp += getNanoRate(); + return this.nanosTimeStamp; + } + + private long getNanoRate() { + return NanoTimer.millisToNanos(getSampleRate()); + } + + private long getSampleRate() { + return 1000; // 1 second + } + + private File archiveFile(final int child) { + return new File(this.dir, + this.testName.getMethodName() + "-01-" + String.format("%02d", child) + ".gfs"); + } + + private File archiveFile() { + return new File(this.archiveFileName); + } + + /** + * Override protected method to move file instead of deleting it. + */ + private class TestableRollingFileHandler extends MainWithChildrenRollingFileHandler { + @Override + protected boolean delete(final File file) { + try { + moveFileToDirectory(file, dirOfDeletedFiles, false); + return true; + } catch (IOException e) { + throw new Error(e); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/test/java/org/apache/geode/internal/statistics/FileSizeLimitIntegrationTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/statistics/FileSizeLimitIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/statistics/FileSizeLimitIntegrationTest.java new file mode 100644 index 0000000..1538862 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/statistics/FileSizeLimitIntegrationTest.java @@ -0,0 +1,170 @@ +/* + * 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.statistics; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.geode.StatisticDescriptor; +import org.apache.geode.Statistics; +import org.apache.geode.StatisticsType; +import org.apache.geode.internal.NanoTimer; +import org.apache.geode.internal.io.MainWithChildrenRollingFileHandler; +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestName; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.File; +import java.util.concurrent.TimeoutException; + +@Category(IntegrationTest.class) +public class FileSizeLimitIntegrationTest { + + private static final long FILE_SIZE_LIMIT = 1; + + private File dir; + private String archiveFileName; + + private LocalStatisticsFactory factory; + private StatisticDescriptor[] statisticDescriptors; + private StatisticsType statisticsType; + private Statistics statistics; + + private SampleCollector sampleCollector; + + private NanoTimer timer = new NanoTimer(); + private long nanosTimeStamp; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Rule + public TestName testName = new TestName(); + + @Before + public void setUp() throws Exception { + this.dir = this.temporaryFolder.getRoot(); + this.archiveFileName = + new File(this.dir, this.testName.getMethodName() + ".gfs").getAbsolutePath(); + + this.factory = new LocalStatisticsFactory(null); + this.statisticDescriptors = new StatisticDescriptor[] { + this.factory.createIntCounter("stat1", "description of stat1", "units", true)}; + this.statisticsType = + factory.createType("statisticsType1", "statisticsType1", this.statisticDescriptors); + this.statistics = factory.createAtomicStatistics(this.statisticsType, "statistics1", 1); + + Answer<Statistics[]> statisticsAnswer = new Answer<Statistics[]>() { + public Statistics[] answer(InvocationOnMock invocation) throws Throwable { + return factory.getStatistics(); + } + }; + + Answer<Integer> modCountAnswer = new Answer<Integer>() { + public Integer answer(InvocationOnMock invocation) throws Throwable { + return factory.getStatListModCount(); + } + }; + + StatisticsSampler sampler = mock(StatisticsSampler.class); + when(sampler.getStatistics()).thenAnswer(statisticsAnswer); + when(sampler.getStatisticsModCount()).thenAnswer(modCountAnswer); + + StatArchiveHandlerConfig config = mock(StatArchiveHandlerConfig.class); + when(config.getArchiveFileName()).thenReturn(new File(this.archiveFileName)); + when(config.getArchiveFileSizeLimit()).thenReturn(FILE_SIZE_LIMIT); + when(config.getSystemId()).thenReturn(1L); + when(config.getSystemStartTime()).thenReturn(System.currentTimeMillis()); + when(config.getSystemDirectoryPath()) + .thenReturn(this.temporaryFolder.getRoot().getAbsolutePath()); + when(config.getProductDescription()).thenReturn(this.testName.getMethodName()); + when(config.getArchiveDiskSpaceLimit()).thenReturn(0L); + + this.sampleCollector = new SampleCollector(sampler); + this.sampleCollector.initialize(config, this.timer.getTime(), + new MainWithChildrenRollingFileHandler()); + + this.timer.reset(); + this.nanosTimeStamp = this.timer.getLastResetTime() - getNanoRate(); + } + + @After + public void tearDown() throws Exception { + StatisticsTypeFactoryImpl.clear(); + } + + @Test + public void rollsWhenLimitIsReached() throws Exception { // TODO: add test to assert size is + // correct + sampleUntilFileExists(archiveFile(1)); + sampleUntilFileExists(archiveFile(2)); + assertThat(archiveFile(1)).exists(); + assertThat(archiveFile(2)).exists(); + } + + private void sampleUntilFileExists(final File file) + throws InterruptedException, TimeoutException { + long timeout = System.nanoTime() + MINUTES.toNanos(1); + int count = 0; + do { + sample(advanceNanosTimeStamp()); + count++; + Thread.sleep(10); + } while (!file.exists() && System.nanoTime() < timeout); + if (!file.exists()) { + throw new TimeoutException("File " + file + " does not exist after " + count + + " samples within " + 1 + " " + MINUTES); + } + System.out.println("Sampled " + count + " times to create " + file); + } + + private void sample(final long time) { + getSampleCollector().sample(time); + } + + private SampleCollector getSampleCollector() { + return this.sampleCollector; + } + + private long advanceNanosTimeStamp() { + this.nanosTimeStamp += getNanoRate(); + return this.nanosTimeStamp; + } + + private long getNanoRate() { + return NanoTimer.millisToNanos(getSampleRate()); + } + + private long getSampleRate() { + return 1000; // 1 second + } + + private File archiveFile(final int child) { + return new File(this.dir, + this.testName.getMethodName() + "-01-" + String.format("%02d", child) + ".gfs"); + } + + private File archiveFile() { + return new File(this.archiveFileName); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/test/java/org/apache/geode/internal/statistics/SampleCollectorTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/statistics/SampleCollectorTest.java b/geode-core/src/test/java/org/apache/geode/internal/statistics/SampleCollectorTest.java index ab84ea4..718f744 100755 --- a/geode-core/src/test/java/org/apache/geode/internal/statistics/SampleCollectorTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/statistics/SampleCollectorTest.java @@ -20,6 +20,7 @@ import static org.mockito.Mockito.*; import java.io.File; import java.util.List; +import org.apache.geode.internal.io.MainWithChildrenRollingFileHandler; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -65,7 +66,8 @@ public class SampleCollectorTest { final StatisticsSampler sampler = new TestStatisticsSampler(manager); this.sampleCollector = new SampleCollector(sampler); - this.sampleCollector.initialize(mockStatArchiveHandlerConfig, NanoTimer.getTime()); + this.sampleCollector.initialize(mockStatArchiveHandlerConfig, NanoTimer.getTime(), + new MainWithChildrenRollingFileHandler()); } @After http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/test/java/org/apache/geode/internal/statistics/StatMonitorHandlerTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/statistics/StatMonitorHandlerTest.java b/geode-core/src/test/java/org/apache/geode/internal/statistics/StatMonitorHandlerTest.java index 85e6f6d..782944a 100755 --- a/geode-core/src/test/java/org/apache/geode/internal/statistics/StatMonitorHandlerTest.java +++ b/geode-core/src/test/java/org/apache/geode/internal/statistics/StatMonitorHandlerTest.java @@ -14,20 +14,20 @@ */ package org.apache.geode.internal.statistics; -import static org.junit.Assert.*; -import static org.junit.Assume.*; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.junit.Test; -import org.junit.experimental.categories.Category; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import org.apache.geode.internal.NanoTimer; -import org.apache.geode.internal.statistics.StatMonitorHandler.StatMonitorNotifier; import org.apache.geode.internal.util.StopWatch; import org.apache.geode.test.junit.categories.UnitTest; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * Unit tests for {@link StatMonitorHandler}. @@ -140,56 +140,6 @@ public class StatMonitorHandlerTest { } } - @Test - public void testStatMonitorNotifierAliveButWaiting() throws Exception { - assumeTrue(StatMonitorHandler.enableMonitorThread); - StatMonitorHandler handler = new StatMonitorHandler(); - TestStatisticsMonitor monitor = new TestStatisticsMonitor(); - handler.addMonitor(monitor); - - final StatMonitorNotifier notifier = handler.getStatMonitorNotifier(); - assertTrue(notifier.isAlive()); - - waitUntilWaiting(notifier); - - for (int i = 0; i < 20; i++) { - assert (notifier.isWaiting()); - Thread.sleep(10); - } - } - - @Test - public void testStatMonitorNotifierWakesUpForWork() throws Exception { - assumeTrue(StatMonitorHandler.enableMonitorThread); - StatMonitorHandler handler = new StatMonitorHandler(); - TestStatisticsMonitor monitor = new TestStatisticsMonitor(); - handler.addMonitor(monitor); - - final StatMonitorNotifier notifier = handler.getStatMonitorNotifier(); - assertTrue(notifier.isAlive()); - - waitUntilWaiting(notifier); - - // if notification occurs then notifier woke up... - assertEquals(0, monitor.getNotificationCount()); - handler.sampled(NanoTimer.getTime(), Collections.<ResourceInstance>emptyList()); - - waitForNotificationCount(monitor, 1, 2 * 1000, 10, false); - assertEquals(1, monitor.getNotificationCount()); - - // and goes back to waiting... - waitUntilWaiting(notifier); - } - - private static void waitUntilWaiting(StatMonitorNotifier notifier) throws InterruptedException { - boolean done = false; - for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < 2000; done = - (notifier.isWaiting())) { - Thread.sleep(10); - } - assertTrue("waiting for notifier to be waiting", done); - } - private static void waitForNotificationCount(final TestStatisticsMonitor monitor, final int expected, long ms, long interval, boolean throwOnTimeout) throws InterruptedException { http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3bdd1049/geode-core/src/test/java/org/apache/geode/internal/statistics/StatMonitorHandlerWithEnabledMonitorThreadTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/statistics/StatMonitorHandlerWithEnabledMonitorThreadTest.java b/geode-core/src/test/java/org/apache/geode/internal/statistics/StatMonitorHandlerWithEnabledMonitorThreadTest.java new file mode 100644 index 0000000..a08fa43 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/statistics/StatMonitorHandlerWithEnabledMonitorThreadTest.java @@ -0,0 +1,140 @@ +/* + * 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.statistics; + +import static org.apache.geode.internal.statistics.StatMonitorHandler.ENABLE_MONITOR_THREAD; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.geode.internal.NanoTimer; +import org.apache.geode.internal.statistics.StatMonitorHandler.StatMonitorNotifier; +import org.apache.geode.internal.util.StopWatch; +import org.apache.geode.test.junit.categories.UnitTest; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.experimental.categories.Category; + +import java.util.Collections; +import java.util.List; + +/** + * Extracted tests from StatMonitorHandlerTest that require enableMonitorThread + */ +@Category(UnitTest.class) +public class StatMonitorHandlerWithEnabledMonitorThreadTest { + + @Rule + public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + + @Before + public void before() throws Exception { + System.setProperty(ENABLE_MONITOR_THREAD, "true"); + } + + @Test + public void testStatMonitorNotifierAliveButWaiting() throws Exception { + StatMonitorHandler handler = new StatMonitorHandler(); + TestStatisticsMonitor monitor = new TestStatisticsMonitor(); + handler.addMonitor(monitor); + + final StatMonitorNotifier notifier = handler.getStatMonitorNotifier(); + assertTrue(notifier.isAlive()); + + waitUntilWaiting(notifier); + + for (int i = 0; i < 20; i++) { + assertTrue(notifier.isWaiting()); + Thread.sleep(10); + } + } + + @Test + public void testStatMonitorNotifierWakesUpForWork() throws Exception { + StatMonitorHandler handler = new StatMonitorHandler(); + TestStatisticsMonitor monitor = new TestStatisticsMonitor(); + handler.addMonitor(monitor); + + final StatMonitorNotifier notifier = handler.getStatMonitorNotifier(); + assertTrue(notifier.isAlive()); + + waitUntilWaiting(notifier); + + // if notification occurs then notifier woke up... + assertEquals(0, monitor.getNotificationCount()); + handler.sampled(NanoTimer.getTime(), Collections.<ResourceInstance>emptyList()); + + waitForNotificationCount(monitor, 1, 2 * 1000, 10, false); + assertEquals(1, monitor.getNotificationCount()); + + // and goes back to waiting... + waitUntilWaiting(notifier); + } + + private static void waitUntilWaiting(StatMonitorNotifier notifier) throws InterruptedException { + boolean done = false; + for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < 2000; done = + (notifier.isWaiting())) { + Thread.sleep(10); + } + assertTrue("waiting for notifier to be waiting", done); + } + + private static void waitForNotificationCount(final TestStatisticsMonitor monitor, + final int expected, final long ms, final long interval, final boolean throwOnTimeout) + throws InterruptedException { + boolean done = false; + for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < ms; done = + (monitor.getNotificationCount() >= expected)) { + Thread.sleep(interval); + } + if (throwOnTimeout) { + assertTrue("waiting for notification count to be " + expected, done); + } + } + + /** + * @since GemFire 7.0 + */ + private static class TestStatisticsMonitor extends StatisticsMonitor { + private volatile long timeStamp; + private volatile List<ResourceInstance> resourceInstances; + private volatile int notificationCount; + + public TestStatisticsMonitor() { + super(); + } + + @Override + protected void monitor(long timeStamp, List<ResourceInstance> resourceInstances) { + this.timeStamp = timeStamp; + this.resourceInstances = resourceInstances; + this.notificationCount++; + } + + long getTimeStamp() { + return this.timeStamp; + } + + List<ResourceInstance> getResourceInstances() { + return this.resourceInstances; + } + + int getNotificationCount() { + return this.notificationCount; + } + } +}
