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

com.scalar.db.sql.common.metadata.CachedNamespaceMetadata 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.NamespaceMetadata;
import com.scalar.db.sql.metadata.TableMetadata;
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 CachedNamespaceMetadata extends AbstractNamespaceMetadata {

  private final NamespaceMetadata namespaceMetadata;

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

  /**
   * A cache for table names. The key is a namespace name, and the value is a list of table names.
   * It is assumed that this cache has only one entry for the namespace.
   */
  private final LoadingCache> tableNamesCache;

  CachedNamespaceMetadata(NamespaceMetadata namespaceMetadata, long cacheExpirationTimeSecs) {
    this.namespaceMetadata = Objects.requireNonNull(namespaceMetadata);
    tableMetadataCache = createTableMetadataCache(cacheExpirationTimeSecs);
    tableNamesCache = createTableNamesCache(cacheExpirationTimeSecs);
  }

  private LoadingCache> createTableMetadataCache(
      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 tableName) {
            return namespaceMetadata.getTable(tableName);
          }
        });
  }

  private LoadingCache> createTableNamesCache(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 namespaceName) {
            Map tables = namespaceMetadata.getTables();

            // Update the table metadata cache, as well
            tables.forEach((name, table) -> tableMetadataCache.put(name, Optional.of(table)));

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

  @Override
  public String getName() {
    return namespaceMetadata.getName();
  }

  @Override
  public Map getTables() {
    try {
      List tableNames = tableNamesCache.getUnchecked(getName());
      Map tables = new HashMap<>();
      for (String tableName : tableNames) {
        Optional tableMetadata = getTable(tableName);
        tableMetadata.ifPresent(metadata -> tables.put(tableName, metadata));
      }
      return tables;
    } catch (UncheckedExecutionException e) {
      throw (RuntimeException) e.getCause();
    }
  }

  @Override
  public Optional getTable(String tableName) {
    try {
      return tableMetadataCache.getUnchecked(tableName);
    } catch (UncheckedExecutionException e) {
      throw (RuntimeException) e.getCause();
    }
  }

  public void invalidateTableNamesCache() {
    tableNamesCache.invalidate(getName());
  }

  public void invalidateTableMetadataCache(String tableName) {
    tableMetadataCache.invalidate(tableName);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy