geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kl...@apache.org
Subject [12/23] incubator-geode git commit: GEODE-1781: repackage internal statistics classes and refactor statistics tests
Date Mon, 15 Aug 2016 18:43:40 GMT
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/866bacec/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatArchiveWriter.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatArchiveWriter.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatArchiveWriter.java
new file mode 100644
index 0000000..027bde1
--- /dev/null
+++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatArchiveWriter.java
@@ -0,0 +1,732 @@
+/*
+ * 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 com.gemstone.gemfire.internal.statistics;
+
+import com.gemstone.gemfire.GemFireIOException;
+import com.gemstone.gemfire.InternalGemFireException;
+import com.gemstone.gemfire.StatisticDescriptor;
+import com.gemstone.gemfire.distributed.internal.DistributionConfig;
+import com.gemstone.gemfire.internal.NanoTimer;
+import com.gemstone.gemfire.internal.SocketCreator;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+import com.gemstone.gemfire.internal.logging.LogService;
+import com.gemstone.gemfire.internal.logging.log4j.LogMarker;
+
+import org.apache.logging.log4j.Logger;
+
+import java.io.*;
+import java.net.UnknownHostException;
+import java.util.*;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * StatArchiveWriter provides APIs to write statistic snapshots to an archive
+ * file.
+ *
+ */
+public class StatArchiveWriter implements StatArchiveFormat, SampleHandler {
+
+  private static final Logger logger = LogService.getLogger();
+  
+  private static volatile String traceStatisticsName = null;
+  private static volatile String traceStatisticsTypeName = null;
+  private static volatile int traceResourceInstId = -1;
+
+  private final boolean trace = Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "stats.debug.traceStatArchiveWriter");
+  
+  private final Set<ResourceInstance> sampleWrittenForResources = 
+      new HashSet<ResourceInstance>();
+  private final Set<ResourceInstance> addedResources = 
+      new HashSet<ResourceInstance>();
+  private final StatArchiveDescriptor archiveDescriptor;
+  private long initialDate;
+  private final OutputStream outStream;
+  private final MyDataOutputStream dataOut;
+  private final OutputStream traceOutStream;
+  private final PrintStream traceDataOut;
+  private long previousMillisTimeStamp;
+  private int sampleCount;
+  
+  /**
+   * Opens a StatArchiveWriter that will archive to the specified file.
+   * @throws GemFireIOException if <code>archiveName</code> can not be written to
+   */
+  public StatArchiveWriter(StatArchiveDescriptor archiveDescriptor) {
+    this.archiveDescriptor = archiveDescriptor;
+    
+    if (archiveDescriptor.getArchiveName().endsWith(".gz")) {
+      try {
+        this.outStream = new GZIPOutputStream(new FileOutputStream(archiveDescriptor.getArchiveName()), 32768);
+      } catch (IOException ex) {
+        throw new GemFireIOException(LocalizedStrings.StatArchiveWriter_COULD_NOT_OPEN_0.toLocalizedString(archiveDescriptor.getArchiveName()), ex);
+      }
+    } else {
+      try {
+        this.outStream = new BufferedOutputStream(new FileOutputStream(archiveDescriptor.getArchiveName()), 32768);
+      } catch (IOException ex) {
+        throw new GemFireIOException(LocalizedStrings.StatArchiveWriter_COULD_NOT_OPEN_0.toLocalizedString(archiveDescriptor.getArchiveName()), ex);
+      }
+    }
+
+    this.dataOut = new MyDataOutputStream(this.outStream);
+    
+    if (this.trace) {
+      String traceFileName = archiveDescriptor.getArchiveName() + ".trace";
+      try {
+        this.traceOutStream = new BufferedOutputStream(new FileOutputStream(traceFileName), 32768);
+      } catch (IOException ex) {
+        throw new GemFireIOException("Could not open " + traceFileName, ex);
+      }
+      this.traceDataOut = new PrintStream(this.traceOutStream);
+    } else {
+      this.traceOutStream = null;
+      this.traceDataOut = null;
+    }
+  }
+
+  public String getArchiveName() {
+    return this.archiveDescriptor.getArchiveName();
+  }
+  
+  public void initialize(long nanosTimeStamp) {
+    this.previousMillisTimeStamp = initPreviousMillisTimeStamp(nanosTimeStamp);
+    this.initialDate = initInitialDate();
+    writeHeader(this.initialDate, this.archiveDescriptor);
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder(getClass().getName());
+    sb.append("@").append(System.identityHashCode(this)).append("{");
+    sb.append("archiveName=").append(this.archiveDescriptor.getArchiveName());
+    sb.append("productDescription=").append(this.archiveDescriptor.getProductDescription());
+    sb.append("systemDirectoryPath=").append(this.archiveDescriptor.getSystemDirectoryPath());
+    sb.append("systemId=").append(this.archiveDescriptor.getSystemId());
+    sb.append("systemStartTime=").append(this.archiveDescriptor.getSystemStartTime());
+    sb.append("previousMillisTimeStamp=").append(this.previousMillisTimeStamp);
+    sb.append("initialDate=").append(this.initialDate);
+    return sb.toString();
+  }
+  
+  /**
+   * Closes the statArchiver by flushing its data to disk a closing its output stream.
+   * @throws GemFireIOException if the archive file could not be closed.
+   */
+  public final void close() {
+    try {
+      this.dataOut.flush();
+      if (this.trace) {
+        this.traceDataOut.flush();
+      }
+    } catch (IOException ignore) {
+    }
+    try {
+      outStream.close();
+      if (this.trace) {
+        this.traceOutStream.close();
+      }
+    } catch (IOException ex) {
+      throw new GemFireIOException(LocalizedStrings.StatArchiveWriter_COULD_NOT_CLOSE_STATARCHIVER_FILE.toLocalizedString(), ex);
+    }
+    if (getSampleCount() == 0) {
+      // If we are closing an empty file go ahead and delete it.
+      // This prevents the fix for 46917 from leaving a bunch of
+      // empty gfs files around.
+      deleteFileIfPossible(new File(getArchiveName()));
+    }
+  }
+  
+  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE", justification="Best effort attempt to delete a GFS file without any samples.") 
+  private static void deleteFileIfPossible(File file) {
+    file.delete();
+  }
+
+  /**
+   * Returns the number of bytes written so far to this archive.
+   * This does not take compression into account.
+   */
+  public final long bytesWritten() {
+    return this.dataOut.getBytesWritten();
+  }
+
+  protected long initPreviousMillisTimeStamp(long nanosTimeStamp) {
+    return NanoTimer.nanosToMillis(nanosTimeStamp);
+  }
+  
+  protected long initInitialDate() {
+    return System.currentTimeMillis();
+  }
+  
+  protected TimeZone getTimeZone() {
+    return Calendar.getInstance().getTimeZone();
+  }
+  
+  protected String getOSInfo() {
+    return System.getProperty("os.name") + " " + System.getProperty("os.version");
+  }
+  
+  protected String getMachineInfo() {
+    String machineInfo = System.getProperty("os.arch");
+    try {
+      String hostName = SocketCreator.getHostName(SocketCreator.getLocalHost());
+      machineInfo += " " + hostName;
+    } catch (UnknownHostException ignore) {
+    }
+    return machineInfo;
+  }
+  
+  private void writeHeader(long initialDate, StatArchiveDescriptor archiveDescriptor) {
+    if (logger.isTraceEnabled(LogMarker.STATISTICS)) {
+      logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#writeHeader initialDate={} archiveDescriptor={}", initialDate, archiveDescriptor);
+    }
+    try {
+      this.dataOut.writeByte(HEADER_TOKEN);
+      this.dataOut.writeByte(ARCHIVE_VERSION);
+      this.dataOut.writeLong(initialDate);
+      this.dataOut.writeLong(archiveDescriptor.getSystemId());
+      this.dataOut.writeLong(archiveDescriptor.getSystemStartTime());
+      TimeZone timeZone = getTimeZone();
+      this.dataOut.writeInt(timeZone.getRawOffset());
+      this.dataOut.writeUTF(timeZone.getID());
+      this.dataOut.writeUTF(archiveDescriptor.getSystemDirectoryPath());
+      this.dataOut.writeUTF(archiveDescriptor.getProductDescription());
+      this.dataOut.writeUTF(getOSInfo());
+      this.dataOut.writeUTF(getMachineInfo());
+      
+      if (this.trace) {
+        this.traceDataOut.println("writeHeader traceStatisticsName: " + traceStatisticsName);
+        this.traceDataOut.println("writeHeader traceStatisticsTypeName: " + traceStatisticsTypeName);
+        this.traceDataOut.println("writeHeader#writeByte HEADER_TOKEN: " + HEADER_TOKEN);
+        this.traceDataOut.println("writeHeader#writeByte ARCHIVE_VERSION: " + ARCHIVE_VERSION);
+        this.traceDataOut.println("writeHeader#writeLong initialDate: " + initialDate);
+        this.traceDataOut.println("writeHeader#writeLong archiveDescriptor.getSystemId(): " + archiveDescriptor.getSystemId());
+        this.traceDataOut.println("writeHeader#writeLong archiveDescriptor.getSystemStartTime(): " + archiveDescriptor.getSystemStartTime());
+        this.traceDataOut.println("writeHeader#writeInt timeZone.getRawOffset(): " + timeZone.getRawOffset());
+        this.traceDataOut.println("writeHeader#writeUTF timeZone.getID(): " + timeZone.getID());
+        this.traceDataOut.println("writeHeader#writeUTF archiveDescriptor.getSystemDirectoryPath(): " + archiveDescriptor.getSystemDirectoryPath());
+        this.traceDataOut.println("writeHeader#writeUTF archiveDescriptor.getProductDescription(): " + archiveDescriptor.getProductDescription());
+        this.traceDataOut.println("writeHeader#writeUTF getOSInfo(): " + getOSInfo());
+        this.traceDataOut.println("writeHeader#writeUTF getMachineInfo(): " + getMachineInfo());
+      }
+    } catch (IOException ex) {
+      throw new GemFireIOException(LocalizedStrings.StatArchiveWriter_FAILED_WRITING_HEADER_TO_STATISTIC_ARCHIVE.toLocalizedString(), ex);
+    }
+  }
+
+  public void allocatedResourceType(ResourceType resourceType) {
+    if (logger.isTraceEnabled(LogMarker.STATISTICS)) {
+      logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#allocatedResourceType resourceType={}", resourceType);
+    }
+    if (resourceType.getStatisticDescriptors().length >= ILLEGAL_STAT_OFFSET) {
+      throw new InternalGemFireException(LocalizedStrings.StatArchiveWriter_COULD_NOT_ARCHIVE_TYPE_0_BECAUSE_IT_HAD_MORE_THAN_1_STATISTICS.toLocalizedString(new Object[] {resourceType.getStatisticsType().getName(), Integer.valueOf(ILLEGAL_STAT_OFFSET-1)}));
+    }
+    // write the type to the archive
+    try {
+      this.dataOut.writeByte(RESOURCE_TYPE_TOKEN);
+      this.dataOut.writeInt(resourceType.getId());
+      this.dataOut.writeUTF(resourceType.getStatisticsType().getName());
+      this.dataOut.writeUTF(resourceType.getStatisticsType().getDescription());
+      StatisticDescriptor[] stats = resourceType.getStatisticDescriptors();
+      this.dataOut.writeShort(stats.length);
+      if (this.trace && (traceStatisticsTypeName == null || traceStatisticsTypeName.equals(resourceType.getStatisticsType().getName()))) {
+        this.traceDataOut.println("allocatedResourceType#writeByte RESOURCE_TYPE_TOKEN: " + RESOURCE_TYPE_TOKEN);
+        this.traceDataOut.println("allocatedResourceType#writeInt resourceType.getId(): " + resourceType.getId());
+        this.traceDataOut.println("allocatedResourceType#writeUTF resourceType.getStatisticsType().getName(): " + resourceType.getStatisticsType().getName());
+        this.traceDataOut.println("allocatedResourceType#writeUTF resourceType.getStatisticsType().getDescription(): " + resourceType.getStatisticsType().getDescription());
+        this.traceDataOut.println("allocatedResourceType#writeShort stats.length: " + stats.length);
+      }
+      for (int i=0; i < stats.length; i++) {
+        this.dataOut.writeUTF(stats[i].getName());
+        this.dataOut.writeByte(((StatisticDescriptorImpl)stats[i]).getTypeCode());
+        this.dataOut.writeBoolean(stats[i].isCounter());
+        this.dataOut.writeBoolean(stats[i].isLargerBetter());
+        this.dataOut.writeUTF(stats[i].getUnit());
+        this.dataOut.writeUTF(stats[i].getDescription());
+        if (this.trace && (traceStatisticsTypeName == null || traceStatisticsTypeName.equals(resourceType.getStatisticsType().getName()))) {
+          this.traceDataOut.println("allocatedResourceType#writeUTF stats[i].getName(): " + stats[i].getName());
+          this.traceDataOut.println("allocatedResourceType#writeByte ((StatisticDescriptorImpl)stats[i]).getTypeCode(): " + ((StatisticDescriptorImpl)stats[i]).getTypeCode());
+          this.traceDataOut.println("allocatedResourceType#writeBoolean stats[i].isCounter(): " + stats[i].isCounter());
+          this.traceDataOut.println("allocatedResourceType#writeBoolean stats[i].isLargerBetter(): " + stats[i].isLargerBetter());
+          this.traceDataOut.println("allocatedResourceType#writeUTF stats[i].getUnit(): " + stats[i].getUnit());
+          this.traceDataOut.println("allocatedResourceType#writeUTF stats[i].getDescription(): " + stats[i].getDescription());
+        }
+      }
+    } catch (IOException ex) {
+      throw new GemFireIOException(LocalizedStrings.StatArchiveWriter_FAILED_WRITING_NEW_RESOURCE_TYPE_TO_STATISTIC_ARCHIVE.toLocalizedString(), ex);
+    }
+  }
+  
+  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification="This is only for debugging and there is never more than one instance being traced because there is only one stat sampler.") 
+  public void allocatedResourceInstance(ResourceInstance statResource) {
+    if (logger.isTraceEnabled(LogMarker.STATISTICS)) {
+      logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#allocatedResourceInstance statResource={}", statResource);
+    }
+    if (statResource.getResourceType().getStatisticDescriptors().length >= ILLEGAL_STAT_OFFSET) {
+      throw new InternalGemFireException(LocalizedStrings.StatArchiveWriter_COULD_NOT_ARCHIVE_TYPE_0_BECAUSE_IT_HAD_MORE_THAN_1_STATISTICS.toLocalizedString(new Object[] {statResource.getResourceType().getStatisticsType().getName(), Integer.valueOf(ILLEGAL_STAT_OFFSET-1)}));
+    }
+    if (statResource.getStatistics().isClosed()) {
+      return;
+    }
+    this.addedResources.add(statResource);
+    try {
+      this.dataOut.writeByte(RESOURCE_INSTANCE_CREATE_TOKEN);
+      this.dataOut.writeInt(statResource.getId());
+      this.dataOut.writeUTF(statResource.getStatistics().getTextId());
+      this.dataOut.writeLong(statResource.getStatistics().getNumericId());
+      this.dataOut.writeInt(statResource.getResourceType().getId());
+      if (this.trace && (traceStatisticsName == null || traceStatisticsName.equals(statResource.getStatistics().getTextId())) && (traceStatisticsTypeName == null || traceStatisticsTypeName.equals(statResource.getResourceType().getStatisticsType().getName()))) {
+        traceResourceInstId = statResource.getId();
+        this.traceDataOut.println("writeHeader traceResourceInstId: " + traceResourceInstId);
+        this.traceDataOut.println("allocatedResourceInstance#writeByte RESOURCE_INSTANCE_CREATE_TOKEN: " + RESOURCE_INSTANCE_CREATE_TOKEN);
+        this.traceDataOut.println("allocatedResourceInstance#writeInt statResource.getId(): " + statResource.getId());
+        this.traceDataOut.println("allocatedResourceInstance#writeUTF statResource.getStatistics().getTextId(): " + statResource.getStatistics().getTextId());
+        this.traceDataOut.println("allocatedResourceInstance#writeLong statResource.getStatistics().getNumericId(): " + statResource.getStatistics().getNumericId());
+        this.traceDataOut.println("allocatedResourceInstance#writeInt statResource.getResourceType().getId(): " + statResource.getResourceType().getId());
+      }
+    } catch (IOException ex) {
+      throw new GemFireIOException(LocalizedStrings.StatArchiveWriter_FAILED_WRITING_NEW_RESOURCE_INSTANCE_TO_STATISTIC_ARCHIVE.toLocalizedString(), ex);
+    }
+  }
+  
+  public void destroyedResourceInstance(ResourceInstance resourceInstance) {
+    if (logger.isTraceEnabled(LogMarker.STATISTICS)) {
+      logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#destroyedResourceInstance resourceInstance={}", resourceInstance);
+    }
+    if (!this.addedResources.contains(resourceInstance)) {    // Fix for bug #45377
+      return;
+    }
+
+    this.sampleWrittenForResources.remove(resourceInstance);
+    this.addedResources.remove(resourceInstance);
+
+    try {
+      this.dataOut.writeByte(RESOURCE_INSTANCE_DELETE_TOKEN);
+      this.dataOut.writeInt(resourceInstance.getId());
+      if (this.trace && (traceStatisticsName == null || traceStatisticsName.equals(resourceInstance.getStatistics().getTextId())) && (traceStatisticsTypeName == null || traceStatisticsTypeName.equals(resourceInstance.getResourceType().getStatisticsType().getName()))) {
+        this.traceDataOut.println("destroyedResourceInstance#writeByte RESOURCE_INSTANCE_DELETE_TOKEN: " + RESOURCE_INSTANCE_DELETE_TOKEN);
+        this.traceDataOut.println("destroyedResourceInstance#writeInt resourceInstance.getId(): " + resourceInstance.getId());
+      }
+    } catch (IOException ex) {
+      throw new GemFireIOException(LocalizedStrings.StatArchiveWriter_FAILED_WRITING_DELETE_RESOURCE_INSTANCE_TO_STATISTIC_ARCHIVE.toLocalizedString(), ex);
+    }
+  }
+  
+  static long calcDelta(long previousMillis, long currentMillis) {
+    long delta = currentMillis - previousMillis;
+    if (delta <= 0) {
+      throw new IllegalArgumentException("Sample timestamp must be greater than previous timestamp (millisTimeStamp is " + currentMillis + ", previousMillis is " + previousMillis + " and delta is " + delta + ").");
+    }
+    return delta;
+  }
+  
+  private void writeTimeStamp(long nanosTimeStamp) throws IOException {
+    final long millisTimeStamp = NanoTimer.nanosToMillis(nanosTimeStamp);
+    final long delta = calcDelta(this.previousMillisTimeStamp, millisTimeStamp);
+    if (logger.isTraceEnabled(LogMarker.STATISTICS)) {
+      logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#writeTimeStamp millisTimeStamp={}, delta={}", millisTimeStamp, (int)delta);
+    }
+    if (delta > MAX_SHORT_TIMESTAMP) {
+      if (delta > Integer.MAX_VALUE) {
+        throw new InternalGemFireException(LocalizedStrings.StatArchiveWriter_TIMESTAMP_DELTA_0_WAS_GREATER_THAN_1.toLocalizedString(new Object[] {Long.valueOf(delta), Integer.valueOf(Integer.MAX_VALUE)}));
+      }
+      this.dataOut.writeShort(INT_TIMESTAMP_TOKEN);
+      this.dataOut.writeInt((int)delta);
+      if (this.trace) {
+        this.traceDataOut.println("writeTimeStamp#writeShort INT_TIMESTAMP_TOKEN: " + INT_TIMESTAMP_TOKEN);
+        this.traceDataOut.println("writeTimeStamp#writeInt (int)delta: " + (int)delta);
+      }
+    } else {
+      this.dataOut.writeShort((int)delta);
+      if (this.trace) {
+        this.traceDataOut.println("writeTimeStamp#writeShort (int)delta: " + (int)delta);
+      }
+    }
+    this.previousMillisTimeStamp = millisTimeStamp;
+  }
+
+  /**
+   * Writes the resource instance id to the <code>dataOut</code> stream.
+   */
+  private void writeResourceInst(int instId) throws IOException {
+    if (logger.isTraceEnabled(LogMarker.STATISTICS)) {
+      logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#writeResourceInst instId={}", instId);
+    }
+    if (instId > MAX_BYTE_RESOURCE_INST_ID) {
+      if (instId > MAX_SHORT_RESOURCE_INST_ID) {
+        this.dataOut.writeByte(INT_RESOURCE_INST_ID_TOKEN);
+        this.dataOut.writeInt(instId);
+        if (this.trace && (traceResourceInstId == -1 || traceResourceInstId == instId)) {
+          this.traceDataOut.println("writeResourceInst#writeByte INT_RESOURCE_INST_ID_TOKEN: " + INT_RESOURCE_INST_ID_TOKEN);
+          if (instId == ILLEGAL_RESOURCE_INST_ID) {
+            this.traceDataOut.println("writeResourceInst#writeInt ILLEGAL_RESOURCE_INST_ID: " + ILLEGAL_RESOURCE_INST_ID);
+          } else {
+            this.traceDataOut.println("writeResourceInst#writeInt instId: " + instId);
+          }
+        }
+      } else {
+        this.dataOut.writeByte(SHORT_RESOURCE_INST_ID_TOKEN);
+        this.dataOut.writeShort(instId);
+        if (this.trace && (traceResourceInstId == -1 || traceResourceInstId == instId)) {
+          this.traceDataOut.println("writeResourceInst#writeByte SHORT_RESOURCE_INST_ID_TOKEN: " + SHORT_RESOURCE_INST_ID_TOKEN);
+          if (instId == ILLEGAL_RESOURCE_INST_ID) {
+            this.traceDataOut.println("writeResourceInst#writeShort ILLEGAL_RESOURCE_INST_ID: " + ILLEGAL_RESOURCE_INST_ID);
+          } else {
+            this.traceDataOut.println("writeResourceInst#writeShort instId: " + instId);
+          }
+        }
+      }
+    } else {
+      this.dataOut.writeByte(instId);
+      if (this.trace && (traceResourceInstId == -1 || traceResourceInstId == instId)) {
+        if (instId == ILLEGAL_RESOURCE_INST_ID) {
+          this.traceDataOut.println("writeResourceInst#writeByte ILLEGAL_RESOURCE_INST_ID: " + ILLEGAL_RESOURCE_INST_ID);
+        } else {
+          this.traceDataOut.println("writeResourceInst#writeByte instId: " + instId);
+        }
+      }
+    }
+  }
+
+  public void sampled(long nanosTimeStamp, List<ResourceInstance> resourceInstances) {
+    if (logger.isTraceEnabled(LogMarker.STATISTICS)) {
+      logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#sampled nanosTimeStamp={}, resourceInstances={}", nanosTimeStamp, resourceInstances);
+    }
+    try {
+      this.dataOut.writeByte(SAMPLE_TOKEN);
+      if (this.trace) {
+        this.traceDataOut.println("sampled#writeByte SAMPLE_TOKEN: " + SAMPLE_TOKEN);
+      }
+      writeTimeStamp(nanosTimeStamp);
+      for (ResourceInstance ri : resourceInstances) {
+        writeSample(ri);
+      }
+      writeResourceInst(ILLEGAL_RESOURCE_INST_ID);
+      this.dataOut.flush();
+      if (this.trace) {
+        this.traceDataOut.flush();
+      }
+    } catch (IOException ex) {
+      throw new GemFireIOException(LocalizedStrings.StatArchiveWriter_FAILED_WRITING_SAMPLE_TO_STATISTIC_ARCHIVE.toLocalizedString(), ex);
+    }
+    this.sampleCount++; // only inc after sample done w/o an exception thrown
+  }
+  
+  public int getSampleCount() {
+    return this.sampleCount;
+  }
+  
+  private void writeSample(ResourceInstance ri) throws IOException {
+    final boolean isDebugEnabled_STATISTICS = logger.isTraceEnabled(LogMarker.STATISTICS);
+    if (isDebugEnabled_STATISTICS) {
+      logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#writeSample ri={}", ri);
+    }
+    if (this.trace && (traceStatisticsName == null || traceStatisticsName.equals(ri.getStatistics().getTextId())) && (traceStatisticsTypeName == null || traceStatisticsTypeName.equals(ri.getResourceType().getStatisticsType().getName()))) {
+      this.traceDataOut.println("writeSample#writeSample for ri=" + ri);
+    }
+    if (ri.getStatistics().isClosed()) {
+      return;
+    }
+    StatisticDescriptor[] stats = ri.getResourceType().getStatisticDescriptors();
+    if (stats.length > 254) {
+      throw new Error("StatisticsType " + ri.getResourceType().getStatisticsType().getName() + " has too many stats: " + stats.length);
+    }
+    boolean wroteInstId = false;
+    boolean checkForChange = true;
+    
+    if (!this.sampleWrittenForResources.contains(ri)) {
+      // first time for this instance so all values need to be written
+      checkForChange = false;
+      this.sampleWrittenForResources.add(ri);
+    }
+    
+    long[] previousStatValues = ri.getPreviousStatValues();
+    if (isDebugEnabled_STATISTICS) {
+      logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#writeSample checkForChange={}, previousStatValues={}, stats.length={}",
+          checkForChange, Arrays.toString(previousStatValues), stats.length);
+    }
+    if (previousStatValues == null) {
+      previousStatValues = new long[stats.length];
+      ri.setPreviousStatValues(previousStatValues);
+    }
+    
+    int statsWritten = 0;
+    try {
+      for (int i=0; i < stats.length; i++) {
+        long value = ri.getLatestStatValues()[i];
+        if (!checkForChange || value != previousStatValues[i]) {
+          long delta = checkForChange ? value - previousStatValues[i] : value;
+          if (!wroteInstId) {
+            wroteInstId = true;
+            writeResourceInst(ri.getId());
+          }
+          this.dataOut.writeByte(i);
+          if (this.trace && (traceStatisticsName == null || traceStatisticsName.equals(ri.getStatistics().getTextId())) && (traceStatisticsTypeName == null || traceStatisticsTypeName.equals(ri.getResourceType().getStatisticsType().getName()))) {
+            this.traceDataOut.println("writeSample#writeByte i: " + i);
+          }
+          if (isDebugEnabled_STATISTICS) {
+            logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#writeStatValue stats[{}]={}, delta={}", i, stats[i], delta);
+          }
+          writeStatValue(stats[i], delta, this.dataOut);
+          if (this.trace && (traceStatisticsName == null || traceStatisticsName.equals(ri.getStatistics().getTextId())) && (traceStatisticsTypeName == null || traceStatisticsTypeName.equals(ri.getResourceType().getStatisticsType().getName()))) {
+            byte typeCode = ((StatisticDescriptorImpl)stats[i]).getTypeCode();
+            switch(typeCode) {
+            case BYTE_CODE:
+              this.traceDataOut.println("writeStatValue#writeByte " + typeCodeToString(typeCode) + " delta: " + delta);
+              break;
+            case SHORT_CODE:
+              this.traceDataOut.println("writeStatValue#writeShort" + typeCodeToString(typeCode) + " delta: " + delta);
+              break;
+            case INT_CODE:
+            case FLOAT_CODE:
+            case LONG_CODE:
+            case DOUBLE_CODE:
+              this.traceDataOut.println("writeStatValue#writeCompactValue " + typeCodeToString(typeCode) + " delta: " + delta);
+              break;
+            default:
+            }
+          }
+        }
+      }
+    } catch (IllegalStateException closedEx) {
+      // resource was closed causing getStatValue to throw this exception
+    }
+    
+    if (wroteInstId) {
+      this.dataOut.writeByte(ILLEGAL_STAT_OFFSET);
+      if (this.trace && (traceStatisticsName == null
+          || traceStatisticsName.equals(ri.getStatistics().getTextId()))
+          && (traceStatisticsTypeName == null
+          || traceStatisticsTypeName.equals(ri.getResourceType().getStatisticsType().getName()))) {
+        this.traceDataOut.println("writeSample#writeByte ILLEGAL_STAT_OFFSET: " + ILLEGAL_STAT_OFFSET);
+      }
+    }
+    if (isDebugEnabled_STATISTICS) {
+      logger.trace(LogMarker.STATISTICS, "StatArchiveWriter#writeSample statsWritten={}", statsWritten);
+    }
+  }
+  
+  public static void writeCompactValue(long v, DataOutput dataOut) throws IOException {
+    if (v <= MAX_1BYTE_COMPACT_VALUE && v >= MIN_1BYTE_COMPACT_VALUE) {
+      dataOut.writeByte((int)v);
+    } else if (v <= MAX_2BYTE_COMPACT_VALUE && v >= MIN_2BYTE_COMPACT_VALUE) {
+      dataOut.writeByte(COMPACT_VALUE_2_TOKEN);
+      dataOut.writeShort((int)v);
+    } else {
+      byte[] buffer = new byte[8];
+      int idx = 0;
+      long originalValue = v;
+      if (v < 0) {
+        while (v != -1 && v != 0) {
+          buffer[idx++] = (byte)(v & 0xFF);
+          v >>= 8;
+        }
+        // On windows v goes to zero somtimes; seems like a bug
+        if (v == 0) {
+          // when this happens we end up with a bunch of -1 bytes
+          // so strip off the high order ones
+          while (buffer[idx-1] == -1) {
+            idx--;
+          }
+          //               System.out.print("DEBUG: originalValue=" + originalValue);
+          //               for (int dbx=0; dbx<idx; dbx++) {
+          //                   System.out.print(" " + buffer[dbx]);
+          //               }
+          //               System.out.println();
+        }
+        if ((buffer[idx-1] & 0x80) == 0) {
+          /* If the most significant byte does not have its high order bit set
+           * then add a -1 byte so we know this is a negative number
+           */
+          buffer[idx++] = -1;
+        }
+      } else {
+        while (v != 0) {
+          buffer[idx++] = (byte)(v & 0xFF);
+          v >>= 8;
+        }
+        if ((buffer[idx-1] & 0x80) != 0) {
+          /* If the most significant byte has its high order bit set
+           * then add a zero byte so we know this is a positive number
+           */
+          buffer[idx++] = 0;
+        }
+      }
+      if (idx <= 2) {
+        throw new InternalGemFireException(LocalizedStrings.StatArchiveWriter_EXPECTED_IDX_TO_BE_GREATER_THAN_2_IT_WAS_0_FOR_THE_VALUE_1.toLocalizedString(new Object[] {Integer.valueOf(idx), Long.valueOf(originalValue)}));
+      }
+      int token = COMPACT_VALUE_2_TOKEN + (idx - 2);
+      dataOut.writeByte(token);
+      for (int i=idx-1; i >= 0; i--) {
+        dataOut.writeByte(buffer[i]);
+      }
+    }
+  }
+
+  public static long readCompactValue(DataInput dataIn) throws IOException {
+    long v = dataIn.readByte();
+    boolean dump = false;
+    if (dump) {
+      System.out.print("compactValue(byte1)=" + v);
+    }
+    if (v < MIN_1BYTE_COMPACT_VALUE) {
+      if (v == COMPACT_VALUE_2_TOKEN) {
+        v = dataIn.readShort();
+        if (dump) {
+          System.out.print("compactValue(short)=" + v);
+        }
+      } else {
+        int bytesToRead = ((byte)v - COMPACT_VALUE_2_TOKEN) + 2;
+        v = dataIn.readByte(); // note the first byte will be a signed byte.
+        if (dump) {
+          System.out.print("compactValue(" + bytesToRead + ")=" + v);
+        }
+        bytesToRead--;
+        while (bytesToRead > 0) {
+          v <<= 8;
+          v |= dataIn.readUnsignedByte();
+          bytesToRead--;
+        }
+      }
+    }
+    return v;
+  }
+
+  protected static void writeStatValue(StatisticDescriptor f, long v, DataOutput dataOut) throws IOException {
+    byte typeCode = ((StatisticDescriptorImpl)f).getTypeCode();
+    writeStatValue(typeCode, v, dataOut);
+  }
+
+  public static void writeStatValue(byte typeCode, long v, DataOutput dataOut) throws IOException {
+    switch(typeCode) {
+    case BYTE_CODE:
+      dataOut.writeByte((int)v);
+      break;
+    case SHORT_CODE:
+      dataOut.writeShort((int)v);
+      break;
+    case INT_CODE:
+    case FLOAT_CODE:
+    case LONG_CODE:
+    case DOUBLE_CODE:
+      writeCompactValue(v, dataOut);
+      break;
+    default:
+      throw new InternalGemFireException(LocalizedStrings.StatArchiveWriter_UNEXPECTED_TYPE_CODE_0.toLocalizedString(Byte.valueOf(typeCode)));
+    }
+  }
+    
+  protected static void setTraceFilter(String traceStatisticsName, String traceStatisticsTypeName) {
+    StatArchiveWriter.traceStatisticsName = traceStatisticsName;
+    StatArchiveWriter.traceStatisticsTypeName = traceStatisticsTypeName;
+    StatArchiveWriter.traceResourceInstId = -1;
+  }
+  
+  protected static void clearTraceFilter() {
+    StatArchiveWriter.traceStatisticsName = null;
+    StatArchiveWriter.traceStatisticsTypeName = null;
+    StatArchiveWriter.traceResourceInstId = -1;
+  }
+  
+  private static String typeCodeToString(byte typeCode) {
+    switch(typeCode) {
+    case BYTE_CODE:
+      return "BYTE_CODE";
+    case SHORT_CODE:
+      return "SHORT_CODE";
+    case INT_CODE:
+      return "INT_CODE";
+    case FLOAT_CODE:
+      return "FLOAT_CODE";
+    case LONG_CODE:
+      return "LONG_CODE";
+    case DOUBLE_CODE:
+      return "DOUBLE_CODE";
+    default:
+      return "unknown typeCode " + typeCode;
+    }
+  }
+    
+  private static class MyDataOutputStream implements DataOutput {
+    private long bytesWritten = 0;
+    private final DataOutputStream dataOut;
+
+    public MyDataOutputStream(OutputStream out) {
+      this.dataOut = new DataOutputStream(out);
+    }
+    
+    public final long getBytesWritten() {
+      return this.bytesWritten;
+    }
+    public final void flush() throws IOException {
+      this.dataOut.flush();
+    }
+    @SuppressWarnings("unused")
+    public final void close() throws IOException {
+      this.dataOut.close();
+    }
+    
+    public final void write(int b) throws IOException {
+      throw new RuntimeException(LocalizedStrings.StatArchiveWriter_METHOD_UNIMPLEMENTED.toLocalizedString());
+    }
+    public final void write(byte[] b, int off, int len) throws IOException {
+      throw new RuntimeException(LocalizedStrings.StatArchiveWriter_METHOD_UNIMPLEMENTED.toLocalizedString());
+    }
+    public final void write(byte[] b) throws IOException {
+      throw new RuntimeException(LocalizedStrings.StatArchiveWriter_METHOD_UNIMPLEMENTED.toLocalizedString());
+    }
+    public final void writeBytes(String v) throws IOException {
+      throw new RuntimeException(LocalizedStrings.StatArchiveWriter_METHOD_UNIMPLEMENTED.toLocalizedString());
+    }
+    public final void writeChar(int v) throws IOException {
+      throw new RuntimeException(LocalizedStrings.StatArchiveWriter_METHOD_UNIMPLEMENTED.toLocalizedString());
+    }
+    public final void writeChars(String v) throws IOException {
+      throw new RuntimeException(LocalizedStrings.StatArchiveWriter_METHOD_UNIMPLEMENTED.toLocalizedString());
+    }
+    public final void writeDouble(double v) throws IOException {
+      throw new RuntimeException(LocalizedStrings.StatArchiveWriter_METHOD_UNIMPLEMENTED.toLocalizedString());
+    }
+    public final void writeFloat(float v) throws IOException {
+      throw new RuntimeException(LocalizedStrings.StatArchiveWriter_METHOD_UNIMPLEMENTED.toLocalizedString());
+    }
+
+    public final void writeBoolean(boolean v) throws IOException {
+      this.dataOut.writeBoolean(v);
+      this.bytesWritten += 1;
+    }
+    public final void writeByte(int v) throws IOException {
+      this.dataOut.writeByte(v);
+      this.bytesWritten += 1;
+    }
+    public final void writeShort(int v) throws IOException {
+      this.dataOut.writeShort(v);
+      this.bytesWritten += 2;
+    }
+    public final void writeInt(int v) throws IOException {
+      this.dataOut.writeInt(v);
+      this.bytesWritten += 4;
+    }
+    public final void writeLong(long v) throws IOException {
+      this.dataOut.writeLong(v);
+      this.bytesWritten += 8;
+    }
+    public final void writeUTF(String v) throws IOException {
+      this.dataOut.writeUTF(v);
+      this.bytesWritten += v.length() + 2; // this is the minimum. The max is v.size()*3 +2
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/866bacec/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatSamplerStats.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatSamplerStats.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatSamplerStats.java
new file mode 100644
index 0000000..e83d46c
--- /dev/null
+++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatSamplerStats.java
@@ -0,0 +1,153 @@
+/*
+ * 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 com.gemstone.gemfire.internal.statistics;
+
+import com.gemstone.gemfire.*;
+
+/**
+ * Statistics related to the statistic sampler.
+ */
+public class StatSamplerStats {
+  public final static String SAMPLE_COUNT = "sampleCount"; // int
+  public final static String SAMPLE_TIME = "sampleTime"; // long
+  public final static String DELAY_DURATION = "delayDuration"; // int
+  public final static String STAT_RESOURCES = "statResources"; // int
+  public final static String JVM_PAUSES = "jvmPauses"; // int
+  public final static String SAMPLE_CALLBACKS = "sampleCallbacks"; // int
+  public final static String SAMPLE_CALLBACK_ERRORS = "sampleCallbackErrors"; // int
+  public final static String SAMPLE_CALLBACK_DURATION = "sampleCallbackDuration"; // long
+
+  private final static StatisticsType samplerType;
+  private final static int sampleCountId;
+  private final static int sampleTimeId;
+  private final static int delayDurationId;
+  private final static int statResourcesId;
+  private final static int jvmPausesId;
+  private final static int sampleCallbacksId;
+  private final static int sampleCallbackErrorsId;
+  private final static int sampleCallbackDurationId;
+  static {
+    StatisticsTypeFactory f = StatisticsTypeFactoryImpl.singleton();
+    samplerType = f.createType("StatSampler",
+                               "Stats on the statistic sampler.",
+                               new StatisticDescriptor[] {
+                                 f.createIntCounter(SAMPLE_COUNT,
+                                                    "Total number of samples taken by this sampler.",
+                                                    "samples", false),
+                                 f.createLongCounter(SAMPLE_TIME,
+                                                     "Total amount of time spent taking samples.",
+                                                     "milliseconds", false),
+                                 f.createIntGauge(DELAY_DURATION,
+                                                  "Actual duration of sampling delay taken before taking this sample.",
+                                                  "milliseconds", false),
+                                 f.createIntGauge(STAT_RESOURCES,
+                                                  "Current number of statistic resources being sampled by this sampler.",
+                                                  "resources", false),
+                                 f.createIntCounter(JVM_PAUSES,
+                                                    "Total number of JVM pauses (which may or may not be full GC pauses) detected by this sampler. A JVM pause is defined as a system event which kept the statistics sampler thread from sampling for 3000 or more milliseconds. This threshold can be customized by setting the system property gemfire.statSamplerDelayThreshold (units are milliseconds).",
+                                                    "jvmPauses", false),
+                                 f.createIntGauge(SAMPLE_CALLBACKS,
+                                   "Current number of statistics that are sampled using callbacks.",
+                                   "resources", false),
+                                 f.createIntCounter(SAMPLE_CALLBACK_ERRORS,
+                                   "Total number of exceptions thrown by callbacks when performing sampling",
+                                   "errors", false),
+                                 f.createLongCounter(SAMPLE_CALLBACK_DURATION,
+                                   "Total amount of time invoking sampling callbacks",
+                                   "milliseconds", false),
+                               });
+    sampleCountId = samplerType.nameToId(SAMPLE_COUNT);
+    sampleTimeId = samplerType.nameToId(SAMPLE_TIME);
+    delayDurationId = samplerType.nameToId(DELAY_DURATION);
+    statResourcesId = samplerType.nameToId(STAT_RESOURCES);
+    jvmPausesId = samplerType.nameToId(JVM_PAUSES);
+    sampleCallbacksId = samplerType.nameToId(SAMPLE_CALLBACKS);
+    sampleCallbackErrorsId = samplerType.nameToId(SAMPLE_CALLBACK_ERRORS);
+    sampleCallbackDurationId = samplerType.nameToId(SAMPLE_CALLBACK_DURATION);
+  }
+
+  private final Statistics samplerStats;
+
+  public StatSamplerStats(StatisticsFactory f, long id) {
+    this.samplerStats = f.createStatistics(samplerType, "statSampler", id);
+  }
+
+  public void tookSample(long nanosSpentWorking, int statResources, long nanosSpentSleeping) {
+    this.samplerStats.incInt(sampleCountId, 1);
+    this.samplerStats.incLong(sampleTimeId, nanosSpentWorking / 1000000);
+    this.samplerStats.setInt(delayDurationId, (int)(nanosSpentSleeping / 1000000));
+    this.samplerStats.setInt(statResourcesId, statResources);
+  }
+  
+  public void incJvmPauses() {
+    this.samplerStats.incInt(jvmPausesId, 1);
+  }
+
+  public void incSampleCallbackErrors(int delta) {
+    this.samplerStats.incInt(sampleCallbackErrorsId, delta);
+  }
+
+  public void setSampleCallbacks(int count) {
+    this.samplerStats.setInt(sampleCallbacksId, count);
+  }
+
+  public void incSampleCallbackDuration(long delta) {
+    this.samplerStats.incLong(sampleCallbackDurationId, delta);
+  }
+
+  public int getSampleCount() {
+    return this.samplerStats.getInt(SAMPLE_COUNT);
+  }
+  
+  public long getSampleTime() {
+    return this.samplerStats.getLong(SAMPLE_TIME);
+  }
+  
+  public int getDelayDuration() {
+    return this.samplerStats.getInt(DELAY_DURATION);
+  }
+  
+  public int getStatResources() {
+    return this.samplerStats.getInt(STAT_RESOURCES);
+  }
+  
+  public int getJvmPauses() {
+    return this.samplerStats.getInt(JVM_PAUSES);
+  }
+  
+  public void close() {
+    this.samplerStats.close();
+  }
+  
+  public Statistics getStats(){
+    return this.samplerStats;
+  }
+  
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder(getClass().getName());
+    sb.append("@").append(System.identityHashCode(this)).append("{");
+    sb.append("isClosed=").append(this.samplerStats.isClosed());
+    sb.append(", ").append(SAMPLE_COUNT + "=").append(this.samplerStats.getInt(SAMPLE_COUNT));
+    sb.append(", ").append(SAMPLE_TIME + "=").append(this.samplerStats.getLong(SAMPLE_TIME));
+    sb.append(", ").append(DELAY_DURATION + "=").append(this.samplerStats.getInt(DELAY_DURATION));
+    sb.append(", ").append(STAT_RESOURCES + "=").append(this.samplerStats.getInt(STAT_RESOURCES));
+    sb.append(", ").append(JVM_PAUSES + "=").append(this.samplerStats.getInt(JVM_PAUSES));
+    sb.append("}");
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/866bacec/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticDescriptorImpl.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticDescriptorImpl.java
new file mode 100644
index 0000000..682f77e
--- /dev/null
+++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticDescriptorImpl.java
@@ -0,0 +1,383 @@
+/*
+ * 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 com.gemstone.gemfire.internal.statistics;
+
+import com.gemstone.gemfire.*;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+
+/**
+ * Describes an individual statistic whose value is updated by an
+ * application and may be archived by GemFire.  These descriptions are
+ * gathered together in a {@link StatisticsType}.
+ *
+ * @see Statistics
+ *
+ *
+ * @since GemFire 3.0
+ */
+public final class StatisticDescriptorImpl implements StatisticDescriptor {
+
+  /** A constant for an <code>byte</code> type */
+  static final byte BYTE = (byte) 3;
+
+  /** A constant for an <code>short</code> type */
+  static final byte SHORT = (byte) 4;
+
+  /** A constant for an <code>int</code> type */
+  static final byte INT = (byte) 5;
+
+  /** A constant for an <code>long</code> type */
+  static final byte LONG = (byte) 6;
+
+  /** A constant for an <code>float</code> type */
+  static final byte FLOAT = (byte) 7;
+
+  /** A constant for an <code>double</code> type */
+  static final byte DOUBLE = (byte) 8;
+
+  ////////////////////  Instance Fields  ////////////////////
+
+  /** An unitialized offset */
+  private int INVALID_OFFSET = -1;
+
+  /** The name of the statistic */
+  private final String name;
+
+  /** The type code of this statistic */
+  private final byte typeCode;
+
+  /** A description of the statistic */
+  private final String description;
+
+  /** The unit of the statistic */
+  private final String unit;
+
+  /** Is the statistic a counter? */
+  private final boolean isCounter;
+
+  /** Do larger values of the statistic indicate better performance? */
+  private final boolean isLargerBetter;
+
+  /** The physical offset used to access the data that stores the
+   * value for this statistic in an instance of {@link Statistics}
+   */
+  private int id = INVALID_OFFSET;
+
+  //////////////////////  Static Methods  //////////////////////
+
+  /**
+   * Returns the name of the given type code
+   *
+   * @throws IllegalArgumentException
+   *         <code>code</code> is an unknown type
+   */
+  public final static String getTypeCodeName(int code) {
+    switch (code) {
+    case BYTE: 
+      return "byte";
+    case SHORT: 
+      return "short";
+    case FLOAT: 
+      return "float";
+    case INT: 
+      return "int";
+    case LONG:
+      return "long";
+    case DOUBLE:
+      return "double";
+    default:
+      throw new IllegalArgumentException(LocalizedStrings.StatisticDescriptorImpl_UNKNOWN_TYPE_CODE_0.toLocalizedString(Integer.valueOf(code)));
+    }
+  }
+
+  /**
+   * Returns the number of bits needed to represent a value of the given type
+   *
+   * @throws IllegalArgumentException
+   *         <code>code</code> is an unknown type
+   */
+  public final static int getTypeCodeBits(int code) {
+    switch (code) {
+    case BYTE: 
+      return 8;
+    case SHORT: 
+      return 16;
+    case FLOAT: 
+      return 32;
+    case INT: 
+      return 32;
+    case LONG:
+      return 64;
+    case DOUBLE:
+      return 64;
+    default:
+      throw new IllegalArgumentException(LocalizedStrings.StatisticDescriptorImpl_UNKNOWN_TYPE_CODE_0.toLocalizedString(Integer.valueOf(code)));
+    }
+  }
+
+  /**
+   * Returns the class of the given type code
+   *
+   * @throws IllegalArgumentException
+   *         <code>code</code> is an unknown type
+   */
+  public final static Class<?> getTypeCodeClass(byte code) {
+    switch (code) {
+    case BYTE: 
+      return byte.class;
+    case SHORT: 
+      return short.class;
+    case FLOAT: 
+      return float.class;
+    case INT: 
+      return int.class;
+    case LONG:
+      return long.class;
+    case DOUBLE:
+      return double.class;
+    default:
+      throw new IllegalArgumentException(LocalizedStrings.StatisticDescriptorImpl_UNKNOWN_TYPE_CODE_0.toLocalizedString(Integer.valueOf(code)));
+    }
+  }
+
+  public static StatisticDescriptor createIntCounter(String name, String description,
+                                              String units, boolean isLargerBetter) {
+    return new StatisticDescriptorImpl(name, INT, description, units, true, isLargerBetter);
+  }
+  public static StatisticDescriptor createLongCounter(String name, String description,
+                                               String units, boolean isLargerBetter) {
+    return new StatisticDescriptorImpl(name, LONG, description, units, true, isLargerBetter);
+  }
+  public static StatisticDescriptor createDoubleCounter(String name, String description,
+                                                 String units, boolean isLargerBetter) {
+    return new StatisticDescriptorImpl(name, DOUBLE, description, units, true, isLargerBetter);
+  }
+  public static StatisticDescriptor createIntGauge(String name, String description,
+                                            String units, boolean isLargerBetter) {
+    return new StatisticDescriptorImpl(name, INT, description, units, false, isLargerBetter);
+  }
+  public static StatisticDescriptor createLongGauge(String name, String description,
+                                             String units, boolean isLargerBetter) {
+    return new StatisticDescriptorImpl(name, LONG, description, units, false, isLargerBetter);
+  }
+  public static StatisticDescriptor createDoubleGauge(String name, String description,
+                                               String units, boolean isLargerBetter) {
+    return new StatisticDescriptorImpl(name, DOUBLE, description, units, false, isLargerBetter);
+  }
+
+  ///////////////////////  Constructors  ///////////////////////
+
+  /**
+   * Creates a new description of a statistic.
+   *
+   * @param name
+   *        The name of the statistic (for example,
+   *        <code>"numDatabaseLookups"</code>) 
+   * @param typeCode
+   *        The type of the statistic.  This must be either
+   *        <code>int.class</code>, <code>long.class</code>, or
+   *        <code>double.class</code>.
+   * @param description
+   *        A description of the statistic (for example, <code>"The
+   *        number of database lookups"</code>
+   * @param unit
+   *        The units that this statistic is measure in (for example,
+   *        <code>"milliseconds"</code>) 
+   * @param isCounter
+   *        Is this statistic a counter?  That is, does its value
+   *        change monotonically (always increases or always
+   *        decreases)? 
+   * @param isLargerBetter
+   *        True if larger values indicate better performance.
+   *
+   * @throws IllegalArgumentException
+   *         <code>type</code> is not one of <code>int.class</code>,
+   *         <code>long.class</code>, or <code>double.class</code>.
+   */
+  private StatisticDescriptorImpl(String name, byte typeCode,
+                                  String description, String unit,
+                                  boolean isCounter,
+                                  boolean isLargerBetter) {
+    this.name = name;
+    this.typeCode = typeCode;
+    if (description == null) {
+      this.description = "";
+
+    } else {
+      this.description = description;
+    }
+
+    if (unit == null) {
+      this.unit = "";
+
+    } else {
+      this.unit = unit;
+    }
+    this.isCounter = isCounter;
+    this.isLargerBetter = isLargerBetter;
+  }
+
+  ////////////////////  StatisticDescriptor Methods  ////////////////////
+
+  public final String getName() {
+    return this.name;
+  }
+
+  public final String getDescription() {
+    return this.description;
+  }
+
+  public final Class<?> getType() {
+    return getTypeCodeClass(this.typeCode);
+  }
+
+  public final int getStorageBits() {
+    return getTypeCodeBits(this.typeCode);
+  }
+
+  public final boolean isCounter() {
+    return this.isCounter;
+  }
+  
+  public final boolean isLargerBetter() {
+    return this.isLargerBetter;
+  }
+  
+  public final String getUnit() {
+    return this.unit;
+  }
+
+  public final int getId() {
+//     if (this.id == INVALID_OFFSET) {
+//       String s = "The id has not been initialized yet.";
+//       throw new IllegalStateException(s);
+//     }
+
+    //Assert.assertTrue(this.id >= 0);
+    return this.id;
+  }
+  
+  public final Number getNumberForRawBits(long bits) {
+    switch (this.typeCode) {
+    case StatisticDescriptorImpl.INT:
+      return (int)bits;
+    case StatisticDescriptorImpl.LONG:
+      return bits;
+    case StatisticDescriptorImpl.DOUBLE:
+      return Double.longBitsToDouble(bits);
+    default:
+      throw new RuntimeException(LocalizedStrings.StatisticsImpl_UNEXPECTED_STAT_DESCRIPTOR_TYPE_CODE_0.toLocalizedString(Byte.valueOf(this.typeCode)));
+    }
+  }
+  
+  ////////////////////  Instance Methods  ////////////////////
+
+  /**
+   * Returns the type code of this statistic
+   */
+  public final byte getTypeCode() {
+    return this.typeCode;
+  }
+
+  /**
+   * Sets the id of this descriptor
+   */
+  final void setId(int id) {
+    //Assert.assertTrue(id >= 0);
+    this.id = id;
+  }
+
+  ////////////////////  Comparable Methods  ////////////////////
+  /**
+   * <code>StatisticDescriptor</code>s are naturally ordered by their
+   * name. 
+   *
+   * @throws IllegalArgumentException
+   *         <code>o</code> is not a <code>StatisticDescriptor</code>
+   *
+   * @see #getName
+   */
+  public int compareTo(StatisticDescriptor o) {
+    return this.getName().compareTo(o.getName());
+  }
+
+  public final int checkInt() {
+    if (this.typeCode != INT) {
+      throw new IllegalArgumentException(LocalizedStrings.StatisticDescriptorImpl_THE_STATISTIC_0_WITH_ID_1_IS_OF_TYPE_2_AND_IT_WAS_EXPECTED_TO_BE_AN_INT.toLocalizedString(new Object[] {getName(), Integer.valueOf(getId()), StatisticDescriptorImpl.getTypeCodeName(getTypeCode())}));
+    }
+    return this.id;
+  }
+
+  public final int checkLong() {
+    if (this.typeCode != LONG) {
+      StringBuffer sb = new StringBuffer();
+      sb.append("The statistic " + getName() + " with id ");
+      sb.append(getId());
+      sb.append(" is of type ");
+      sb.append(StatisticDescriptorImpl.getTypeCodeName(getTypeCode()));
+      
+      sb.append(" and it was expected to be a long");
+      throw new IllegalArgumentException(sb.toString());
+    }
+    return this.id;
+  }
+
+  public final int checkDouble() {
+    if (this.typeCode != DOUBLE) {
+      throw new IllegalArgumentException(LocalizedStrings.StatisticDescriptorImpl_THE_STATISTIC_0_WITH_ID_1_IS_OF_TYPE_2_AND_IT_WAS_EXPECTED_TO_BE_A_DOUBLE.toLocalizedString(new Object[] {getName(), Integer.valueOf(getId()), StatisticDescriptorImpl.getTypeCodeName(getTypeCode())}));
+    }
+    return this.id;
+  }
+
+
+  @Override // GemStoneAddition
+  public int hashCode() {
+    return getName().hashCode();
+  }
+  @Override
+  public boolean equals(Object o) {
+    if (o == null) {
+      return false;
+    }
+    if (!(o instanceof StatisticDescriptorImpl)) {
+      return false;
+    }
+    StatisticDescriptorImpl other = (StatisticDescriptorImpl)o;
+    if (getId() != other.getId()) {
+      return false;
+    }
+    if (!getName().equals(other.getName())) {
+      return false;
+    }
+    if (isCounter() != other.isCounter()) {
+      return false;
+    }
+    if (isLargerBetter() != other.isLargerBetter()) {
+      return false;
+    }
+    if (!getType().equals(other.getType())) {
+      return false;
+    }
+    if (!getUnit().equals(other.getUnit())) {
+      return false;
+    }
+    if (!getDescription().equals(other.getDescription())) {
+      return false;
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/866bacec/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsImpl.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsImpl.java
new file mode 100644
index 0000000..ea3b953
--- /dev/null
+++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsImpl.java
@@ -0,0 +1,588 @@
+/*
+ * 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 com.gemstone.gemfire.internal.statistics;
+
+//import com.gemstone.gemfire.distributed.DistributedSystem;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.DoubleSupplier;
+import java.util.function.IntSupplier;
+import java.util.function.LongSupplier;
+
+import com.gemstone.gemfire.StatisticDescriptor;
+import com.gemstone.gemfire.Statistics;
+import com.gemstone.gemfire.StatisticsType;
+import com.gemstone.gemfire.internal.concurrent.Atomics;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+import com.gemstone.gemfire.internal.logging.LogService;
+import com.gemstone.gemfire.internal.util.concurrent.CopyOnWriteHashMap;
+
+import org.apache.logging.log4j.Logger;
+
+// @todo darrel Add statistics instances to archive when they are created. 
+/**
+ * An object that maintains the values of various application-defined
+ * statistics.  The statistics themselves are described by an instance
+ * of {@link StatisticsType}.
+ *
+ * <P>
+ *
+ * For optimal statistic access, each statistic may be referred to by
+ * its {@link #nameToId id} in the statistics object.
+ *
+ * <P>
+ *
+ * @see <A href="package-summary.html#statistics">Package introduction</A>
+ *
+ *
+ * @since GemFire 3.0
+ */
+public abstract class StatisticsImpl implements Statistics {
+  /** logger - not private for tests */
+  static Logger logger = LogService.getLogger();
+
+  /** The type of this statistics instance */
+  private final StatisticsTypeImpl type;
+
+  /** The display name of this statistics instance */
+  private final String textId;
+
+  /** Numeric information display with these statistics */
+  private final long numericId;
+
+  /** Non-zero if stats values come from operating system system calls */
+  private final int osStatFlags;
+
+  /** Are these statistics closed? */
+  private boolean closed;
+
+  /** Uniquely identifies this instance */
+  private long uniqueId;
+
+  /**
+   * Suppliers of int sample values to be sampled every sample-interval
+   */
+  private final CopyOnWriteHashMap<Integer, IntSupplier> intSuppliers = new CopyOnWriteHashMap<>();
+  /**
+   * Suppliers of long sample values to be sampled every sample-interval
+   */
+  private final CopyOnWriteHashMap<Integer, LongSupplier> longSuppliers = new CopyOnWriteHashMap<>();
+  /**
+   * Suppliers of double sample values to be sampled every sample-interval
+   */
+  private final CopyOnWriteHashMap<Integer, DoubleSupplier> doubleSuppliers = new CopyOnWriteHashMap<>();
+
+  /**
+   * Suppliers that have previously failed. Tracked to avoid logging many messages about
+   * a failing supplier
+   */
+  private final Set<Object> flakySuppliers = new HashSet<Object>();
+
+  ///////////////////////  Constructors  ///////////////////////
+
+  /** factory method to create a class that implements Statistics
+   */
+  public static Statistics createAtomicNoOS(StatisticsType type, String textId,
+                                            long numericId, long uniqueId,
+                                            StatisticsManager mgr) {
+    return Atomics.createAtomicStatistics(type, textId, numericId, uniqueId, mgr);
+  }
+  /**
+   * Creates a new statistics instance of the given type and unique id
+   *
+   * @param type
+   *        A description of the statistics
+   * @param textId
+   *        Text that helps identifies this instance
+   * @param numericId
+   *        A number that helps identify this instance
+   * @param uniqueId
+   *        A number that uniquely identifies this instance
+   * @param osStatFlags
+   *        Non-zero if stats require system calls to collect them; for internal use only
+   */
+  public StatisticsImpl(StatisticsType type, String textId,
+                        long numericId, long uniqueId, int osStatFlags) {
+    this.type = (StatisticsTypeImpl)type;
+    this.textId = textId;
+    this.numericId = numericId;
+    this.uniqueId = uniqueId;
+    this.osStatFlags = osStatFlags;
+    closed = false;
+  }
+
+  //////////////////////  Instance Methods  //////////////////////
+
+  public final boolean usesSystemCalls() {
+    return this.osStatFlags != 0;
+  }
+
+  public final int getOsStatFlags() {
+    return this.osStatFlags;
+  }
+
+  public final int nameToId(String name) {
+    return this.type.nameToId(name);
+  }
+
+  public final StatisticDescriptor nameToDescriptor(String name) {
+    return this.type.nameToDescriptor(name);
+  }
+
+  public void close() {
+    this.closed = true;
+  }
+  
+  public final boolean isClosed() {
+    return this.closed;
+  }
+
+  public abstract boolean isAtomic();
+
+  private final boolean isOpen() { // fix for bug 29973
+    return !this.closed;
+  }
+
+  ////////////////////////  attribute Methods  ///////////////////////
+
+  public final StatisticsType getType() {
+    return this.type;
+  }
+  public final String getTextId() {
+    return this.textId;
+  }
+  public final long getNumericId() {
+    return this.numericId;
+  }
+  
+  /**
+   * Gets the unique id for this resource
+   */
+  public long getUniqueId() {
+    return this.uniqueId;
+  }
+  /**
+   * Sets a unique id for this resource.
+   */
+  public void setUniqueId(long uid) {
+    this.uniqueId = uid;
+  }
+
+  ////////////////////////  set() Methods  ///////////////////////
+
+  public final void setInt(String name, int value) {
+    setInt(nameToDescriptor(name), value);
+  }
+
+  public final void setInt(StatisticDescriptor descriptor, int value) {
+    setInt(getIntId(descriptor), value);
+  }
+
+  public final void setInt(int id, int value) {
+    if (isOpen()) {
+      _setInt(id, value);
+    }
+  }
+
+  /**
+   * Sets the value of a statistic of type <code>int</code> at the
+   * given offset, but performs no type checking.
+   */
+  protected abstract void _setInt(int offset, int value);
+
+  public final void setLong(String name, long value) {
+    setLong(nameToDescriptor(name), value);
+  }
+
+  public final void setLong(StatisticDescriptor descriptor, long value) {
+    setLong(getLongId(descriptor), value);
+  }
+
+  public final void setLong(int id, long value) {
+    if (isOpen()) {
+      _setLong(id, value);
+    }
+  }
+
+  /**
+   * Sets the value of a statistic of type <code>long</code> at the
+   * given offset, but performs no type checking.
+   */  
+  protected abstract void _setLong(int offset, long value);
+
+  public final void setDouble(String name, double value) {
+    setDouble(nameToDescriptor(name), value);
+  }
+
+  public final void setDouble(StatisticDescriptor descriptor, double value) {
+    setDouble(getDoubleId(descriptor), value);
+  }
+
+  public final void setDouble(int id, double value) {
+    if (isOpen()) {
+      _setDouble(id, value);
+    }
+  }
+
+  /**
+   * Sets the value of a statistic of type <code>double</code> at the
+   * given offset, but performs no type checking.
+   */
+  protected abstract void _setDouble(int offset, double value);
+
+  ///////////////////////  get() Methods  ///////////////////////
+
+  public final int getInt(String name) {
+    return getInt(nameToDescriptor(name));
+  }
+
+  public final int getInt(StatisticDescriptor descriptor) {
+    return getInt(getIntId(descriptor));
+  }
+
+  public final int getInt(int id) {
+    if (isOpen()) {
+      return _getInt(id);
+    } else {
+      return 0;
+    }
+  }
+
+  /**
+   * Returns the value of the statistic of type <code>int</code> at
+   * the given offset, but performs no type checking.
+   */
+  protected abstract int _getInt(int offset);
+
+
+  public final long getLong(String name) {
+    return getLong(nameToDescriptor(name));
+  }
+
+  public final long getLong(StatisticDescriptor descriptor) {
+    return getLong(getLongId(descriptor));
+  }
+
+  public final long getLong(int id) {
+    if (isOpen()) {
+      return _getLong(id);
+    } else {
+      return 0;
+    }
+  }
+
+
+  /**
+   * Returns the value of the statistic of type <code>long</code> at
+   * the given offset, but performs no type checking.
+   */
+  protected abstract long _getLong(int offset);
+
+  public final double getDouble(String name) {
+    return getDouble(nameToDescriptor(name));
+  }
+
+  public final double getDouble(StatisticDescriptor descriptor) {
+    return getDouble(getDoubleId(descriptor));
+  }
+
+  public final double getDouble(int id) {
+    if (isOpen()) {
+      return _getDouble(id);
+    } else {
+      return 0.0;
+    }
+  }
+
+  /**
+   * Returns the value of the statistic of type <code>double</code> at
+   * the given offset, but performs no type checking.
+   */
+  protected abstract double _getDouble(int offset);
+
+  public final Number get(StatisticDescriptor descriptor) {
+    if (isOpen()) {
+      return _get((StatisticDescriptorImpl)descriptor);
+    } else {
+      return Integer.valueOf(0);
+    }
+  }
+
+  public final Number get(String name) {
+    return get(nameToDescriptor(name));
+  }
+
+  public long getRawBits(StatisticDescriptor descriptor) {
+    if (isOpen()) {
+      return _getRawBits((StatisticDescriptorImpl)descriptor);
+    } else {
+      return 0;
+    }
+  }
+
+  public long getRawBits(String name) {
+    return getRawBits(nameToDescriptor(name));
+  }
+
+  ////////////////////////  inc() Methods  ////////////////////////
+
+  public final void incInt(String name, int delta) {
+    incInt(nameToDescriptor(name), delta);
+  }
+
+  public final void incInt(StatisticDescriptor descriptor, int delta) {
+    incInt(getIntId(descriptor), delta);
+  }
+
+  public final void incInt(int id, int delta) {
+    if (isOpen()) {
+      _incInt(id, delta);
+    }
+  }
+
+  /**
+   * Increments the value of the statistic of type <code>int</code> at
+   * the given offset by a given amount, but performs no type checking.
+   */
+  protected abstract void _incInt(int offset, int delta);
+
+  public final void incLong(String name, long delta) {
+    incLong(nameToDescriptor(name), delta);
+  }
+  public final void incLong(StatisticDescriptor descriptor, long delta) {
+    incLong(getLongId(descriptor), delta);
+  }
+  public final void incLong(int id, long delta) {
+    if (isOpen()) {
+      _incLong(id, delta);
+    }
+  }
+
+  /**
+   * Increments the value of the statistic of type <code>long</code> at
+   * the given offset by a given amount, but performs no type checking.
+   */
+  protected abstract void _incLong(int offset, long delta);
+
+  public final void incDouble(String name, double delta) {
+    incDouble(nameToDescriptor(name), delta);
+  }
+
+  public final void incDouble(StatisticDescriptor descriptor, double delta) {
+    incDouble(getDoubleId(descriptor), delta);
+  }
+
+  public final void incDouble(int id, double delta) {
+    if (isOpen()) {
+      _incDouble(id, delta);
+    }
+  }
+
+  /**
+   * Increments the value of the statistic of type <code>double</code> at
+   * the given offset by a given amount, but performs no type checking.
+   */
+  protected abstract void _incDouble(int offset, double delta);
+
+  /**
+   * For internal use only.
+   * Tells the implementation to prepare the data in this instance
+   * for sampling.
+   * @since GemFire 5.1
+   */
+  public void prepareForSample() {
+    // nothing needed in this impl.
+  }
+
+  /**
+   * Invoke sample suppliers to retrieve the current value for
+   * the suppler controlled sets and update the stats to reflect
+   * the supplied values.
+   * @return the number of callback errors that occurred while
+   * sampling stats
+   */
+  public int invokeSuppliers() {
+    int errors = 0;
+    for(Map.Entry<Integer, IntSupplier> entry: intSuppliers.entrySet()) {
+      try {
+        _setInt(entry.getKey(), entry.getValue().getAsInt());
+      } catch(Throwable t) {
+        logSupplierError(t, entry.getKey(), entry.getValue());
+        errors++;
+      }
+    }
+    for(Map.Entry<Integer, LongSupplier> entry: longSuppliers.entrySet()) {
+      try {
+        _setLong(entry.getKey(), entry.getValue().getAsLong());
+      } catch(Throwable t) {
+        logSupplierError(t, entry.getKey(), entry.getValue());
+        errors++;
+      }
+    }
+    for(Map.Entry<Integer, DoubleSupplier> entry: doubleSuppliers.entrySet()) {
+      try {
+        _setDouble(entry.getKey(), entry.getValue().getAsDouble());
+      } catch(Throwable t) {
+        logSupplierError(t, entry.getKey(), entry.getValue());
+        errors++;
+      }
+    }
+
+    return errors;
+  }
+
+  private void logSupplierError(final Throwable t, int statId, Object supplier) {
+    if(flakySuppliers.add(supplier)) {
+      logger.warn("Error invoking supplier for stat {}, id {}", this.getTextId(), statId, t);
+    }
+  }
+
+  /**
+   * @return the number of statistics that are measured using supplier callbacks
+   */
+  public int getSupplierCount() {
+    return intSuppliers.size() + doubleSuppliers.size() + longSuppliers.size();
+  }
+
+  @Override
+  public IntSupplier setIntSupplier(final int id, final IntSupplier supplier) {
+    if(id >= type.getIntStatCount()) {
+      throw new IllegalArgumentException("Id " + id + " is not in range for stat" + type);
+    }
+    return intSuppliers.put(id, supplier);
+  }
+
+  @Override
+  public IntSupplier setIntSupplier(final String name, final IntSupplier supplier) {
+    return setIntSupplier(nameToId(name), supplier);
+  }
+
+  @Override
+  public IntSupplier setIntSupplier(final StatisticDescriptor descriptor, final IntSupplier supplier) {
+    return setIntSupplier(getIntId(descriptor), supplier);
+  }
+
+  @Override
+  public LongSupplier setLongSupplier(final int id, final LongSupplier supplier) {
+    if(id >= type.getLongStatCount()) {
+      throw new IllegalArgumentException("Id " + id + " is not in range for stat" + type);
+    }
+    return longSuppliers.put(id, supplier);
+  }
+
+  @Override
+  public LongSupplier setLongSupplier(final String name, final LongSupplier supplier) {
+    return setLongSupplier(nameToId(name), supplier);
+  }
+
+  @Override
+  public LongSupplier setLongSupplier(final StatisticDescriptor descriptor, final LongSupplier supplier) {
+    return setLongSupplier(getLongId(descriptor), supplier);
+  }
+
+  @Override
+  public DoubleSupplier setDoubleSupplier(final int id, final DoubleSupplier supplier) {
+    if(id >= type.getDoubleStatCount()) {
+      throw new IllegalArgumentException("Id " + id + " is not in range for stat" + type);
+    }
+    return doubleSuppliers.put(id, supplier);
+  }
+
+  @Override
+  public DoubleSupplier setDoubleSupplier(final String name, final DoubleSupplier supplier) {
+    return setDoubleSupplier(nameToId(name), supplier);
+  }
+
+  @Override
+  public DoubleSupplier setDoubleSupplier(final StatisticDescriptor descriptor, final DoubleSupplier supplier) {
+    return setDoubleSupplier(getDoubleId(descriptor), supplier);
+  }
+
+  @Override
+  public int hashCode() {
+    return (int)this.uniqueId;
+  }
+  @Override
+  public boolean equals(Object o) {
+    if (o == null) {
+      return false;
+    }
+    if (!(o instanceof StatisticsImpl)) {
+      return false;
+    }
+    StatisticsImpl other = (StatisticsImpl)o;
+    return this.uniqueId == other.getUniqueId();
+  }
+
+  private final static int getIntId(StatisticDescriptor descriptor) {
+    return ((StatisticDescriptorImpl)descriptor).checkInt();
+  }
+  
+  private final static int getLongId(StatisticDescriptor descriptor) {
+    return ((StatisticDescriptorImpl)descriptor).checkLong();
+  }
+  
+  private final static int getDoubleId(StatisticDescriptor descriptor) {
+    return ((StatisticDescriptorImpl)descriptor).checkDouble();
+  }
+  
+  /**
+   * Returns the value of the specified statistic descriptor.
+   */
+  private final Number _get(StatisticDescriptorImpl stat) {
+    switch (stat.getTypeCode()) {
+    case StatisticDescriptorImpl.INT:
+      return Integer.valueOf(_getInt(stat.getId()));
+    case StatisticDescriptorImpl.LONG:
+      return Long.valueOf(_getLong(stat.getId()));
+    case StatisticDescriptorImpl.DOUBLE:
+      return Double.valueOf(_getDouble(stat.getId()));
+    default:
+      throw new RuntimeException(LocalizedStrings.StatisticsImpl_UNEXPECTED_STAT_DESCRIPTOR_TYPE_CODE_0.toLocalizedString(Byte.valueOf(stat.getTypeCode())));
+    }
+  }
+  /**
+   * Returns the bits that represent the raw value of the
+   * specified statistic descriptor.
+   */
+  private final long _getRawBits(StatisticDescriptorImpl stat) {
+    switch (stat.getTypeCode()) {
+    case StatisticDescriptorImpl.INT:
+      return _getInt(stat.getId());
+    case StatisticDescriptorImpl.LONG:
+      return _getLong(stat.getId());
+    case StatisticDescriptorImpl.DOUBLE:
+      return Double.doubleToRawLongBits(_getDouble(stat.getId()));
+    default:
+      throw new RuntimeException(LocalizedStrings.StatisticsImpl_UNEXPECTED_STAT_DESCRIPTOR_TYPE_CODE_0.toLocalizedString(Byte.valueOf(stat.getTypeCode())));
+    }
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder(getClass().getName());
+    sb.append("@").append(System.identityHashCode(this)).append("{");
+    sb.append("uniqueId=").append(this.uniqueId);
+    sb.append(", numericId=").append(this.numericId);
+    sb.append(", textId=").append(this.textId);
+    sb.append(", type=").append(this.type.getName());
+    sb.append(", closed=").append(this.closed);
+    sb.append("}");
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/866bacec/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsManager.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsManager.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsManager.java
new file mode 100644
index 0000000..9257271
--- /dev/null
+++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsManager.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.gemstone.gemfire.internal.statistics;
+
+import java.util.List;
+
+import com.gemstone.gemfire.Statistics;
+import com.gemstone.gemfire.StatisticsFactory;
+
+/**
+ * Defines the contract that a statistics factory must implement
+ * for its Statistics instances. This is an internal implementation
+ * specific interface.
+ *
+ *
+ */
+public interface StatisticsManager extends StatisticsFactory {
+  /**
+   * Called when the Statistics instance <code>s</code> is closed.
+   */
+  public void destroyStatistics(Statistics s);
+  /**
+   * Returns a name that can be used to identify the manager
+   */
+  public String getName();
+  /**
+   * Returns a numeric id that can be used to identify the manager
+   */
+  public long getId();
+  /**
+   * Returns the start time of this manager.
+   */
+  public long getStartTime();
+  /**
+   * Returns a value that changes any time a Statistics instance is added
+   * or removed from this manager.
+   */
+  public int getStatListModCount();
+  /**
+   * Returns a list of all the Statistics this manager is currently managing.
+   */
+  public List<Statistics> getStatsList();
+  
+  /**
+   * Returns the current number of statistics instances.
+   */
+  public int getStatisticsCount();
+
+  /**
+   * Returns the statistics resource instance given its id.
+   */
+  public Statistics findStatistics(long id);
+
+  /**
+   * Returns true if the specified statistic resource still exists.
+   */
+  public boolean statisticsExists(long id);
+
+  /**
+   * Returns an array of all the current statistic resource instances.
+   */
+  public Statistics[] getStatistics();
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/866bacec/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsTypeFactoryImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsTypeFactoryImpl.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsTypeFactoryImpl.java
new file mode 100644
index 0000000..8450dd3
--- /dev/null
+++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/statistics/StatisticsTypeFactoryImpl.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 com.gemstone.gemfire.internal.statistics;
+
+import com.gemstone.gemfire.*;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * The implementation of {@link StatisticsTypeFactory}.
+ * Each VM can any have a single instance of this class which can
+ * be accessed by calling {@link #singleton()}.
+ *
+ * @see <A href="package-summary.html#statistics">Package introduction</A>
+ *
+ *
+ * @since GemFire 3.0
+ *
+ */
+public class StatisticsTypeFactoryImpl implements StatisticsTypeFactory {
+  // static fields
+  private final static StatisticsTypeFactoryImpl singleton = new StatisticsTypeFactoryImpl();
+
+  // static methods
+  /**
+   * Returns the single instance of this class.
+   */
+  public final static StatisticsTypeFactory singleton() {
+    return singleton;
+  }
+  
+  protected final static void clear() {
+    singleton.statTypes.clear();
+  }
+
+  // constructors
+  private StatisticsTypeFactoryImpl() {
+  }
+  
+  // instance fields
+  private final HashMap statTypes = new HashMap();
+
+  // instance methods
+  /**
+   * Adds an already created type. If the type has already been
+   * added and is equal to the new one then the new one is dropped and the existing one returned.
+   * @throws IllegalArgumentException if the type already exists and is not equal to the new type
+   */
+  public StatisticsType addType(StatisticsType t) {
+    StatisticsType result = t;
+    synchronized (this.statTypes) {
+      StatisticsType currentValue = findType(result.getName());
+      if (currentValue == null) {
+        this.statTypes.put(result.getName(), result);
+      } else if (result.equals(currentValue)) {
+        result = currentValue;
+      } else {
+        throw new IllegalArgumentException(LocalizedStrings.StatisticsTypeFactoryImpl_STATISTICS_TYPE_NAMED_0_ALREADY_EXISTS.toLocalizedString(result.getName()));
+      }
+    }
+    return result;
+  }
+  public StatisticsType createType(String name, String description,
+                                   StatisticDescriptor[] stats) {
+    return addType(new StatisticsTypeImpl(name, description, stats));
+  }
+  public StatisticsType findType(String name) {
+    return (StatisticsType)this.statTypes.get(name);
+  }
+  public StatisticsType[] createTypesFromXml(Reader reader)
+    throws IOException {
+    return StatisticsTypeImpl.fromXml(reader, this);
+  }
+
+  public StatisticDescriptor createIntCounter(String name, String description,
+                                              String units) {
+    return StatisticDescriptorImpl.createIntCounter(name, description, units, true);
+  }
+  public StatisticDescriptor createLongCounter(String name, String description,
+                                               String units) {
+    return StatisticDescriptorImpl.createLongCounter(name, description, units, true);
+  }
+  public StatisticDescriptor createDoubleCounter(String name, String description,
+                                                 String units) {
+    return StatisticDescriptorImpl.createDoubleCounter(name, description, units, true);
+  }
+  public StatisticDescriptor createIntGauge(String name, String description,
+                                            String units) {
+    return StatisticDescriptorImpl.createIntGauge(name, description, units, false);
+  }
+  public StatisticDescriptor createLongGauge(String name, String description,
+                                             String units) {
+    return StatisticDescriptorImpl.createLongGauge(name, description, units, false);
+  }
+  public StatisticDescriptor createDoubleGauge(String name, String description,
+                                               String units) {
+    return StatisticDescriptorImpl.createDoubleGauge(name, description, units, false);
+  }
+
+  public StatisticDescriptor createIntCounter(String name, String description,
+                                              String units, boolean largerBetter) {
+    return StatisticDescriptorImpl.createIntCounter(name, description, units, largerBetter);
+  }
+  public StatisticDescriptor createLongCounter(String name, String description,
+                                               String units, boolean largerBetter) {
+    return StatisticDescriptorImpl.createLongCounter(name, description, units, largerBetter);
+  }
+  public StatisticDescriptor createDoubleCounter(String name, String description,
+                                                 String units, boolean largerBetter) {
+    return StatisticDescriptorImpl.createDoubleCounter(name, description, units, largerBetter);
+  }
+  public StatisticDescriptor createIntGauge(String name, String description,
+                                            String units, boolean largerBetter) {
+    return StatisticDescriptorImpl.createIntGauge(name, description, units, largerBetter);
+  }
+  public StatisticDescriptor createLongGauge(String name, String description,
+                                             String units, boolean largerBetter) {
+    return StatisticDescriptorImpl.createLongGauge(name, description, units, largerBetter);
+  }
+  public StatisticDescriptor createDoubleGauge(String name, String description,
+                                               String units, boolean largerBetter) {
+    return StatisticDescriptorImpl.createDoubleGauge(name, description, units, largerBetter);
+  }
+}


Mime
View raw message