本文主要研究一下Elasticsearch的SingleObjectCache

SingleObjectCache

elasticsearch-7.0.1/server/src/main/java/org/elasticsearch/common/util/SingleObjectCache.java

public abstract class SingleObjectCache<T>{

    private volatile T cached;
    private Lock refreshLock = new ReentrantLock();
    private final TimeValue refreshInterval;
    protected long lastRefreshTimestamp = 0;

    protected SingleObjectCache(TimeValue refreshInterval, T initialValue) {
        if (initialValue == null) {
            throw new IllegalArgumentException("initialValue must not be null");
        }
        this.refreshInterval = refreshInterval;
        cached = initialValue;
    }


    /**
     * Returns the currently cached object and potentially refreshes the cache before returning.
     */
    public T getOrRefresh() {
        if (needsRefresh()) {
            if(refreshLock.tryLock()) {
                try {
                    if (needsRefresh()) { // check again!
                        cached = refresh();
                        assert cached != null;
                        lastRefreshTimestamp = System.currentTimeMillis();
                    }
                } finally {
                    refreshLock.unlock();
                }
            }
        }
        assert cached != null;
        return cached;
    }

    /** Return the potentially stale cached entry. */
    protected final T getNoRefresh() {
        return cached;
    }

    /**
     * Returns a new instance to cache
     */
    protected abstract T refresh();

    /**
     * Returns <code>true</code> iff the cache needs to be refreshed.
     */
    protected boolean needsRefresh() {
        if (refreshInterval.millis() == 0) {
            return true;
        }
        final long currentTime = System.currentTimeMillis();
        return (currentTime - lastRefreshTimestamp) > refreshInterval.millis();
    }
}
  • SingleObjectCache的构造器要求refreshInterval、initialValue两个参数;它提供了getOrRefresh方法,该方法会判断该cached值是否过期,如果过期则调用refresh方法刷新值,同时更新lastRefreshTimestamp,如果没过期则返回cached值

实例

elasticsearch-7.0.1/server/src/main/java/org/elasticsearch/monitor/fs/FsService.java

public class FsService {

    private static final Logger logger = LogManager.getLogger(FsService.class);

    private final FsProbe probe;
    private final TimeValue refreshInterval;
    private final SingleObjectCache<FsInfo> cache;
    private final ClusterInfoService clusterInfoService;

    public static final Setting<TimeValue> REFRESH_INTERVAL_SETTING =
        Setting.timeSetting(
            "monitor.fs.refresh_interval",
            TimeValue.timeValueSeconds(1),
            TimeValue.timeValueSeconds(1),
            Property.NodeScope);

    public FsService(final Settings settings, final NodeEnvironment nodeEnvironment, ClusterInfoService clusterInfoService) {
        this.probe = new FsProbe(nodeEnvironment);
        this.clusterInfoService = clusterInfoService;
        refreshInterval = REFRESH_INTERVAL_SETTING.get(settings);
        logger.debug("using refresh_interval [{}]", refreshInterval);
        cache = new FsInfoCache(refreshInterval, stats(probe, null, logger, null));
    }

    public FsInfo stats() {
        return cache.getOrRefresh();
    }

    private static FsInfo stats(FsProbe probe, FsInfo initialValue, Logger logger, @Nullable ClusterInfo clusterInfo) {
        try {
            return probe.stats(initialValue, clusterInfo);
        } catch (IOException e) {
            logger.debug("unexpected exception reading filesystem info", e);
            return null;
        }
    }

    private class FsInfoCache extends SingleObjectCache<FsInfo> {

        private final FsInfo initialValue;

        FsInfoCache(TimeValue interval, FsInfo initialValue) {
            super(interval, initialValue);
            this.initialValue = initialValue;
        }

        @Override
        protected FsInfo refresh() {
            return stats(probe, initialValue, logger, clusterInfoService.getClusterInfo());
        }

    }

}
  • FsService的构造器使用FsInfoCache创建了cache,其无参的stats方法执行的是cache.getOrRefresh();FsInfoCache继承了SingleObjectCache,它的refresh方法调用的是stats方法,该方法通过probe.stats(initialValue, clusterInfo)来刷新值

小结

SingleObjectCache的构造器要求refreshInterval、initialValue两个参数;它提供了getOrRefresh方法,该方法会判断该cached值是否过期,如果过期则调用refresh方法刷新值,同时更新lastRefreshTimestamp,如果没过期则返回cached值

doc


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...