/*
* 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.cache.lru;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.geode.Statistics;
import org.apache.geode.StatisticsFactory;
import org.apache.geode.StatisticsType;
import org.apache.geode.internal.Assert;
/**
* Statistics for both the LocalLRUClockHand. Note that all its instance fields are
* <code>final</code>. Thus, we do not need to worry about refreshing an instance when it resides in
* shared memory.
*/
public class LRUStatistics {
/** The Statistics object that we delegate most behavior to */
private final Statistics stats;
protected int limitId;
/**
* the number of destroys that must occur before a list scan is initiated to to remove unlinked
* entries.
*/
protected int destroysLimitId;
protected int counterId;
/** entries that have been evicted from the LRU list */
protected int evictionsId;
/** entries that have been destroyed, but not yet evicted from the LRU list */
protected int destroysId;
protected int evaluationsId;
protected int greedyReturnsId;
// Note: the following atomics have been added so that the LRU code
// does not depend on the value of a statistic for its operations.
// In particular they optimize the "get" methods for these items.
// Striped stats optimize inc but cause set and get to be more expensive.
private final AtomicLong counter = new AtomicLong();
private final AtomicLong limit = new AtomicLong();
private final AtomicLong destroysLimit = new AtomicLong();
private final AtomicLong destroys = new AtomicLong();
private final AtomicLong evictions = new AtomicLong();
///////////////////////// Constructors /////////////////////////
/**
* Constructor for the LRUStatistics object
*
* @param name Description of the Parameter
*/
public LRUStatistics(StatisticsFactory factory, String name, EnableLRU helper) {
String statName = helper.getStatisticsName() + "-" + name;
stats = factory.createAtomicStatistics(helper.getStatisticsType(), statName);
if (!helper.getEvictionAlgorithm().isLRUHeap()) {
limitId = helper.getLimitStatId();
}
destroysLimitId = helper.getDestroysLimitStatId();
counterId = helper.getCountStatId();
evictionsId = helper.getEvictionsStatId();
destroysId = helper.getDestroysStatId();
this.evaluationsId = helper.getEvaluationsStatId();
this.greedyReturnsId = helper.getGreedyReturnsStatId();
}
public LRUStatistics(StatisticsFactory factory, String name, StatisticsType statisticsType) {
stats = factory.createAtomicStatistics(statisticsType, name);
limitId = 0;
destroysLimitId = 0;
counterId = 0;
evictionsId = 0;
destroysId = 0;
this.evaluationsId = 0;
this.greedyReturnsId = 0;
}
public void close() {
stats.close();
}
/** common counter for different lru types */
public long getCounter() {
return this.counter.get();
}
/** limit */
public void setLimit(long newValue) {
Assert.assertTrue(newValue > 0L,
"limit must be positive, an attempt was made to set it to: " + newValue);
long oldValue = this.limit.get();
if (oldValue != newValue) {
this.limit.set(newValue);
stats.setLong(limitId, newValue);
}
}
/** destroy limit */
public void setDestroysLimit(long newValue) {
Assert.assertTrue(newValue > 0L,
"destroys limit must be positive, an attempt was made to set it to: " + newValue);
long oldValue = this.destroysLimit.get();
if (oldValue != newValue) {
this.destroysLimit.set(newValue);
stats.setLong(destroysLimitId, newValue);
}
}
public long getLimit() {
return this.limit.get();
}
public long getDestroysLimit() {
return this.destroysLimit.get();
}
public void updateCounter(long delta) {
if (delta != 0) {
this.counter.getAndAdd(delta);
stats.incLong(counterId, delta);
}
}
public void resetCounter() {
if (this.counter.get() != 0) {
this.counter.set(0);
stats.setLong(counterId, 0);
}
}
// public void setCounter(long newValue) {
// long oldValue = this.counter.get();
// if (oldValue != newValue) {
// this.counter.set(oldValue+newValue);
// stats.setLong(counterId, newValue);
// }
// }
//
public void decrementCounter(long delta) {
if (delta != 0) {
this.counter.addAndGet(-delta);
stats.setLong(counterId, counter.get());
}
}
public void incEvictions() {
this.evictions.getAndAdd(1);
stats.incLong(evictionsId, 1);
}
public void incEvictions(long delta) {
this.evictions.getAndAdd(delta);
stats.incLong(evictionsId, delta);
}
public long getEvictions() {
return this.evictions.get();
}
public void resetDestroys() {
if (this.destroys.get() != 0) {
this.destroys.set(0);
stats.setLong(destroysId, 0);
}
}
public void incDestroys() {
this.destroys.getAndAdd(1);
stats.incLong(destroysId, 1);
}
public long getDestroys() {
return this.destroys.get();
}
public void incEvaluations(long numEvals) {
stats.incLong(evaluationsId, numEvals);
}
public void incGreedyReturns(long numEvals) {
stats.incLong(greedyReturnsId, numEvals);
}
public Statistics getStats() {
return this.stats;
}
}