/* * 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.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.ThreadFactoryBuilder; 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.*; import java.util.function.Supplier; public class Catalog implements AutoCloseable { private Supplier<Snapshot> snapshotProvider; private ScheduledExecutorService service; private CatalogCache metaCache; @Override public void close() throws Exception { if(service != null) { service.shutdown(); } } private static class CatalogCache { private CatalogCache(CatalogTransaction transaction) { this.transaction = transaction; this.dbCache = loadDatabases(); this.tableCache = new ConcurrentHashMap<>(); this.currentVersion = transaction.getLatestSchemaVersion(); } private final Map<String, TiDBInfo> dbCache; private final ConcurrentHashMap<TiDBInfo, Map<String, TiTableInfo>> tableCache; private CatalogTransaction transaction; private long currentVersion; 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<TiDBInfo> listDatabases() { return ImmutableList.copyOf(dbCache.values()); } public List<TiTableInfo> listTables(TiDBInfo db) { Map<String, TiTableInfo> tableMap = tableCache.get(db); if (tableMap == null) { tableMap = loadTables(db); } return ImmutableList.copyOf(tableMap.values()); } public TiTableInfo getTable(TiDBInfo db, String tableName) { Map<String, TiTableInfo> tableMap = tableCache.get(db); if (tableMap == null) { tableMap = loadTables(db); } return tableMap.get(tableName.toLowerCase()); } private Map<String, TiTableInfo> loadTables(TiDBInfo db) { List<TiTableInfo> tables = transaction.getTables(db.getId()); ImmutableMap.Builder<String, TiTableInfo> builder = ImmutableMap.builder(); for (TiTableInfo table : tables) { builder.put(table.getName(), table); } Map<String, TiTableInfo> tableMap = builder.build(); tableCache.put(db, tableMap); return tableMap; } private Map<String, TiDBInfo> loadDatabases() { HashMap<String, TiDBInfo> newDBCache = new HashMap<>(); List<TiDBInfo> databases = transaction.getDatabases(); databases.forEach(db -> newDBCache.put(db.getName(), db)); return newDBCache; } } public Catalog(Supplier<Snapshot> snapshotProvider, int refreshPeriod, TimeUnit periodUnit) { this.snapshotProvider = Objects.requireNonNull(snapshotProvider, "Snapshot Provider is null"); metaCache = new CatalogCache(new CatalogTransaction(snapshotProvider.get())); service = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setDaemon(true).build()); service.scheduleAtFixedRate(this::reloadCache, refreshPeriod, refreshPeriod, periodUnit); } public Catalog(Supplier<Snapshot> snapshotProvider) { this.snapshotProvider = Objects.requireNonNull(snapshotProvider, "Snapshot Provider is null"); metaCache = new CatalogCache(new CatalogTransaction(snapshotProvider.get())); } private void reloadCache() { Snapshot snapshot = snapshotProvider.get(); CatalogTransaction newTrx = new CatalogTransaction(snapshot); long latestVersion = newTrx.getLatestSchemaVersion(); if (latestVersion > metaCache.getVersion()) { metaCache = new CatalogCache(newTrx); } } public List<TiDBInfo> listDatabases() { return metaCache.listDatabases(); } public List<TiTableInfo> listTables(TiDBInfo database) { Objects.requireNonNull(database, "database is null"); return metaCache.listTables(database); } public TiDBInfo getDatabase(String dbName) { Objects.requireNonNull(dbName, "dbName is null"); 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"); return metaCache.getTable(database, tableName); } public TiTableInfo getTable(TiDBInfo database, long tableId) { Objects.requireNonNull(database, "database is null"); Collection<TiTableInfo> tables = listTables(database); for (TiTableInfo table : tables) { if (table.getId() == tableId) { return table; } } return null; } }