0

我有一个缓存加载器,它缓存来自 API 的响应(以列表的形式)。现在我的函数不需要直接响应数据,所以我创建了一个提供者,它可以处理这些原始响应并充当一个预言机,它允许我发送所需的数据而不是整个列表。

我当前方法的问题是,对于每个这样的响应,提供者必须遍历整个列表,即使列表与以前相同;这使得每次调用的复杂性为 O(n) 而不是我想要的 O(1)。

我能想到的潜在解决方案

  1. 而是缓存处理过的数据。现在的问题是,在这种情况下我需要两个不同的缓存,并且每次刷新都会从 API 中不必要地获取相同的结果。
  2. 仅当缓存值已更改时才在提供程序中迭代我想这样做但我找不到知道缓存是否已更改值的方法,我所有的方法都需要传递数据,这将再次需要 O(n)时间。

任何人都可以提出解决此问题的好方法吗?

规则信息缓存加载器类


import com.google.common.cache.CacheLoader;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.ParametersAreNonnullByDefault;

final class RuleInfoLoader extends CacheLoader<RuleType, List<RuleInfo>> {
  private final ConfigServiceGrpc.ConfigServiceBlockingStub configServiceBlockingStub;
  private final long callTimeout;

  RuleInfoLoader(ConfigServiceClientConfig clientConfig) {
    callTimeout = clientConfig.getCallTimeout();
    configServiceBlockingStub = ConfigServiceGrpc.newBlockingStub();
  }

  @Override
  @ParametersAreNonnullByDefault
  public List<RuleInfo> load(RuleType ruleType) {
    return fetchRuleInfo(ruleType);
  }

  private List<RuleInfo> fetchRuleInfo(RuleType ruleType) {
    return configServiceBlockingStub
        .withDeadlineAfter(callTimeout, TimeUnit.MILLISECONDS)
        .getAnomalyRuleInfos(
            GetRuleInfosRequest.newBuilder().setRuleType(ruleType).build())
        .getRuleInfosList();
  }
}

规则信息提供者

import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableMap;
import com.typesafe.config.Config;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

public class RuleInfoProvider {
  private LoadingCache<RuleType, List<RuleInfo>> ruleInfoCache;

  public RuleInfoProvider(Config config) {
    initCache(config);
  }

  public Map<String, RuleInfo> getRuleMapping() {
    ImmutableMap.Builder<String, RuleInfo> mapBuilder = new ImmutableMap.Builder<>();
    getRuleInfo(RuleType.a)
        .forEach(rule -> mapBuilder.put(rule.getRuleId(), rule));
    getRuleInfo(RuleType.b)
        .forEach(rule -> mapBuilder.put(rule.getRuleId(), rule));
    getRuleInfo(RuleType.c)
        .forEach(rule -> mapBuilder.put(rule.getRuleId(), rule));
    return mapBuilder.build();
  }

  public Map<Class<? extends RuleInfo>, List<String>> getPathsMapping() {
    return new ImmutableMap.Builder<Class<? extends RuleInfo>, List<String>>()
        .put(
            Class_A.class,
            getRuleInfo(RuleType.a).stream()
                .map(RuleInfo::getPath)
                .collect(Collectors.toList()))
        .put(
            Class_B.class,
            getRuleInfo(RuleType.b).stream()
                .map(RuleInfo::getPath)
                .collect(Collectors.toList()))
        .put(
            Class_c.class,
            getRuleInfo(RuleType.c).stream()
                .map(RuleInfo::getPath)
                .collect(Collectors.toList()))
        .build();
  }

  private List<RuleInfo> getRuleInfo(RuleType ruleType) {
    try {
      return ruleInfoCache.get(ruleType);
    } catch (Exception e) {
      return Collections.emptyList();
    }
  }
  
  private void initCache(Config config) {
    ruleInfoCache =
        CacheBuilder.newBuilder()
            .refreshAfterWrite(config.getCacheConfig().getRefreshMs())
            .maximumSize(config.getCacheConfig().getMaxSize())
            .build(
                CacheLoader.asyncReloading(
                    new RuleInfoLoader(config.getConfigServiceClientConfig()),
                    Executors.newSingleThreadScheduledExecutor()));
  }
}
4

0 回答 0