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

com.pingcap.tikv.catalog.Catalog Maven / Gradle / Ivy

There is a newer version: 3.2.3
Show newest version
/*
 * Copyright 2017 PingCAP, Inc.
 *
 * Licensed 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,
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.pingcap.tikv.catalog;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.pingcap.tikv.Snapshot;
import com.pingcap.tikv.meta.TiDBInfo;
import com.pingcap.tikv.meta.TiTableInfo;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Catalog implements AutoCloseable {
  private final boolean showRowId;
  private final String dbPrefix;
  private final Logger logger = LoggerFactory.getLogger(this.getClass());
  private final Supplier snapshotProvider;
  private CatalogCache metaCache;
  private static final AtomicLong lastUpdateTime = new AtomicLong(0);

  public Catalog(Supplier snapshotProvider, boolean showRowId, String dbPrefix) {
    this.snapshotProvider = Objects.requireNonNull(snapshotProvider, "Snapshot Provider is null");
    this.showRowId = showRowId;
    this.dbPrefix = dbPrefix;
    metaCache = new CatalogCache(new CatalogTransaction(snapshotProvider.get()), dbPrefix, false);
    reloadCache(true);
  }

  @Override
  public void close() {}

  public void reloadCache(boolean loadTables) {
    synchronized (lastUpdateTime) {
      if (lastUpdateTime.get() < System.currentTimeMillis()) {
        Snapshot snapshot = snapshotProvider.get();
        CatalogTransaction newTrx = new CatalogTransaction(snapshot);
        long latestVersion = newTrx.getLatestSchemaVersion();
        if (latestVersion > metaCache.getVersion()) {
          metaCache = new CatalogCache(newTrx, dbPrefix, loadTables, latestVersion);
        }
        lastUpdateTime.set(System.currentTimeMillis());
      }
    }
  }

  private void reloadCache() {
    reloadCache(false);
  }

  public List listDatabases() {
    reloadCache();
    return metaCache.listDatabases();
  }

  public List listTables(TiDBInfo database) {
    Objects.requireNonNull(database, "database is null");
    reloadCache(true);
    if (showRowId) {
      return metaCache
          .listTables(database)
          .stream()
          .map(TiTableInfo::copyTableWithRowId)
          .collect(Collectors.toList());
    } else {
      return metaCache.listTables(database);
    }
  }

  public List listDatabasesFromCache() {
    return metaCache.listDatabases();
  }

  public List listTablesFromCache(TiDBInfo database) {
    Objects.requireNonNull(database, "database is null");
    if (showRowId) {
      return metaCache
          .listTables(database)
          .stream()
          .map(TiTableInfo::copyTableWithRowId)
          .collect(Collectors.toList());
    } else {
      return metaCache.listTables(database);
    }
  }

  public TiDBInfo getDatabaseFromCache(String dbName) {
    Objects.requireNonNull(dbName, "dbName is null");
    return metaCache.getDatabase(dbName);
  }

  public TiTableInfo getTableFromCache(String dbName, String tableName) {
    TiDBInfo database = getDatabaseFromCache(dbName);
    if (database == null) {
      return null;
    }
    return getTableFromCache(database, tableName);
  }

  public TiTableInfo getTableFromCache(TiDBInfo database, String tableName) {
    Objects.requireNonNull(database, "database is null");
    Objects.requireNonNull(tableName, "tableName is null");
    TiTableInfo table = metaCache.getTable(database, tableName);
    if (showRowId && table != null) {
      return table.copyTableWithRowId();
    } else {
      return table;
    }
  }

  public TiDBInfo getDatabase(String dbName) {
    Objects.requireNonNull(dbName, "dbName is null");
    reloadCache();
    return metaCache.getDatabase(dbName);
  }

  public TiTableInfo getTable(String dbName, String tableName) {
    TiDBInfo database = getDatabase(dbName);
    if (database == null) {
      return null;
    }
    return getTable(database, tableName);
  }

  public TiTableInfo getTable(TiDBInfo database, String tableName) {
    Objects.requireNonNull(database, "database is null");
    Objects.requireNonNull(tableName, "tableName is null");
    reloadCache(true);
    TiTableInfo table = metaCache.getTable(database, tableName);
    if (showRowId && table != null) {
      return table.copyTableWithRowId();
    } else {
      return table;
    }
  }

  @VisibleForTesting
  public TiTableInfo getTable(TiDBInfo database, long tableId) {
    Objects.requireNonNull(database, "database is null");
    Collection tables = listTables(database);
    for (TiTableInfo table : tables) {
      if (table.getId() == tableId) {
        if (showRowId) {
          return table.copyTableWithRowId();
        } else {
          return table;
        }
      }
    }
    return null;
  }

  private static class CatalogCache {

    private final Map dbCache;
    private final ConcurrentHashMap> tableCache;
    private final String dbPrefix;
    private final CatalogTransaction transaction;
    private final long currentVersion;

    private CatalogCache(
        CatalogTransaction transaction, String dbPrefix, boolean loadTables, long currentVersion) {
      this.transaction = transaction;
      this.dbPrefix = dbPrefix;
      this.tableCache = new ConcurrentHashMap<>();
      this.dbCache = loadDatabases(loadTables);
      this.currentVersion = currentVersion;
    }

    private CatalogCache(CatalogTransaction transaction, String dbPrefix, boolean loadTables) {
      this.transaction = transaction;
      this.dbPrefix = dbPrefix;
      this.tableCache = new ConcurrentHashMap<>();
      this.dbCache = loadDatabases(loadTables);
      this.currentVersion = transaction.getLatestSchemaVersion();
    }

    public CatalogTransaction getTransaction() {
      return transaction;
    }

    public long getVersion() {
      return currentVersion;
    }

    public TiDBInfo getDatabase(String name) {
      Objects.requireNonNull(name, "name is null");
      return dbCache.get(name.toLowerCase());
    }

    public List listDatabases() {
      return ImmutableList.copyOf(dbCache.values());
    }

    public List listTables(TiDBInfo db) {
      Map tableMap = tableCache.get(db);
      if (tableMap == null) {
        tableMap = loadTables(db);
      }
      Collection tables = tableMap.values();
      return tables
          .stream()
          .filter(tbl -> !tbl.isView() || !tbl.isSequence())
          .collect(Collectors.toList());
    }

    public TiTableInfo getTable(TiDBInfo db, String tableName) {
      Map tableMap = tableCache.get(db);
      if (tableMap == null) {
        tableMap = loadTables(db);
      }
      TiTableInfo tbl = tableMap.get(tableName.toLowerCase());
      // https://github.com/pingcap/tispark/issues/961
      // TODO: support reading from view table in the future.
      if (tbl != null && (tbl.isView() || tbl.isSequence())) return null;
      return tbl;
    }

    private Map loadTables(TiDBInfo db) {
      List tables = transaction.getTables(db.getId());
      ImmutableMap.Builder builder = ImmutableMap.builder();
      for (TiTableInfo table : tables) {
        builder.put(table.getName().toLowerCase(), table);
      }
      Map tableMap = builder.build();
      tableCache.put(db, tableMap);
      return tableMap;
    }

    private Map loadDatabases(boolean loadTables) {
      HashMap newDBCache = new HashMap<>();

      List databases = transaction.getDatabases();
      databases.forEach(
          db -> {
            TiDBInfo newDBInfo = db.rename(dbPrefix + db.getName());
            newDBCache.put(newDBInfo.getName().toLowerCase(), newDBInfo);
            if (loadTables) {
              loadTables(newDBInfo);
            }
          });
      return newDBCache;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy