All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scalar.db.sql.common.metadata.CachedMetadata Maven / Gradle / Ivy

There is a newer version: 3.14.0
Show newest version
package com.scalar.db.sql.common.metadata;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.scalar.db.sql.metadata.Metadata;
import com.scalar.db.sql.metadata.NamespaceMetadata;
import com.scalar.db.sql.metadata.UserMetadata;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;

@ThreadSafe
public class CachedMetadata implements Metadata {

  private static final String NAMESPACE_NAMES_CACHE_KEY = "key";

  /**
   * A cache for namespace metadata. The key is a namespace name, and the value is a namespace
   * metadata.
   */
  private final LoadingCache> namespaceMetadataCache;

  /**
   * A cache for namespace names. The key is a fixed string {@code NAMESPACE_NAMES_CACHE_KEY}, and
   * the value is a list of namespace names. It is assumed that this cache has only one entry for
   * the fixed string.
   */
  private final LoadingCache> namespaceNamesCache;

  private final Metadata metadata;

  private CachedMetadata(Metadata metadata, long cacheExpirationTimeSecs) {
    this.metadata = metadata;

    namespaceMetadataCache =
        createNamespaceMetadataCache(Objects.requireNonNull(metadata), cacheExpirationTimeSecs);
    namespaceNamesCache = createNamespaceNamesCache(metadata, cacheExpirationTimeSecs);
  }

  private LoadingCache> createNamespaceMetadataCache(
      Metadata metadata, long cacheExpirationTimeSecs) {
    CacheBuilder builder = CacheBuilder.newBuilder();
    if (cacheExpirationTimeSecs >= 0) {
      builder.expireAfterWrite(cacheExpirationTimeSecs, TimeUnit.SECONDS);
    }
    return builder.build(
        new CacheLoader>() {
          @Nonnull
          @Override
          public Optional load(@Nonnull String namespaceName) {
            return metadata
                .getNamespace(namespaceName)
                .map(n -> new CachedNamespaceMetadata(n, cacheExpirationTimeSecs));
          }
        });
  }

  private LoadingCache> createNamespaceNamesCache(
      Metadata metadata, long cacheExpirationTimeSecs) {
    CacheBuilder builder = CacheBuilder.newBuilder();
    if (cacheExpirationTimeSecs >= 0) {
      builder.expireAfterWrite(cacheExpirationTimeSecs, TimeUnit.SECONDS);
    }
    return builder.build(
        new CacheLoader>() {
          @Nonnull
          @Override
          public List load(@Nonnull String key) {
            Map namespaces = metadata.getNamespaces();

            // Update the namespace metadata cache, as well
            namespaces.forEach(
                (name, namespace) -> namespaceMetadataCache.put(name, Optional.of(namespace)));

            return ImmutableList.copyOf(namespaces.keySet());
          }
        });
  }

  @Override
  public Map getNamespaces() {
    try {
      List namespaceNames = namespaceNamesCache.getUnchecked(NAMESPACE_NAMES_CACHE_KEY);
      Map namespaces = new HashMap<>();
      for (String namespaceName : namespaceNames) {
        Optional namespaceMetadata = getNamespace(namespaceName);
        namespaceMetadata.ifPresent(metadata -> namespaces.put(namespaceName, metadata));
      }
      return namespaces;
    } catch (UncheckedExecutionException e) {
      throw (RuntimeException) e.getCause();
    }
  }

  @Override
  public Optional getNamespace(String namespaceName) {
    try {
      return namespaceMetadataCache.getUnchecked(namespaceName);
    } catch (UncheckedExecutionException e) {
      throw (RuntimeException) e.getCause();
    }
  }

  public void invalidateNamespaceNamesCache() {
    namespaceMetadataCache.invalidate(NAMESPACE_NAMES_CACHE_KEY);
  }

  public void invalidateNamespaceMetadataCache(String namespaceName) {
    namespaceMetadataCache.invalidate(namespaceName);
  }

  @Override
  public Map getUsers() {
    return metadata.getUsers();
  }

  @Override
  public Optional getUser(String username) {
    return metadata.getUser(username);
  }

  public static CachedMetadata create(Metadata metadata, long cacheExpirationTimeSecs) {
    return new CachedMetadata(metadata, cacheExpirationTimeSecs);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy