Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.drill.exec.store.mapr.db; import com.mapr.db.Table; import com.mapr.db.impl.MapRDBImpl; import com.mapr.db.index.IndexDesc; import org.apache.drill.common.config.DrillConfig; import org.apache.drill.common.exceptions.DrillRuntimeException; import org.apache.drill.exec.util.ImpersonationUtil; import org.apache.hadoop.fs.Path; import org.apache.hadoop.security.UserGroupInformation; import java.io.IOException; import java.security.PrivilegedExceptionAction; import java.util.concurrent.TimeUnit; import org.apache.drill.shaded.guava.com.google.common.cache.CacheBuilder; import org.apache.drill.shaded.guava.com.google.common.cache.CacheLoader; import org.apache.drill.shaded.guava.com.google.common.cache.LoadingCache; import org.apache.drill.shaded.guava.com.google.common.cache.RemovalListener; import org.apache.drill.shaded.guava.com.google.common.cache.RemovalNotification; public class MapRDBTableCache { static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MapRDBFormatPlugin.class); public static final String FORMAT_MAPRDB_JSON_TABLE_CACHE_ENABLED = "format-maprdb.json.tableCache.enabled"; public static final String FORMAT_MAPRDB_JSON_TABLE_CACHE_SIZE = "format-maprdb.json.tableCache.size"; public static final String FORMAT_MAPRDB_JSON_TABLE_CACHE_TIMEOUT = "format-maprdb.json.tableCache.expireTimeInMinutes"; private static final int MIN_TABLE_CACHE_SIZE = 1; private static final int MIN_TABLE_CACHE_ENTRY_TIMEOUT = 10; LoadingCache<MapRDBTableCache.Key, Table> tableCache; private final boolean tableCachingEnabled; public MapRDBTableCache(DrillConfig config) { tableCachingEnabled = config.getBoolean(FORMAT_MAPRDB_JSON_TABLE_CACHE_ENABLED); if (tableCachingEnabled) { final int tableCacheSize = Math.max((int) (config.getDouble(FORMAT_MAPRDB_JSON_TABLE_CACHE_SIZE)), MIN_TABLE_CACHE_SIZE); final int tableCacheExpiryTime = Math.max( (int) (config.getDouble(FORMAT_MAPRDB_JSON_TABLE_CACHE_TIMEOUT)), MIN_TABLE_CACHE_ENTRY_TIMEOUT); RemovalListener<MapRDBTableCache.Key, Table> removalListener = new RemovalListener<MapRDBTableCache.Key, Table>() { public void onRemoval(RemovalNotification<MapRDBTableCache.Key, Table> removal) { Table table = removal.getValue(); MapRDBTableCache.Key key = removal.getKey(); logger.debug("time {} closing the tablePath {} tableHandle {} index {} userName {}", System.nanoTime(), key.path == null ? "null" : key.path, table == null ? "null" : table, key.indexDesc == null ? "null" : key.indexDesc.getIndexName(), key.ugi.getUserName() == null ? "null" : key.ugi.getUserName()); table.close(); // close the table } }; // Common table cache for primary and index tables. Key is Pair<tablePath, indexDesc> // For primary table, indexDesc is null. tableCache = CacheBuilder.newBuilder().expireAfterAccess(tableCacheExpiryTime, TimeUnit.MINUTES) .maximumSize(tableCacheSize).removalListener(removalListener) .build(new CacheLoader<MapRDBTableCache.Key, Table>() { @Override public Table load(final MapRDBTableCache.Key key) throws Exception { // getTable is already calling tableCache.get in correct user UGI context, so should be fine here. // key.Left is Path. key.Right is indexDesc. Table table = (key.indexDesc == null ? MapRDBImpl.getTable(key.path) : MapRDBImpl.getIndexTable(key.indexDesc)); logger.debug( "time {} opened the table for tablePath {} tableHandle {} index {} userName {}", System.nanoTime(), key.path == null ? "null" : key.path, table == null ? "null" : table, key.indexDesc == null ? "null" : key.indexDesc.getIndexName(), key.ugi.getUserName() == null ? "null" : key.ugi.getUserName()); return table; } }); logger.debug("table cache created with size {} and expiryTimeInMin {} ", tableCacheSize, tableCacheExpiryTime); } } /** * getTable given primary table path and indexDesc. * returns Table for corresponding index table if indexDesc is not null. * returns Table for primary table if indexDesc is null. * * @param tablePath primary table path * @param indexDesc index table descriptor */ public Table getTable(final Path tablePath, final IndexDesc indexDesc, final String userName) throws DrillRuntimeException { final Table dbTableHandle; final UserGroupInformation proxyUserUgi = ImpersonationUtil.createProxyUgi(userName); try { dbTableHandle = proxyUserUgi.doAs(new PrivilegedExceptionAction<Table>() { public Table run() throws Exception { if (logger.isTraceEnabled()) { logger.trace("Getting MaprDB Table handle for proxy user: " + UserGroupInformation.getCurrentUser()); } if (tableCachingEnabled) { Table table = tableCache.get(new MapRDBTableCache.Key(tablePath, indexDesc)); logger.trace( "time {} get the tablePath {} tableHandle {} index {} userName {} currentUser {}", System.nanoTime(), tablePath == null ? "null" : tablePath, table == null ? "null" : table, indexDesc == null ? "null" : indexDesc.getIndexName(), userName == null ? "null" : userName, UserGroupInformation.getCurrentUser() == null ? "null" : UserGroupInformation.getCurrentUser()); return table; } else { return indexDesc == null ? MapRDBImpl.getTable(tablePath) : MapRDBImpl.getIndexTable(indexDesc); } } }); } catch (Exception e) { throw new DrillRuntimeException("Error getting table: " + tablePath.toString() + (indexDesc == null ? "" : (", " + "IndexDesc: " + indexDesc.toString())), e); } return dbTableHandle; } /** * getTable given primary table name. * returns Table for primary table with given name. * * @param tableName primary table path */ public Table getTable(String tableName, String userName) { return getTable(new Path(tableName), null, userName); } /** * getTable given primary table path. * returns Table for primary table with given path. * * @param tablePath primary table path */ public Table getTable(Path tablePath, String userName) { return getTable(tablePath, null, userName); } /** * getTable given primary table name and indexDesc. * returns Table for corresponding index table if indexDesc is not null. * returns Table for primary table if indexDesc is null. * * @param tableName primary table name * @param indexDesc index table Descriptor */ public Table getTable(String tableName, IndexDesc indexDesc, String userName) { return getTable(new Path(tableName), indexDesc, userName); } /** * closeTable * * @param table table to be closed. */ public void closeTable(Table table) { if (!tableCachingEnabled && table != null) { table.close(); } } /** * Key for {@link MapRDBTableCache} to store table path, {@link IndexDesc} and UGI. */ static class Key { final Path path; final IndexDesc indexDesc; final UserGroupInformation ugi; Key(Path path, IndexDesc indexDesc) throws IOException { this.path = path; this.indexDesc = indexDesc; this.ugi = UserGroupInformation.getCurrentUser(); } public int hashCode() { final int IdxDescHashCode = (indexDesc == null) ? 0 : indexDesc.getIndexFid().hashCode(); return (path.hashCode() + IdxDescHashCode + ugi.hashCode()); } static boolean isEqual(Object a, Object b) { return a == b || a != null && a.equals(b); } public boolean equals(Object obj) { if (obj == this) { return true; } else if (obj != null && obj instanceof MapRDBTableCache.Key) { MapRDBTableCache.Key that = (MapRDBTableCache.Key) obj; return isEqual(this.path, that.path) && isEqual(this.indexDesc, that.indexDesc) && isEqual(this.ugi, that.ugi); } else { return false; } } public String toString() { return "(Path: " + this.path.toString() + ", UGI: " + this.ugi.toString() + ", IndexDesc: " + (this.indexDesc == null ? "" : this.indexDesc.toString()) + ")"; } } }