@Test
  public void testDistributedStats() {
    final String name = getUniqueName();
    final Object key = "KEY";
    final Object value = "VALUE";

    SerializableRunnable create = new CacheSerializableRunnable("Create Region") {
      @Override
      public void run2() throws CacheException {
        AttributesFactory factory = new AttributesFactory();
        factory.setScope(Scope.DISTRIBUTED_ACK);
        factory.setEarlyAck(false);
        factory.setStatisticsEnabled(true);
        createRegion(name, factory.create());
      }
    };

    Host host = Host.getHost(0);
    VM vm0 = host.getVM(0);
    VM vm1 = host.getVM(1);

    vm0.invoke(create);
    vm1.invoke(create);

    vm0.invoke(new CacheSerializableRunnable("Define entry") {
      @Override
      public void run2() throws CacheException {
        Region region = getRootRegion().getSubregion(name);
        // region.create(key, null);
        region.put(key, value);
        CacheStatistics stats = region.getEntry(key).getStatistics();
        lastAccessed = stats.getLastAccessedTime();
        lastModified = stats.getLastModifiedTime();
        getCache().getLogger()
            .fine("DEFINE: lastAccessed: " + lastAccessed + ", lastModified: " + lastModified);
        assertEquals(0, stats.getHitCount());
        assertEquals(0, stats.getMissCount());
        assertTrue(lastModified > 0);
        lastModifiedLocal = lastModified;
      }
    });

    vm1.invoke(new CacheSerializableRunnable("Net search") {
      @Override
      public void run2() throws CacheException {
        Region region = getRootRegion().getSubregion(name);
        Object result = region.get(key);
        assertEquals(value, result);
        CacheStatistics stats = region.getEntry(key).getStatistics();
        lastModifiedRemote = stats.getLastModifiedTime();
        getCache().getLogger().fine("NETSEARCH: lastAccessed: " + stats.getLastAccessedTime()
            + ", lastModified: " + stats.getLastModifiedTime());

      }
    });

    vm0.invoke(new CacheSerializableRunnable("Verify stats") {
      @Override
      public void run2() throws CacheException {
        Region region = getRootRegion().getSubregion(name);
        CacheStatistics stats = region.getEntry(key).getStatistics();
        assertEquals(lastAccessed, stats.getLastAccessedTime());
        assertEquals(lastModified, stats.getLastModifiedTime());
        assertEquals(0, stats.getHitCount());
        assertEquals(0, stats.getMissCount());
      }
    });

    assertEquals(lastModifiedLocal, lastModifiedRemote);

    // make sure at least 100ms have passed; otherwise, the update
    // may not actually bump the statistics
    Wait.pause(100);

    vm1.invoke(new CacheSerializableRunnable("Update") {
      @Override
      public void run2() throws CacheException {
        Region region = getRootRegion().getSubregion(name);
        // assertNull(region.getEntry(key));
        region.put(key, value);
        assertEquals(value, region.getEntry(key).getValue());
        CacheStatistics stats = region.getEntry(key).getStatistics();
        getCache().getLogger().fine("UPDATE: lastAccessed: " + stats.getLastAccessedTime()
            + ", lastModified: " + stats.getLastModifiedTime());
      }
    });

    final long errorMargin = 50;

    vm0.invoke(new CacheSerializableRunnable("Verify stats") {
      @Override
      public void run2() throws CacheException {
        Region region = getRootRegion().getSubregion(name);
        CacheStatistics stats = region.getEntry(key).getStatistics();
        long ta = stats.getLastAccessedTime();
        long tm = stats.getLastModifiedTime();
        long hc = stats.getHitCount();
        long mc = stats.getMissCount();

        getCache().getLogger().fine("VERIFY: lastAccessed: " + ta + ", lastModified: " + tm);
        assertTrue("lastAccessedTime was " + ta + " but was expected to be > " + lastAccessed,
            lastAccessed < (ta + errorMargin));
        assertTrue("lastAccessed=" + lastAccessed + " should be < stats.getLastModifiedTime=" + tm,
            lastAccessed < (tm + errorMargin));
        assertEquals(0, hc);
        assertEquals(0, mc);
        lastAccessed = stats.getLastAccessedTime();
        lastModified = stats.getLastModifiedTime();
      }
    });

    vm1.invoke(new CacheSerializableRunnable("Invalidate") {
      @Override
      public void run2() throws CacheException {
        Region region = getRootRegion().getSubregion(name);
        region.invalidate(key);
      }
    });
    vm0.invoke(new CacheSerializableRunnable("Verify stats") {
      @Override
      public void run2() throws CacheException {
        Region region = getRootRegion().getSubregion(name);
        CacheStatistics stats = region.getEntry(key).getStatistics();
        assertEquals(lastAccessed, stats.getLastAccessedTime());
        assertEquals(lastModified, stats.getLastModifiedTime());
        assertEquals(0, stats.getHitCount());
        assertEquals(0, stats.getMissCount());
      }
    });
    vm1.invoke(new CacheSerializableRunnable("Destroy Entry") {
      @Override
      public void run2() throws CacheException {
        Region region = getRootRegion().getSubregion(name);
        region.destroy(key);
      }
    });
    vm0.invoke(new CacheSerializableRunnable("Verify region stats") {
      @Override
      public void run2() throws CacheException {
        Region region = getRootRegion().getSubregion(name);
        CacheStatistics stats = region.getStatistics();

        // lastAccessed var contains stat from an Entry, which may be
        // up to 100 ms off from stat in Region because Entry has
        // less precision
        // assertIndexDetailsEquals(lastAccessed, stats.getLastAccessedTime(), 100);
        assertEquals(0, stats.getHitCount());
        assertEquals(0, stats.getMissCount());
      }
    });
  }
Tests that distributed operations update the {@link CacheStatistics#getLastModifiedTime last
modified time}, but not the {@link CacheStatistics#getLastAccessedTime last accessed time}. It
also validates that distributed operations do not affect the hit and miss counts in remote
caches.
geode-core/src/distributedTest/java/org/apache/geode/cache30/CacheStatisticsDUnitTest.java