You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by sp...@apache.org on 2018/05/31 03:32:57 UTC

[79/86] sentry git commit: SENTRY-2208: Refactor out Sentry service into own module from sentry-provider-db (Anthony Young-Garner, reviewed by Sergio Pena, Steve Moist, Na Li)

http://git-wip-us.apache.org/repos/asf/sentry/blob/7db84b2f/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
deleted file mode 100644
index 1c4bb37..0000000
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
+++ /dev/null
@@ -1,4797 +0,0 @@
-/**
- * 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.sentry.provider.db.service.persistent;
-
-import static org.apache.sentry.core.common.utils.SentryConstants.AUTHORIZABLE_JOINER;
-import static org.apache.sentry.core.common.utils.SentryConstants.KV_JOINER;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import javax.jdo.FetchGroup;
-import javax.jdo.JDODataStoreException;
-import javax.jdo.JDOHelper;
-import javax.jdo.PersistenceManager;
-import javax.jdo.PersistenceManagerFactory;
-import javax.jdo.Query;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.sentry.core.common.exception.SentryAccessDeniedException;
-import org.apache.sentry.core.common.exception.SentryAlreadyExistsException;
-import org.apache.sentry.core.common.exception.SentryGrantDeniedException;
-import org.apache.sentry.core.common.exception.SentryInvalidInputException;
-import org.apache.sentry.core.common.exception.SentryNoSuchObjectException;
-import org.apache.sentry.core.common.exception.SentrySiteConfigurationException;
-import org.apache.sentry.core.common.exception.SentryUserException;
-import org.apache.sentry.core.common.utils.PathUtils;
-import org.apache.sentry.core.common.utils.SentryConstants;
-import org.apache.sentry.core.model.db.AccessConstants;
-import org.apache.sentry.core.model.db.DBModelAuthorizable.AuthorizableType;
-import org.apache.sentry.hdfs.PathsUpdate;
-import org.apache.sentry.hdfs.UniquePathsUpdate;
-import org.apache.sentry.hdfs.UpdateableAuthzPaths;
-import org.apache.sentry.hdfs.service.thrift.TPrivilegeEntityType;
-import org.apache.sentry.provider.db.service.model.MAuthzPathsMapping;
-import org.apache.sentry.provider.db.service.model.MAuthzPathsSnapshotId;
-import org.apache.sentry.provider.db.service.model.MSentryChange;
-import org.apache.sentry.provider.db.service.model.MSentryGroup;
-import org.apache.sentry.provider.db.service.model.MSentryHmsNotification;
-import org.apache.sentry.provider.db.service.model.MSentryPathChange;
-import org.apache.sentry.provider.db.service.model.MSentryPermChange;
-import org.apache.sentry.provider.db.service.model.MSentryPrivilege;
-import org.apache.sentry.provider.db.service.model.MSentryGMPrivilege;
-import org.apache.sentry.provider.db.service.model.MSentryRole;
-import org.apache.sentry.provider.db.service.model.MSentryUser;
-import org.apache.sentry.provider.db.service.model.MSentryVersion;
-import org.apache.sentry.provider.db.service.model.MSentryUtil;
-import org.apache.sentry.provider.db.service.model.MPath;
-import org.apache.sentry.hdfs.service.thrift.TPrivilegeEntity;
-import org.apache.sentry.api.common.ApiConstants.PrivilegeScope;
-import org.apache.sentry.api.service.thrift.SentryPolicyStoreProcessor;
-import org.apache.sentry.api.service.thrift.TSentryActiveRoleSet;
-import org.apache.sentry.api.service.thrift.TSentryAuthorizable;
-import org.apache.sentry.api.service.thrift.TSentryGrantOption;
-import org.apache.sentry.api.service.thrift.TSentryGroup;
-import org.apache.sentry.api.service.thrift.TSentryMappingData;
-import org.apache.sentry.api.service.thrift.TSentryPrivilege;
-import org.apache.sentry.api.service.thrift.TSentryPrivilegeMap;
-import org.apache.sentry.api.service.thrift.TSentryRole;
-import org.apache.sentry.service.common.ServiceConstants.SentryEntityType;
-import org.apache.sentry.service.common.ServiceConstants.ServerConfig;
-import org.datanucleus.store.rdbms.exceptions.MissingTableException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.codahale.metrics.Gauge;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import static org.apache.sentry.hdfs.Updateable.Update;
-import static org.apache.sentry.provider.db.service.persistent.QueryParamBuilder.newQueryParamBuilder;
-
-/**
- * SentryStore is the data access object for Sentry data. Strings
- * such as role and group names will be normalized to lowercase
- * in addition to starting and ending whitespace.
- * <p>
- * We have several places where we rely on transactions to support
- * read/modify/write semantics for incrementing IDs.
- * This works but using DB support is rather expensive and we can
- * user in-core serializations to help with this a least within a
- * single node and rely on DB for multi-node synchronization.
- * <p>
- * This isn't much of a problem for path updates since they are
- * driven by HMSFollower which usually runs on a single leader
- * node, but permission updates originate from clients
- * directly and may be highly concurrent.
- * <p>
- * We are internally serializing all permissions update anyway, so doing
- * partial serialization on every node helps. For this reason all
- * SentryStore calls that affect permission deltas are serialized.
- * <p>
- * See <a href="https://issues.apache.org/jira/browse/SENTRY-1824">SENTRY-1824</a>
- * for more detail.
- */
-public class SentryStore {
-  private static final Logger LOGGER = LoggerFactory
-      .getLogger(SentryStore.class);
-
-  public static final String NULL_COL = "__NULL__";
-  public static final int INDEX_GROUP_ROLES_MAP = 0;
-  public static final int INDEX_USER_ROLES_MAP = 1;
-
-  // String constants for field names
-  public static final String SERVER_NAME = "serverName";
-  public static final String DB_NAME = "dbName";
-  public static final String TABLE_NAME = "tableName";
-  public static final String COLUMN_NAME = "columnName";
-  public static final String ACTION = "action";
-  public static final String URI = "URI";
-  public static final String GRANT_OPTION = "grantOption";
-  public static final String ROLE_NAME = "roleName";
-
-  // Initial change ID for permission/path change. Auto increment
-  // is starting from 1.
-  public static final long INIT_CHANGE_ID = 1L;
-
-  private static final long EMPTY_CHANGE_ID = 0L;
-
-  public static final long EMPTY_NOTIFICATION_ID = 0L;
-
-  // Representation for empty HMS snapshots not found on MAuthzPathsSnapshotId
-  public static final long EMPTY_PATHS_SNAPSHOT_ID = 0L;
-
-  // For counters, representation of the "unknown value"
-  private static final long COUNT_VALUE_UNKNOWN = -1L;
-
-  // Representation for unknown HMS notification ID
-  private static final long NOTIFICATION_UNKNOWN = -1L;
-
-  private static final String EMPTY_GRANTOR_PRINCIPAL = "--";
-
-
-  private static final Set<String> ALL_ACTIONS = Sets.newHashSet(
-      AccessConstants.ALL, AccessConstants.ACTION_ALL,
-      AccessConstants.SELECT, AccessConstants.INSERT, AccessConstants.ALTER,
-      AccessConstants.CREATE, AccessConstants.DROP, AccessConstants.INDEX,
-      AccessConstants.LOCK);
-
-  // Now partial revoke just support action with SELECT,INSERT and ALL.
-  // Now partial revoke just support action with SELECT,INSERT, and ALL.
-  // e.g. If we REVOKE SELECT from a privilege with action ALL, it will leads to INSERT
-  // e.g. If we REVOKE SELECT from a privilege with action ALL, it will leads to others individual
-  // Otherwise, if we revoke other privilege(e.g. ALTER,DROP...), we will remove it from a role directly.
-  private static final Set<String> PARTIAL_REVOKE_ACTIONS = Sets.newHashSet(AccessConstants.ALL,
-      AccessConstants.ACTION_ALL.toLowerCase(), AccessConstants.SELECT, AccessConstants.INSERT);
-
-  // Datanucleus property controlling whether query results are loaded at commit time
-  // to make query usable post-commit
-  private static final String LOAD_RESULTS_AT_COMMIT = "datanucleus.query.loadResultsAtCommit";
-
-  private final PersistenceManagerFactory pmf;
-  private Configuration conf;
-  private final TransactionManager tm;
-
-  // When it is true, execute DeltaTransactionBlock to persist delta changes.
-  // When it is false, do not execute DeltaTransactionBlock
-  private boolean persistUpdateDeltas;
-
-  /**
-   * counterWait is used to synchronize notifications between Thrift and HMSFollower.
-   * Technically it doesn't belong here, but the only thing that connects HMSFollower
-   * and Thrift API is SentryStore. An alternative could be a singleton CounterWait or
-   * some factory that returns CounterWait instances keyed by name, but this complicates
-   * things unnecessary.
-   * <p>
-   * Keeping it here isn't ideal but serves the purpose until we find a better home.
-   */
-  private final CounterWait counterWait;
-
-  public static Properties getDataNucleusProperties(Configuration conf)
-          throws SentrySiteConfigurationException, IOException {
-    Properties prop = new Properties();
-    prop.putAll(ServerConfig.SENTRY_STORE_DEFAULTS);
-    String jdbcUrl = conf.get(ServerConfig.SENTRY_STORE_JDBC_URL, "").trim();
-    Preconditions.checkArgument(!jdbcUrl.isEmpty(), "Required parameter " +
-        ServerConfig.SENTRY_STORE_JDBC_URL + " is missed");
-    String user = conf.get(ServerConfig.SENTRY_STORE_JDBC_USER, ServerConfig.
-        SENTRY_STORE_JDBC_USER_DEFAULT).trim();
-    //Password will be read from Credential provider specified using property
-    // CREDENTIAL_PROVIDER_PATH("hadoop.security.credential.provider.path" in sentry-site.xml
-    // it falls back to reading directly from sentry-site.xml
-    char[] passTmp = conf.getPassword(ServerConfig.SENTRY_STORE_JDBC_PASS);
-    if (passTmp == null) {
-      throw new SentrySiteConfigurationException("Error reading " +
-              ServerConfig.SENTRY_STORE_JDBC_PASS);
-    }
-    String pass = new String(passTmp);
-
-    String driverName = conf.get(ServerConfig.SENTRY_STORE_JDBC_DRIVER,
-        ServerConfig.SENTRY_STORE_JDBC_DRIVER_DEFAULT);
-    prop.setProperty(ServerConfig.JAVAX_JDO_URL, jdbcUrl);
-    prop.setProperty(ServerConfig.JAVAX_JDO_USER, user);
-    prop.setProperty(ServerConfig.JAVAX_JDO_PASS, pass);
-    prop.setProperty(ServerConfig.JAVAX_JDO_DRIVER_NAME, driverName);
-
-    /*
-     * Oracle doesn't support "repeatable-read" isolation level and testing
-     * showed issues with "serializable" isolation level for Oracle 12,
-     * so we use "read-committed" instead.
-     *
-     * JDBC URL always looks like jdbc:oracle:<drivertype>:@<database>
-     *  we look at the second component.
-     *
-     * The isolation property can be overwritten via configuration property.
-     */
-    final String oracleDb = "oracle";
-    if (prop.getProperty(ServerConfig.DATANUCLEUS_ISOLATION_LEVEL, "").
-            equals(ServerConfig.DATANUCLEUS_REPEATABLE_READ) &&
-                    jdbcUrl.contains(oracleDb)) {
-      String[] parts = jdbcUrl.split(":");
-      if ((parts.length > 1) && parts[1].equals(oracleDb)) {
-        // For Oracle JDBC driver, replace "repeatable-read" with "read-committed"
-        prop.setProperty(ServerConfig.DATANUCLEUS_ISOLATION_LEVEL,
-                "read-committed");
-      }
-    }
-
-    for (Map.Entry<String, String> entry : conf) {
-      String key = entry.getKey();
-      if (key.startsWith(ServerConfig.SENTRY_JAVAX_JDO_PROPERTY_PREFIX) ||
-          key.startsWith(ServerConfig.SENTRY_DATANUCLEUS_PROPERTY_PREFIX)) {
-        key = StringUtils.removeStart(key, ServerConfig.SENTRY_DB_PROPERTY_PREFIX);
-        prop.setProperty(key, entry.getValue());
-      }
-    }
-    // Disallow operations outside of transactions
-    prop.setProperty("datanucleus.NontransactionalRead", "false");
-    prop.setProperty("datanucleus.NontransactionalWrite", "false");
-    return prop;
-  }
-
-  public SentryStore(Configuration conf) throws Exception {
-    this.conf = conf;
-    Properties prop = getDataNucleusProperties(conf);
-    boolean checkSchemaVersion = conf.get(
-        ServerConfig.SENTRY_VERIFY_SCHEM_VERSION,
-        ServerConfig.SENTRY_VERIFY_SCHEM_VERSION_DEFAULT).equalsIgnoreCase(
-        "true");
-
-    // Schema verification should be set to false only for testing.
-    // If it is set to false, appropriate datanucleus properties will be set so that
-    // database schema is automatically created. This is desirable only for running tests.
-    // Sentry uses <code>SentrySchemaTool</code> to create schema with the help of sql scripts.
-
-    if (!checkSchemaVersion) {
-      prop.setProperty("datanucleus.schema.autoCreateAll", "true");
-    }
-    pmf = JDOHelper.getPersistenceManagerFactory(prop);
-    tm = new TransactionManager(pmf, conf);
-    verifySentryStoreSchema(checkSchemaVersion);
-    long notificationTimeout = conf.getInt(ServerConfig.SENTRY_NOTIFICATION_SYNC_TIMEOUT_MS,
-            ServerConfig.SENTRY_NOTIFICATION_SYNC_TIMEOUT_DEFAULT);
-    counterWait = new CounterWait(notificationTimeout, TimeUnit.MILLISECONDS);
-  }
-
-  public void setPersistUpdateDeltas(boolean persistUpdateDeltas) {
-    this.persistUpdateDeltas = persistUpdateDeltas;
-  }
-
-
-  public TransactionManager getTransactionManager() {
-    return tm;
-  }
-
-  public CounterWait getCounterWait() {
-    return counterWait;
-  }
-
-  // ensure that the backend DB schema is set
-  void verifySentryStoreSchema(boolean checkVersion) throws Exception {
-    if (!checkVersion) {
-      setSentryVersion(SentryStoreSchemaInfo.getSentryVersion(),
-          "Schema version set implicitly");
-    } else {
-      String currentVersion = getSentryVersion();
-      if (!SentryStoreSchemaInfo.getSentryVersion().equals(currentVersion)) {
-        throw new SentryAccessDeniedException(
-            "The Sentry store schema version " + currentVersion
-                + " is different from distribution version "
-                + SentryStoreSchemaInfo.getSentryVersion());
-      }
-    }
-  }
-
-  public synchronized void stop() {
-    if (pmf != null) {
-      pmf.close();
-    }
-  }
-
-  /**
-   * Get a single role with the given name inside a transaction
-   * @param pm Persistence Manager instance
-   * @param roleName Role name (should not be null)
-   * @return single role with the given name
-   */
-  public MSentryRole getRole(PersistenceManager pm, String roleName) {
-    Query query = pm.newQuery(MSentryRole.class);
-    query.addExtension(LOAD_RESULTS_AT_COMMIT, "false");
-    query.setFilter("this.roleName == :roleName");
-    query.setUnique(true);
-    return (MSentryRole) query.execute(roleName);
-  }
-
-  /**
-   * Get list of all roles. Should be called inside transaction.
-   * @param pm Persistence manager instance
-   * @return List of all roles
-   */
-  @SuppressWarnings("unchecked")
-  private List<MSentryRole> getAllRoles(PersistenceManager pm) {
-    Query query = pm.newQuery(MSentryRole.class);
-    query.addExtension(LOAD_RESULTS_AT_COMMIT, "false");
-    return (List<MSentryRole>) query.execute();
-  }
-
-  /**
-   * Get a single user with the given name inside a transaction
-   * @param pm Persistence Manager instance
-   * @param userName User name (should not be null)
-   * @return single user with the given name
-   */
-  public MSentryUser getUser(PersistenceManager pm, String userName) {
-    Query query = pm.newQuery(MSentryUser.class);
-    query.addExtension(LOAD_RESULTS_AT_COMMIT, "false");
-    query.setFilter("this.userName == :userName");
-    query.setUnique(true);
-    return (MSentryUser) query.execute(userName);
-  }
-
-  /**
-   * Create a sentry user and persist it. User name is the primary key for the
-   * user, so an attempt to create a user which exists fails with JDO exception.
-   *
-   * @param userName: Name of the user being persisted.
-   *    The name is normalized.
-   * @throws Exception
-   */
-  public void createSentryUser(final String userName) throws Exception {
-    tm.executeTransactionWithRetry(
-        pm -> {
-          pm.setDetachAllOnCommit(false); // No need to detach objects
-          String trimmedUserName = trimAndLower(userName);
-          if (getUser(pm, trimmedUserName) != null) {
-            throw new SentryAlreadyExistsException("User: " + trimmedUserName);
-          }
-          pm.makePersistent(
-              new MSentryUser(trimmedUserName, System.currentTimeMillis(), Sets.newHashSet()));
-          return null;
-        });
-  }
-
-  /**
-   * Normalize the string values - remove leading and trailing whitespaces and
-   * convert to lower case
-   * @return normalized input
-   */
-  private String trimAndLower(String input) {
-    return input.trim().toLowerCase();
-  }
-
-  /**
-   * Create a sentry role and persist it. Role name is the primary key for the
-   * role, so an attempt to create a role which exists fails with JDO exception.
-   *
-   * @param roleName: Name of the role being persisted.
-   *    The name is normalized.
-   * @throws Exception
-   */
-  public void createSentryRole(final String roleName) throws Exception {
-    tm.executeTransactionWithRetry(
-            pm -> {
-              pm.setDetachAllOnCommit(false); // No need to detach objects
-              String trimmedRoleName = trimAndLower(roleName);
-              if (getRole(pm, trimmedRoleName) != null) {
-                throw new SentryAlreadyExistsException("Role: " + trimmedRoleName);
-              }
-              pm.makePersistent(new MSentryRole(trimmedRoleName));
-              return null;
-              });
-  }
-
-  /**
-   * Get count of object of the given class
-   * @param tClass Class to count
-   * @param <T> Class type
-   * @return count of objects or -1 in case of error
-     */
-  private <T> Long getCount(final Class<T> tClass) {
-    try {
-      return tm.executeTransaction(
-              pm -> {
-                pm.setDetachAllOnCommit(false); // No need to detach objects
-                Query query = pm.newQuery();
-                query.addExtension(LOAD_RESULTS_AT_COMMIT, "false");
-                query.setClass(tClass);
-                query.setResult("count(this)");
-                Long result = (Long)query.execute();
-                return result;
-              });
-    } catch (Exception e) {
-       return COUNT_VALUE_UNKNOWN;
-    }
-  }
-
-  /**
-   * @return number of roles
-   */
-  public Gauge<Long> getRoleCountGauge() {
-    return () -> getCount(MSentryRole.class);
-  }
-
-  /**
-   * @return Number of privileges
-   */
-  public Gauge<Long> getPrivilegeCountGauge() {
-    return () -> getCount(MSentryPrivilege.class);
-  }
-
-  /**
-   * @return number of groups
-   */
-  public Gauge<Long> getGroupCountGauge() {
-    return () -> getCount(MSentryGroup.class);
-  }
-
-  /**
-   * @return Number of users
-   */
-  Gauge<Long> getUserCountGauge() {
-    return () -> getCount(MSentryUser.class);
-  }
-
-  /**
-   * @return number of threads waiting for HMS notifications to be processed
-   */
-  public Gauge<Integer> getHMSWaitersCountGauge() {
-    return () -> counterWait.waitersCount();
-  }
-
-  /**
-   * @return current value of last processed notification ID
-   */
-  public Gauge<Long> getLastNotificationIdGauge() {
-    return () -> {
-      try {
-        return getLastProcessedNotificationID();
-      } catch (Exception e) {
-        LOGGER.error("Can not read current notificationId", e);
-        return NOTIFICATION_UNKNOWN;
-      }
-    };
-  }
-
-  /**
-   * @return ID of the path snapshot
-   */
-  public Gauge<Long> getLastPathsSnapshotIdGauge() {
-    return () -> {
-      try {
-        return getCurrentAuthzPathsSnapshotID();
-      } catch (Exception e) {
-        LOGGER.error("Can not read current paths snapshot ID", e);
-        return NOTIFICATION_UNKNOWN;
-      }
-    };
-  }
-
-  /**
-   * @return Permissions change ID
-   */
-  public Gauge<Long> getPermChangeIdGauge() {
-    return new Gauge<Long>() {
-      @Override
-      public Long getValue() {
-        try {
-          return tm.executeTransaction(
-                  pm -> getLastProcessedChangeIDCore(pm, MSentryPermChange.class)
-          );
-        } catch (Exception e) {
-          LOGGER.error("Can not read current permissions change ID", e);
-          return NOTIFICATION_UNKNOWN;
-        }
-      }
-    };
-  }
-
-  /**
-   * @return Path change id
-   */
-  public Gauge<Long> getPathChangeIdGauge() {
-    return () -> {
-      try {
-        return tm.executeTransaction(
-                pm -> getLastProcessedChangeIDCore(pm, MSentryPathChange.class)
-        );
-      } catch (Exception e) {
-        LOGGER.error("Can not read current path change ID", e);
-        return NOTIFICATION_UNKNOWN;
-      }
-    };
-  }
-
-  /**
-   * Lets the test code know how many privs are in the db, so that we know
-   * if they are in fact being cleaned up when not being referenced any more.
-   * @return The number of rows in the db priv table.
-   */
-  @VisibleForTesting
-  long countMSentryPrivileges() {
-    return getCount(MSentryPrivilege.class);
-  }
-
-  @VisibleForTesting
-  void clearAllTables() {
-    try {
-      tm.executeTransaction(
-              pm -> {
-                pm.newQuery(MSentryRole.class).deletePersistentAll();
-                pm.newQuery(MSentryGroup.class).deletePersistentAll();
-                pm.newQuery(MSentryUser.class).deletePersistentAll();
-                pm.newQuery(MSentryPrivilege.class).deletePersistentAll();
-                pm.newQuery(MSentryPermChange.class).deletePersistentAll();
-                pm.newQuery(MSentryPathChange.class).deletePersistentAll();
-                pm.newQuery(MAuthzPathsMapping.class).deletePersistentAll();
-                pm.newQuery(MPath.class).deletePersistentAll();
-                pm.newQuery(MSentryHmsNotification.class).deletePersistentAll();
-                pm.newQuery(MAuthzPathsSnapshotId.class).deletePersistentAll();
-                return null;
-              });
-    } catch (Exception e) {
-      // the method only for test, log the error and ignore the exception
-      LOGGER.error(e.getMessage(), e);
-    }
-  }
-
-  /**
-   * Removes all the information related to HMS Objects from sentry store.
-   */
-  @VisibleForTesting
-  public void clearHmsPathInformation() throws Exception {
-    tm.executeTransactionWithRetry(
-            pm -> {
-              // Data in MAuthzPathsSnapshotId.class is not cleared intentionally.
-              // This data will help sentry retain the history of snapshots taken before
-              // and help in picking appropriate ID even when hdfs sync is enabled/disabled.
-              pm.newQuery(MSentryPathChange.class).deletePersistentAll();
-              pm.newQuery(MAuthzPathsMapping.class).deletePersistentAll();
-              pm.newQuery(MPath.class).deletePersistentAll();
-              return null;
-            });
-  }
-
-  /**
-   * Purge a given delta change table, with a specified number of changes to be kept.
-   *
-   * @param cls the class of a perm/path delta change {@link MSentryPermChange} or
-   *            {@link MSentryPathChange}.
-   * @param pm a {@link PersistenceManager} instance.
-   * @param changesToKeep the number of changes the caller want to keep.
-   * @param <T> the type of delta change class.
-   */
-  @VisibleForTesting
-  <T extends MSentryChange> void purgeDeltaChangeTableCore(
-      Class<T> cls, PersistenceManager pm, long changesToKeep) {
-    Preconditions.checkArgument(changesToKeep >= 0,
-        "changes to keep must be a non-negative number");
-    long lastChangedID = getLastProcessedChangeIDCore(pm, cls);
-    long maxIDDeleted = lastChangedID - changesToKeep;
-
-    Query query = pm.newQuery(cls);
-    query.addExtension(LOAD_RESULTS_AT_COMMIT, "false");
-
-    // It is an approximation of "SELECT ... LIMIT CHANGE_TO_KEEP" in SQL, because JDO w/ derby
-    // does not support "LIMIT".
-    // See: http://www.datanucleus.org/products/datanucleus/jdo/jdoql_declarative.html
-    query.setFilter("changeID <= maxChangedIdDeleted");
-    query.declareParameters("long maxChangedIdDeleted");
-    long numDeleted = query.deletePersistentAll(maxIDDeleted);
-    if (numDeleted > 0) {
-      LOGGER.info(String.format("Purged %d of %s to changeID=%d",
-              numDeleted, cls.getSimpleName(), maxIDDeleted));
-    }
-  }
-
-  /**
-   * Purge notification id table, keeping a specified number of entries.
-   * @param pm a {@link PersistenceManager} instance.
-   * @param changesToKeep  the number of changes the caller want to keep.
-   */
-  @VisibleForTesting
-  protected void purgeNotificationIdTableCore(PersistenceManager pm,
-      long changesToKeep) {
-    Preconditions.checkArgument(changesToKeep > 0,
-      "You need to keep at least one entry in SENTRY_HMS_NOTIFICATION_ID table");
-    long lastNotificationID = getLastProcessedNotificationIDCore(pm);
-    Query query = pm.newQuery(MSentryHmsNotification.class);
-    query.addExtension(LOAD_RESULTS_AT_COMMIT, "false");
-
-    // It is an approximation of "SELECT ... LIMIT CHANGE_TO_KEEP" in SQL, because JDO w/ derby
-    // does not support "LIMIT".
-    // See: http://www.datanucleus.org/products/datanucleus/jdo/jdoql_declarative.html
-    query.setFilter("notificationId <= maxNotificationIdDeleted");
-    query.declareParameters("long maxNotificationIdDeleted");
-    long numDeleted = query.deletePersistentAll(lastNotificationID - changesToKeep);
-    if (numDeleted > 0) {
-      LOGGER.info("Purged {} of {}", numDeleted, MSentryHmsNotification.class.getSimpleName());
-    }
-  }
-
-  /**
-   * Purge delta change tables, {@link MSentryPermChange} and {@link MSentryPathChange}.
-   * The number of deltas to keep is configurable
-   */
-  public void purgeDeltaChangeTables() {
-    final int changesToKeep = conf.getInt(ServerConfig.SENTRY_DELTA_KEEP_COUNT,
-            ServerConfig.SENTRY_DELTA_KEEP_COUNT_DEFAULT);
-    LOGGER.info("Purging MSentryPathUpdate and MSentyPermUpdate tables, leaving {} entries",
-            changesToKeep);
-    try {
-      tm.executeTransaction(pm -> {
-        pm.setDetachAllOnCommit(false); // No need to detach objects
-        purgeDeltaChangeTableCore(MSentryPermChange.class, pm, changesToKeep);
-        LOGGER.info("MSentryPermChange table has been purged.");
-        purgeDeltaChangeTableCore(MSentryPathChange.class, pm, changesToKeep);
-        LOGGER.info("MSentryPathUpdate table has been purged.");
-        return null;
-      });
-    } catch (Exception e) {
-      LOGGER.error("Delta change cleaning process encountered an error", e);
-    }
-  }
-
-  /**
-   * Purge hms notification id table , {@link MSentryHmsNotification}.
-   * The number of notifications id's to be kept is based on configuration
-   * sentry.server.delta.keep.count
-   */
-  public void purgeNotificationIdTable() {
-    final int changesToKeep = conf.getInt(ServerConfig.SENTRY_HMS_NOTIFICATION_ID_KEEP_COUNT,
-      ServerConfig.SENTRY_HMS_NOTIFICATION_ID_KEEP_COUNT_DEFAULT);
-    LOGGER.debug("Purging MSentryHmsNotification table, leaving {} entries",
-      changesToKeep);
-    try {
-      tm.executeTransaction(pm -> {
-        pm.setDetachAllOnCommit(false); // No need to detach objects
-        purgeNotificationIdTableCore(pm, changesToKeep);
-        return null;
-      });
-    } catch (Exception e) {
-      LOGGER.error("MSentryHmsNotification cleaning process encountered an error", e);
-    }
-  }
-  /**
-   * Alter a given sentry role to grant a privilege.
-   *
-   * @param grantorPrincipal User name
-   * @param roleName the given role name
-   * @param privilege the given privilege
-   * @throws Exception
-   */
-  void alterSentryRoleGrantPrivilege(final String grantorPrincipal,
-      final String roleName, final TSentryPrivilege privilege) throws Exception {
-    tm.executeTransactionWithRetry(
-            pm -> {
-              pm.setDetachAllOnCommit(false); // No need to detach objects
-              String trimmedRoleName = trimAndLower(roleName);
-              // first do grant check
-              grantOptionCheck(pm, grantorPrincipal, privilege);
-
-              // Alter sentry Role and grant Privilege.
-              MSentryPrivilege mPrivilege = alterSentryRoleGrantPrivilegeCore(
-                pm, trimmedRoleName, privilege);
-
-              if (mPrivilege != null) {
-                // update the privilege to be the one actually updated.
-                convertToTSentryPrivilege(mPrivilege, privilege);
-              }
-              return null;
-            });
-  }
-
-  /**
-   * Alter a given sentry role to grant a set of privileges.
-   * Internally calls alterSentryRoleGrantPrivilege.
-   *
-   * @param grantorPrincipal User name
-   * @param roleName Role name
-   * @param privileges Set of privileges
-   * @throws Exception
-   */
-  public void alterSentryRoleGrantPrivileges(final String grantorPrincipal,
-      final String roleName, final Set<TSentryPrivilege> privileges) throws Exception {
-    for (TSentryPrivilege privilege : privileges) {
-      alterSentryRoleGrantPrivilege(grantorPrincipal, roleName, privilege);
-    }
-  }
-
-  /**
-   * Alter a given sentry role to grant a privilege, as well as persist the corresponding
-   * permission change to MSentryPermChange table in a single transaction.
-   *
-   * @param grantorPrincipal User name
-   * @param roleName the given role name
-   * @param privilege the given privilege
-   * @param update the corresponding permission delta update.
-   * @throws Exception
-   *
-   */
-  synchronized void alterSentryRoleGrantPrivilege(final String grantorPrincipal,
-      final String roleName, final TSentryPrivilege privilege,
-      final Update update) throws Exception {
-
-    execute(update, pm -> {
-      pm.setDetachAllOnCommit(false); // No need to detach objects
-      String trimmedRoleName = trimAndLower(roleName);
-      // first do grant check
-      grantOptionCheck(pm, grantorPrincipal, privilege);
-
-      // Alter sentry Role and grant Privilege.
-      MSentryPrivilege mPrivilege = alterSentryRoleGrantPrivilegeCore(pm,
-        trimmedRoleName, privilege);
-
-      if (mPrivilege != null) {
-        // update the privilege to be the one actually updated.
-        convertToTSentryPrivilege(mPrivilege, privilege);
-      }
-      return null;
-    });
-  }
-
-  /**
-   * Alter a given sentry role to grant a set of privileges, as well as persist the
-   * corresponding permission change to MSentryPermChange table in a single transaction.
-   * Internally calls alterSentryRoleGrantPrivilege.
-   *
-   * @param grantorPrincipal User name
-   * @param roleName the given role name
-   * @param privileges a Set of privileges
-   * @param privilegesUpdateMap the corresponding <privilege, DeltaTransactionBlock> map
-   * @throws Exception
-   *
-   */
-  public void alterSentryRoleGrantPrivileges(final String grantorPrincipal,
-      final String roleName, final Set<TSentryPrivilege> privileges,
-      final Map<TSentryPrivilege, Update> privilegesUpdateMap) throws Exception {
-
-    Preconditions.checkNotNull(privilegesUpdateMap);
-    for (TSentryPrivilege privilege : privileges) {
-      Update update = privilegesUpdateMap.get(privilege);
-      if (update != null) {
-        alterSentryRoleGrantPrivilege(grantorPrincipal, roleName, privilege,
-          update);
-      } else {
-        alterSentryRoleGrantPrivilege(grantorPrincipal, roleName, privilege);
-      }
-    }
-  }
-
-  private MSentryPrivilege alterSentryRoleGrantPrivilegeCore(PersistenceManager pm,
-      String roleName, TSentryPrivilege privilege)
-      throws SentryNoSuchObjectException, SentryInvalidInputException {
-    MSentryPrivilege mPrivilege = null;
-    MSentryRole mRole = getRole(pm, roleName);
-    if (mRole == null) {
-      throw noSuchRole(roleName);
-    }
-
-    if(privilege.getPrivilegeScope().equalsIgnoreCase(PrivilegeScope.URI.name())
-        && StringUtils.isBlank(privilege.getURI())) {
-      throw new SentryInvalidInputException("cannot grant URI privileges to Null or EMPTY location");
-    }
-
-    if (!isNULL(privilege.getColumnName()) || !isNULL(privilege.getTableName())
-        || !isNULL(privilege.getDbName())) {
-      // If Grant is for ALL and Either INSERT/SELECT already exists..
-      // need to remove it and GRANT ALL..
-      if (AccessConstants.ALL.equalsIgnoreCase(privilege.getAction())
-          || AccessConstants.ACTION_ALL.equalsIgnoreCase(privilege.getAction())) {
-        TSentryPrivilege tNotAll = new TSentryPrivilege(privilege);
-        tNotAll.setAction(AccessConstants.SELECT);
-        MSentryPrivilege mSelect = getMSentryPrivilege(tNotAll, pm);
-        tNotAll.setAction(AccessConstants.INSERT);
-        MSentryPrivilege mInsert = getMSentryPrivilege(tNotAll, pm);
-        if ((mSelect != null) && mRole.getPrivileges().contains(mSelect)) {
-          mSelect.removeRole(mRole);
-          pm.makePersistent(mSelect);
-        }
-        if ((mInsert != null) && mRole.getPrivileges().contains(mInsert)) {
-          mInsert.removeRole(mRole);
-          pm.makePersistent(mInsert);
-        }
-      } else {
-        // If Grant is for Either INSERT/SELECT and ALL already exists..
-        // do nothing..
-        TSentryPrivilege tAll = new TSentryPrivilege(privilege);
-        tAll.setAction(AccessConstants.ALL);
-        MSentryPrivilege mAll1 = getMSentryPrivilege(tAll, pm);
-        tAll.setAction(AccessConstants.ACTION_ALL);
-        MSentryPrivilege mAll2 = getMSentryPrivilege(tAll, pm);
-        if (mAll1 != null && mRole.getPrivileges().contains(mAll1)) {
-          return null;
-        }
-        if (mAll2 != null && mRole.getPrivileges().contains(mAll2)) {
-          return null;
-        }
-      }
-    }
-
-    mPrivilege = getMSentryPrivilege(privilege, pm);
-    if (mPrivilege == null) {
-      mPrivilege = convertToMSentryPrivilege(privilege);
-    }
-    mPrivilege.appendRole(mRole);
-    pm.makePersistent(mPrivilege);
-    return mPrivilege;
-  }
-
-  /**
-   * Alter a given sentry user to grant a set of privileges.
-   * Internally calls alterSentryUserGrantPrivilege.
-   *
-   * @param grantorPrincipal User name
-   * @param userName User name
-   * @param privileges Set of privileges
-   * @throws Exception
-   */
-  public void alterSentryUserGrantPrivileges(final String grantorPrincipal,
-      final String userName, final Set<TSentryPrivilege> privileges) throws Exception {
-
-    try {
-      MSentryUser userEntry = getMSentryUserByName(userName, false);
-      if (userEntry == null) {
-        createSentryUser(userName);
-      }
-    } catch (SentryAlreadyExistsException e) {
-        // the user may be created by other thread, so swallow the exception and proceed
-    }
-
-    for (TSentryPrivilege privilege : privileges) {
-      alterSentryUserGrantPrivilege(grantorPrincipal, userName, privilege);
-    }
-  }
-
-  /**
-   * Alter a given sentry user to grant a privilege.
-   *
-   * @param grantorPrincipal User name
-   * @param userName the given user name
-   * @param privilege the given privilege
-   * @throws Exception
-   */
-  void alterSentryUserGrantPrivilege(final String grantorPrincipal,
-      final String userName, final TSentryPrivilege privilege) throws Exception {
-    tm.executeTransactionWithRetry(
-        new TransactionBlock<Object>() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            pm.setDetachAllOnCommit(false); // No need to detach objects
-            String trimmedUserName = trimAndLower(userName);
-            // first do grant check
-            grantOptionCheck(pm, grantorPrincipal, privilege);
-
-            // Alter sentry User and grant Privilege.
-            MSentryPrivilege mPrivilege = alterSentryUserGrantPrivilegeCore(
-                pm, trimmedUserName, privilege);
-
-            if (mPrivilege != null) {
-              // update the privilege to be the one actually updated.
-              convertToTSentryPrivilege(mPrivilege, privilege);
-            }
-            return null;
-          }
-        });
-  }
-
-  /**
-   * Alter a given sentry user to grant a privilege, as well as persist the corresponding
-   * permission change to MSentryPermChange table in a single transaction.
-   *
-   * @param grantorPrincipal User name
-   * @param userName the given user name
-   * @param privilege the given privilege
-   * @param update the corresponding permission delta update.
-   * @throws Exception
-   *
-   */
-  synchronized void alterSentryUserGrantPrivilege(final String grantorPrincipal,
-      final String userName, final TSentryPrivilege privilege,
-      final Update update) throws Exception {
-
-    execute(update, new TransactionBlock<Object>() {
-      public Object execute(PersistenceManager pm) throws Exception {
-        pm.setDetachAllOnCommit(false); // No need to detach objects
-        String trimmedUserName = trimAndLower(userName);
-        // first do grant check
-        grantOptionCheck(pm, grantorPrincipal, privilege);
-
-        // Alter sentry User and grant Privilege.
-        MSentryPrivilege mPrivilege = alterSentryUserGrantPrivilegeCore(pm,
-            trimmedUserName, privilege);
-
-        if (mPrivilege != null) {
-          // update the privilege to be the one actually updated.
-          convertToTSentryPrivilege(mPrivilege, privilege);
-        }
-        return null;
-      }
-    });
-  }
-
-  /**
-   * Alter a given sentry user to grant a set of privileges, as well as persist the
-   * corresponding permission change to MSentryPermChange table in a single transaction.
-   * Internally calls alterSentryUserGrantPrivilege.
-   *
-   * @param grantorPrincipal User name
-   * @param userName the given user name
-   * @param privileges a Set of privileges
-   * @param privilegesUpdateMap the corresponding <privilege, DeltaTransactionBlock> map
-   * @throws Exception
-   *
-   */
-  public void alterSentryUserGrantPrivileges(final String grantorPrincipal,
-      final String userName, final Set<TSentryPrivilege> privileges,
-      final Map<TSentryPrivilege, Update> privilegesUpdateMap) throws Exception {
-
-    try {
-      MSentryUser userEntry = getMSentryUserByName(userName, false);
-      if (userEntry == null) {
-        createSentryUser(userName);
-      }
-    } catch (SentryAlreadyExistsException e) {
-      // the user may be created by other thread, so swallow the exception and proeed
-    }
-
-    Preconditions.checkNotNull(privilegesUpdateMap);
-    for (TSentryPrivilege privilege : privileges) {
-      Update update = privilegesUpdateMap.get(privilege);
-      if (update != null) {
-        alterSentryUserGrantPrivilege(grantorPrincipal, userName, privilege,
-            update);
-      } else {
-        alterSentryUserGrantPrivilege(grantorPrincipal, userName, privilege);
-      }
-    }
-  }
-
-  /**
-   * Get the user entry by user name
-   * @param userName the name of the user
-   * @return the user entry
-   * @throws Exception if the specified user does not exist
-   */
-  @VisibleForTesting
-  public MSentryUser getMSentryUserByName(final String userName) throws Exception {
-    return getMSentryUserByName(userName, true);
-  }
-
-  /**
-   * Get the user entry by user name
-   * @param userName the name of the user
-   * @param throwExceptionIfNotExist true: throw exception if user does not exist; false: return null
-   * @return the user entry or null
-   * @throws Exception if the specified user does not exist and throwExceptionIfNotExist is true
-   */
-  MSentryUser getMSentryUserByName(final String userName, boolean throwExceptionIfNotExist) throws Exception {
-    return tm.executeTransaction(
-        new TransactionBlock<MSentryUser>() {
-          public MSentryUser execute(PersistenceManager pm) throws Exception {
-            String trimmedUserName = trimAndLower(userName);
-            MSentryUser sentryUser = getUser(pm, trimmedUserName);
-            if (sentryUser == null) {
-              if (throwExceptionIfNotExist) {
-                throw noSuchUser(trimmedUserName);
-              }
-              else {
-                return null;
-              }
-            }
-            return sentryUser;
-          }
-        });
-  }
-
-  private MSentryPrivilege alterSentryUserGrantPrivilegeCore(PersistenceManager pm,
-      String userName, TSentryPrivilege privilege)
-      throws SentryNoSuchObjectException, SentryInvalidInputException {
-    MSentryPrivilege mPrivilege = null;
-    MSentryUser mUser = getUser(pm, userName);
-    if (mUser == null) {
-      throw noSuchUser(userName);
-    }
-
-    if(privilege.getPrivilegeScope().equalsIgnoreCase(PrivilegeScope.URI.name())
-        && StringUtils.isBlank(privilege.getURI())) {
-      throw new SentryInvalidInputException("cannot grant URI privileges to Null or EMPTY location");
-    }
-
-    if (!isNULL(privilege.getColumnName()) || !isNULL(privilege.getTableName())
-        || !isNULL(privilege.getDbName())) {
-      // If Grant is for ALL and Either INSERT/SELECT already exists..
-      // need to remove it and GRANT ALL..
-      if (AccessConstants.ALL.equalsIgnoreCase(privilege.getAction())
-          || AccessConstants.ACTION_ALL.equalsIgnoreCase(privilege.getAction())) {
-        TSentryPrivilege tNotAll = new TSentryPrivilege(privilege);
-        tNotAll.setAction(AccessConstants.SELECT);
-        MSentryPrivilege mSelect = getMSentryPrivilege(tNotAll, pm);
-        tNotAll.setAction(AccessConstants.INSERT);
-        MSentryPrivilege mInsert = getMSentryPrivilege(tNotAll, pm);
-        if ((mSelect != null) && mUser.getPrivileges().contains(mSelect)) {
-          mSelect.removeUser(mUser);
-          pm.makePersistent(mSelect);
-        }
-        if ((mInsert != null) && mUser.getPrivileges().contains(mInsert)) {
-          mInsert.removeUser(mUser);
-          pm.makePersistent(mInsert);
-        }
-      } else {
-        // If Grant is for Either INSERT/SELECT and ALL already exists..
-        // do nothing..
-        TSentryPrivilege tAll = new TSentryPrivilege(privilege);
-        tAll.setAction(AccessConstants.ALL);
-        MSentryPrivilege mAll1 = getMSentryPrivilege(tAll, pm);
-        tAll.setAction(AccessConstants.ACTION_ALL);
-        MSentryPrivilege mAll2 = getMSentryPrivilege(tAll, pm);
-        if (mAll1 != null && mUser.getPrivileges().contains(mAll1)) {
-          return null;
-        }
-        if (mAll2 != null && mUser.getPrivileges().contains(mAll2)) {
-          return null;
-        }
-      }
-    }
-
-    mPrivilege = getMSentryPrivilege(privilege, pm);
-    if (mPrivilege == null) {
-      mPrivilege = convertToMSentryPrivilege(privilege);
-    }
-    mPrivilege.appendUser(mUser);
-    pm.makePersistent(mPrivilege);
-    return mPrivilege;
-  }
-
-  /**
-   * Alter a given sentry user to revoke a privilege.
-   *
-   * @param grantorPrincipal User name
-   * @param userName the given user name
-   * @param tPrivilege the given privilege
-   * @throws Exception
-   *
-   */
-  void alterSentryUserRevokePrivilege(final String grantorPrincipal,
-      final String userName, final TSentryPrivilege tPrivilege) throws Exception {
-
-    tm.executeTransactionWithRetry(
-        new TransactionBlock<Object>() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            pm.setDetachAllOnCommit(false); // No need to detach objects
-            String trimmedUserName = safeTrimLower(userName);
-            // first do revoke check
-            grantOptionCheck(pm, grantorPrincipal, tPrivilege);
-
-            alterSentryUserRevokePrivilegeCore(pm, trimmedUserName, tPrivilege);
-            return null;
-          }
-        });
-  }
-
-  /**
-   * Alter a given sentry user to revoke a set of privileges.
-   * Internally calls alterSentryUserRevokePrivilege.
-   *
-   * @param grantorPrincipal User name
-   * @param userName the given user name
-   * @param tPrivileges a Set of privileges
-   * @throws Exception
-   *
-   */
-  public void alterSentryUserRevokePrivileges(final String grantorPrincipal,
-      final String userName, final Set<TSentryPrivilege> tPrivileges) throws Exception {
-    for (TSentryPrivilege tPrivilege : tPrivileges) {
-      alterSentryUserRevokePrivilege(grantorPrincipal, userName, tPrivilege);
-    }
-  }
-
-  /**
-   * Alter a given sentry user to revoke a set of privileges, as well as persist the
-   * corresponding permission change to MSentryPermChange table in a single transaction.
-   * Internally calls alterSentryUserRevokePrivilege.
-   *
-   * @param grantorPrincipal User name
-   * @param userName the given user name
-   * @param tPrivileges a Set of privileges
-   * @param privilegesUpdateMap the corresponding <privilege, Update> map
-   * @throws Exception
-   *
-   */
-  public void alterSentryUserRevokePrivileges(final String grantorPrincipal,
-      final String userName, final Set<TSentryPrivilege> tPrivileges,
-      final Map<TSentryPrivilege, Update> privilegesUpdateMap)
-      throws Exception {
-
-    Preconditions.checkNotNull(privilegesUpdateMap);
-    for (TSentryPrivilege tPrivilege : tPrivileges) {
-      Update update = privilegesUpdateMap.get(tPrivilege);
-      if (update != null) {
-        alterSentryUserRevokePrivilege(grantorPrincipal, userName,
-            tPrivilege, update);
-      } else {
-        alterSentryUserRevokePrivilege(grantorPrincipal, userName,
-            tPrivilege);
-      }
-    }
-  }
-
-  /**
-   * Alter a given sentry user to revoke a privilege, as well as persist the corresponding
-   * permission change to MSentryPermChange table in a single transaction.
-   *
-   * @param grantorPrincipal User name
-   * @param userName the given user name
-   * @param tPrivilege the given privilege
-   * @param update the corresponding permission delta update transaction block
-   * @throws Exception
-   *
-   */
-  private synchronized void alterSentryUserRevokePrivilege(final String grantorPrincipal,
-      final String userName, final TSentryPrivilege tPrivilege,
-      final Update update) throws Exception {
-    execute(update, new TransactionBlock<Object>() {
-      public Object execute(PersistenceManager pm) throws Exception {
-        pm.setDetachAllOnCommit(false); // No need to detach objects
-        String trimmedUserName = safeTrimLower(userName);
-        // first do revoke check
-        grantOptionCheck(pm, grantorPrincipal, tPrivilege);
-
-        alterSentryUserRevokePrivilegeCore(pm, trimmedUserName, tPrivilege);
-        return null;
-      }
-    });
-  }
-
-  private void alterSentryUserRevokePrivilegeCore(PersistenceManager pm,
-      String userName, TSentryPrivilege tPrivilege)
-      throws SentryNoSuchObjectException, SentryInvalidInputException {
-    MSentryUser mUser = getUser(pm, userName);
-    if (mUser == null) {
-      throw noSuchUser(userName);
-    }
-    if(tPrivilege.getPrivilegeScope().equalsIgnoreCase(PrivilegeScope.URI.name())
-        && StringUtils.isBlank(tPrivilege.getURI())) {
-      throw new SentryInvalidInputException("cannot revoke URI privileges from Null or EMPTY location");
-    }
-
-    MSentryPrivilege mPrivilege = getMSentryPrivilege(tPrivilege, pm);
-    if (mPrivilege == null) {
-      mPrivilege = convertToMSentryPrivilege(tPrivilege);
-    } else {
-      mPrivilege = pm.detachCopy(mPrivilege);
-    }
-
-    Set<MSentryPrivilege> privilegeGraph = new HashSet<>();
-    if (mPrivilege.getGrantOption() != null) {
-      privilegeGraph.add(mPrivilege);
-    } else {
-      MSentryPrivilege mTure = new MSentryPrivilege(mPrivilege);
-      mTure.setGrantOption(true);
-      privilegeGraph.add(mTure);
-      MSentryPrivilege mFalse = new MSentryPrivilege(mPrivilege);
-      mFalse.setGrantOption(false);
-      privilegeGraph.add(mFalse);
-    }
-    // Get the privilege graph
-    populateChildren(pm, SentryEntityType.USER, Sets.newHashSet(userName), mPrivilege, privilegeGraph);
-    for (MSentryPrivilege childPriv : privilegeGraph) {
-      revokePrivilegeFromUser(pm, tPrivilege, mUser, childPriv);
-    }
-    pm.makePersistent(mUser);
-  }
-
-  /**
-  * Alter a given sentry role to revoke a privilege.
-  *
-  * @param grantorPrincipal User name
-  * @param roleName the given role name
-  * @param tPrivilege the given privilege
-  * @throws Exception
-  *
-  */
-  void alterSentryRoleRevokePrivilege(final String grantorPrincipal,
-      final String roleName, final TSentryPrivilege tPrivilege) throws Exception {
-
-    tm.executeTransactionWithRetry(
-            pm -> {
-              pm.setDetachAllOnCommit(false); // No need to detach objects
-              String trimmedRoleName = safeTrimLower(roleName);
-              // first do revoke check
-              grantOptionCheck(pm, grantorPrincipal, tPrivilege);
-
-              alterSentryRoleRevokePrivilegeCore(pm, trimmedRoleName, tPrivilege);
-              return null;
-            });
-  }
-
-  /**
-   * Alter a given sentry role to revoke a set of privileges.
-   * Internally calls alterSentryRoleRevokePrivilege.
-   *
-   * @param grantorPrincipal User name
-   * @param roleName the given role name
-   * @param tPrivileges a Set of privileges
-   * @throws Exception
-   *
-   */
-  public void alterSentryRoleRevokePrivileges(final String grantorPrincipal,
-      final String roleName, final Set<TSentryPrivilege> tPrivileges) throws Exception {
-    for (TSentryPrivilege tPrivilege : tPrivileges) {
-      alterSentryRoleRevokePrivilege(grantorPrincipal, roleName, tPrivilege);
-    }
-  }
-
-  /**
-   * Alter a given sentry role to revoke a privilege, as well as persist the corresponding
-   * permission change to MSentryPermChange table in a single transaction.
-   *
-   * @param grantorPrincipal User name
-   * @param roleName the given role name
-   * @param tPrivilege the given privilege
-   * @param update the corresponding permission delta update transaction block
-   * @throws Exception
-   *
-   */
-  private synchronized void alterSentryRoleRevokePrivilege(final String grantorPrincipal,
-                                              final String roleName, final TSentryPrivilege tPrivilege,
-                                              final Update update) throws Exception {
-    execute(update, pm -> {
-      pm.setDetachAllOnCommit(false); // No need to detach objects
-      String trimmedRoleName = safeTrimLower(roleName);
-      // first do revoke check
-      grantOptionCheck(pm, grantorPrincipal, tPrivilege);
-
-      alterSentryRoleRevokePrivilegeCore(pm, trimmedRoleName, tPrivilege);
-      return null;
-    });
-  }
-
-  /**
-   * Alter a given sentry role to revoke a set of privileges, as well as persist the
-   * corresponding permission change to MSentryPermChange table in a single transaction.
-   * Internally calls alterSentryRoleRevokePrivilege.
-   *
-   * @param grantorPrincipal User name
-   * @param roleName the given role name
-   * @param tPrivileges a Set of privileges
-   * @param privilegesUpdateMap the corresponding <privilege, Update> map
-   * @throws Exception
-   *
-   */
-  public void alterSentryRoleRevokePrivileges(final String grantorPrincipal,
-      final String roleName, final Set<TSentryPrivilege> tPrivileges,
-      final Map<TSentryPrivilege, Update> privilegesUpdateMap)
-          throws Exception {
-
-    Preconditions.checkNotNull(privilegesUpdateMap);
-    for (TSentryPrivilege tPrivilege : tPrivileges) {
-      Update update = privilegesUpdateMap.get(tPrivilege);
-      if (update != null) {
-        alterSentryRoleRevokePrivilege(grantorPrincipal, roleName,
-          tPrivilege, update);
-      } else {
-        alterSentryRoleRevokePrivilege(grantorPrincipal, roleName,
-          tPrivilege);
-      }
-    }
-  }
-
-  private void alterSentryRoleRevokePrivilegeCore(PersistenceManager pm,
-      String roleName, TSentryPrivilege tPrivilege)
-      throws SentryNoSuchObjectException, SentryInvalidInputException {
-    MSentryRole mRole = getRole(pm, roleName);
-    if (mRole == null) {
-      throw noSuchRole(roleName);
-    }
-    if(tPrivilege.getPrivilegeScope().equalsIgnoreCase(PrivilegeScope.URI.name())
-        && StringUtils.isBlank(tPrivilege.getURI())) {
-      throw new SentryInvalidInputException("cannot revoke URI privileges from Null or EMPTY location");
-    }
-
-    MSentryPrivilege mPrivilege = getMSentryPrivilege(tPrivilege, pm);
-    if (mPrivilege == null) {
-      mPrivilege = convertToMSentryPrivilege(tPrivilege);
-    } else {
-      mPrivilege = pm.detachCopy(mPrivilege);
-    }
-
-    Set<MSentryPrivilege> privilegeGraph = new HashSet<>();
-    if (mPrivilege.getGrantOption() != null) {
-      privilegeGraph.add(mPrivilege);
-    } else {
-      MSentryPrivilege mTure = new MSentryPrivilege(mPrivilege);
-      mTure.setGrantOption(true);
-      privilegeGraph.add(mTure);
-      MSentryPrivilege mFalse = new MSentryPrivilege(mPrivilege);
-      mFalse.setGrantOption(false);
-      privilegeGraph.add(mFalse);
-    }
-    // Get the privilege graph
-    populateChildren(pm, SentryEntityType.ROLE, Sets.newHashSet(roleName), mPrivilege, privilegeGraph);
-    for (MSentryPrivilege childPriv : privilegeGraph) {
-      revokePrivilegeFromRole(pm, tPrivilege, mRole, childPriv);
-    }
-    pm.makePersistent(mRole);
-  }
-
-  /**
-   * Roles can be granted ALL, SELECT, and INSERT on tables. When
-   * a role has ALL and SELECT or INSERT are revoked, we need to remove the ALL
-   * privilege and add SELECT (INSERT was revoked) or INSERT (SELECT was revoked).
-   */
-  private void revokePartial(PersistenceManager pm,
-                             TSentryPrivilege requestedPrivToRevoke,
-                             MSentryRole mRole, MSentryUser mUser,
-                             MSentryPrivilege currentPrivilege) throws SentryInvalidInputException {
-    MSentryPrivilege persistedPriv =
-      getMSentryPrivilege(convertToTSentryPrivilege(currentPrivilege), pm);
-    if (persistedPriv == null) {
-      // The privilege corresponding to the currentPrivilege doesn't exist in the persistent
-      // store, so we create a fake one for the code below. The fake one is not associated with
-      // any role and shouldn't be stored in the persistent storage.
-      persistedPriv = convertToMSentryPrivilege(convertToTSentryPrivilege(currentPrivilege));
-    }
-
-    if (requestedPrivToRevoke.getAction().equalsIgnoreCase(AccessConstants.ALL) ||
-      requestedPrivToRevoke.getAction().equalsIgnoreCase(AccessConstants.ACTION_ALL)) {
-      if (!persistedPriv.getRoles().isEmpty()) {
-        if (mRole != null) {
-          persistedPriv.removeRole(mRole);
-        }
-        if (mUser != null) {
-          persistedPriv.removeUser(mUser);
-        }
-
-        if (isPrivilegeStall(persistedPriv)) {
-          pm.deletePersistent(persistedPriv);
-        } else {
-          pm.makePersistent(persistedPriv);
-        }
-      }
-    } else {
-
-      Set<String> addActions = new HashSet<String>();
-      for (String actionToAdd : PARTIAL_REVOKE_ACTIONS) {
-        if( !requestedPrivToRevoke.getAction().equalsIgnoreCase(actionToAdd) &&
-            !currentPrivilege.getAction().equalsIgnoreCase(actionToAdd) &&
-            !AccessConstants.ALL.equalsIgnoreCase(actionToAdd) &&
-            !AccessConstants.ACTION_ALL.equalsIgnoreCase(actionToAdd)) {
-          addActions.add(actionToAdd);
-        }
-      }
-
-      if (mRole != null) {
-        revokeRolePartial(pm, mRole, currentPrivilege, persistedPriv, addActions);
-      }
-
-      if (mUser != null) {
-        revokeUserPartial(pm, mUser, currentPrivilege, persistedPriv, addActions);
-      }
-    }
-  }
-
-  private boolean isPrivilegeStall(MSentryPrivilege privilege) {
-    if (privilege.getUsers().isEmpty() && privilege.getRoles().isEmpty()) {
-      return true;
-    }
-
-    return false;
-  }
-
-  private boolean isPrivilegeStall(MSentryGMPrivilege privilege) {
-    if (privilege.getRoles().isEmpty()) {
-      return true;
-    }
-
-    return false;
-  }
-
-  private void revokeRolePartial(PersistenceManager pm, MSentryRole mRole,
-                                 MSentryPrivilege currentPrivilege,
-                                 MSentryPrivilege persistedPriv,
-                                 Set<String> addActions) throws SentryInvalidInputException {
-    // If table / URI, remove ALL
-    persistedPriv = getMSentryPrivilege(convertToTSentryPrivilege(persistedPriv), pm);
-    if (persistedPriv != null && !persistedPriv.getRoles().isEmpty()) {
-      persistedPriv.removeRole(mRole);
-      if (isPrivilegeStall(persistedPriv)) {
-        pm.deletePersistent(persistedPriv);
-      } else {
-        pm.makePersistent(persistedPriv);
-      }
-    }
-    currentPrivilege.setAction(AccessConstants.ALL);
-    persistedPriv = getMSentryPrivilege(convertToTSentryPrivilege(currentPrivilege), pm);
-    if (persistedPriv != null && mRole.getPrivileges().contains(persistedPriv)) {
-      persistedPriv.removeRole(mRole);
-      if (isPrivilegeStall(persistedPriv)) {
-        pm.deletePersistent(persistedPriv);
-      } else {
-        pm.makePersistent(persistedPriv);
-      }
-
-      // add decomposted actions
-      for (String addAction : addActions) {
-        currentPrivilege.setAction(addAction);
-        TSentryPrivilege tSentryPrivilege = convertToTSentryPrivilege(currentPrivilege);
-        persistedPriv = getMSentryPrivilege(tSentryPrivilege, pm);
-        if (persistedPriv == null) {
-          persistedPriv = convertToMSentryPrivilege(tSentryPrivilege);
-        }
-        mRole.appendPrivilege(persistedPriv);
-      }
-      persistedPriv.appendRole(mRole);
-      pm.makePersistent(persistedPriv);
-    }
-  }
-
-  private void revokeUserPartial(PersistenceManager pm, MSentryUser mUser,
-      MSentryPrivilege currentPrivilege,
-      MSentryPrivilege persistedPriv,
-      Set<String> addActions) throws SentryInvalidInputException {
-    // If table / URI, remove ALL
-    persistedPriv = getMSentryPrivilege(convertToTSentryPrivilege(persistedPriv), pm);
-    if (persistedPriv != null && !persistedPriv.getUsers().isEmpty()) {
-      persistedPriv.removeUser(mUser);
-      if (isPrivilegeStall(persistedPriv)) {
-        pm.deletePersistent(persistedPriv);
-      } else {
-        pm.makePersistent(persistedPriv);
-      }
-    }
-    currentPrivilege.setAction(AccessConstants.ALL);
-    persistedPriv = getMSentryPrivilege(convertToTSentryPrivilege(currentPrivilege), pm);
-    if (persistedPriv != null && mUser.getPrivileges().contains(persistedPriv)) {
-      persistedPriv.removeUser(mUser);
-      if (isPrivilegeStall(persistedPriv)) {
-        pm.deletePersistent(persistedPriv);
-      } else {
-        pm.makePersistent(persistedPriv);
-      }
-
-      // add decomposted actions
-      for (String addAction : addActions) {
-        currentPrivilege.setAction(addAction);
-        TSentryPrivilege tSentryPrivilege = convertToTSentryPrivilege(currentPrivilege);
-        persistedPriv = getMSentryPrivilege(tSentryPrivilege, pm);
-        if (persistedPriv == null) {
-          persistedPriv = convertToMSentryPrivilege(tSentryPrivilege);
-        }
-        mUser.appendPrivilege(persistedPriv);
-      }
-      persistedPriv.appendUser(mUser);
-      pm.makePersistent(persistedPriv);
-    }
-  }
-
-  /**
-   * Revoke privilege from role
-   */
-  private void revokePrivilegeFromRole(PersistenceManager pm, TSentryPrivilege tPrivilege,
-                                       MSentryRole mRole, MSentryPrivilege mPrivilege)
-    throws SentryInvalidInputException {
-    if (PARTIAL_REVOKE_ACTIONS.contains(mPrivilege.getAction())) {
-      // if this privilege is in parital revoke actions
-      // we will do partial revoke
-      revokePartial(pm, tPrivilege, mRole, null, mPrivilege);
-    } else {
-      // otherwise,
-      // we will revoke it from role directly
-      MSentryPrivilege persistedPriv = getMSentryPrivilege(convertToTSentryPrivilege(mPrivilege), pm);
-      if (persistedPriv != null && !persistedPriv.getRoles().isEmpty()) {
-        persistedPriv.removeRole(mRole);
-        if (isPrivilegeStall(persistedPriv)) {
-          pm.deletePersistent(persistedPriv);
-        } else {
-          pm.makePersistent(persistedPriv);
-        }
-      }
-    }
-  }
-
-  /**
-   * Revoke privilege from user
-   */
-  private void revokePrivilegeFromUser(PersistenceManager pm, TSentryPrivilege tPrivilege,
-      MSentryUser mUser, MSentryPrivilege mPrivilege)
-      throws SentryInvalidInputException {
-    if (PARTIAL_REVOKE_ACTIONS.contains(mPrivilege.getAction())) {
-      // if this privilege is in parital revoke actions
-      // we will do partial revoke
-      revokePartial(pm, tPrivilege, null, mUser, mPrivilege);
-    } else {
-      // otherwise,
-      // we will revoke it from user directly
-      MSentryPrivilege persistedPriv = getMSentryPrivilege(convertToTSentryPrivilege(mPrivilege), pm);
-      if (persistedPriv != null && !persistedPriv.getUsers().isEmpty()) {
-        persistedPriv.removeUser(mUser);
-        if (isPrivilegeStall(persistedPriv)) {
-          pm.deletePersistent(persistedPriv);
-        } else {
-          pm.makePersistent(persistedPriv);
-        }
-      }
-    }
-  }
-
-  /**
-   * Explore Privilege graph and collect child privileges.
-   * The responsibility to commit/rollback the transaction should be handled by the caller.
-   */
-  private void populateChildren(PersistenceManager pm, SentryEntityType entityType, Set<String> entityNames, MSentryPrivilege priv,
-      Collection<MSentryPrivilege> children) throws SentryInvalidInputException {
-    Preconditions.checkNotNull(pm);
-    if (!isNULL(priv.getServerName()) || !isNULL(priv.getDbName())
-        || !isNULL(priv.getTableName())) {
-      // Get all TableLevel Privs
-      Set<MSentryPrivilege> childPrivs = getChildPrivileges(pm, entityType, entityNames, priv);
-      for (MSentryPrivilege childPriv : childPrivs) {
-        // Only recurse for table level privs..
-        if (!isNULL(childPriv.getDbName()) && !isNULL(childPriv.getTableName())
-            && !isNULL(childPriv.getColumnName())) {
-          populateChildren(pm, entityType, entityNames, childPriv, children);
-        }
-        // The method getChildPrivileges() didn't do filter on "action",
-        // if the action is not "All", it should judge the action of children privilege.
-        // For example: a user has a privilege “All on Col1”,
-        // if the operation is “REVOKE INSERT on table”
-        // the privilege should be the child of table level privilege.
-        // but the privilege may still have other meaning, likes "SELECT, CREATE etc. on Col1".
-        // and the privileges like "SELECT, CREATE etc. on Col1" should not be revoke.
-        if (!priv.isActionALL()) {
-          if (childPriv.isActionALL()) {
-            // If the child privilege is All, we should convert it to the same
-            // privilege with parent
-            childPriv.setAction(priv.getAction());
-          }
-          // Only include privilege that imply the parent privilege.
-          if (!priv.implies(childPriv)) {
-            continue;
-          }
-        }
-        children.add(childPriv);
-      }
-    }
-  }
-
-  private Set<MSentryPrivilege> getChildPrivileges(PersistenceManager pm, SentryEntityType entityType, Set<String> entityNames,
-      MSentryPrivilege parent) throws SentryInvalidInputException {
-    // Column and URI do not have children
-    if (!isNULL(parent.getColumnName()) || !isNULL(parent.getURI())) {
-      return Collections.emptySet();
-    }
-
-    Query query = pm.newQuery(MSentryPrivilege.class);
-    QueryParamBuilder paramBuilder = null;
-    if (entityType == SentryEntityType.ROLE) {
-      paramBuilder = QueryParamBuilder.addRolesFilter(query, null, entityNames).add(SERVER_NAME, parent.getServerName());
-    } else if (entityType == SentryEntityType.USER) {
-      paramBuilder = QueryParamBuilder.addUsersFilter(query, null, entityNames).add(SERVER_NAME, parent.getServerName());
-    } else {
-      throw new SentryInvalidInputException("entityType" + entityType + " is not valid");
-    }
-
-    if (!isNULL(parent.getDbName())) {
-      paramBuilder.add(DB_NAME, parent.getDbName());
-      if (!isNULL(parent.getTableName())) {
-        paramBuilder.add(TABLE_NAME, parent.getTableName())
-            .addNotNull(COLUMN_NAME);
-      } else {
-        paramBuilder.addNotNull(TABLE_NAME);
-      }
-    } else {
-      // Add condition dbName != NULL || URI != NULL
-      paramBuilder.newChild()
-          .addNotNull(DB_NAME)
-          .addNotNull(URI);
-    }
-
-    query.setFilter(paramBuilder.toString());
-    query.setResult("privilegeScope, serverName, dbName, tableName, columnName," +
-        " URI, action, grantOption");
-    List<Object[]> privObjects =
-        (List<Object[]>) query.executeWithMap(paramBuilder.getArguments());
-    Set<MSentryPrivilege> privileges = new HashSet<>(privObjects.size());
-    for (Object[] privObj : privObjects) {
-      String scope        = (String)privObj[0];
-      String serverName   = (String)privObj[1];
-      String dbName       = (String)privObj[2];
-      String tableName    = (String) privObj[3];
-      String columnName   = (String) privObj[4];
-      String URI          = (String) privObj[5];
-      String action       = (String) privObj[6];
-      Boolean grantOption = (Boolean) privObj[7];
-      MSentryPrivilege priv =
-          new MSentryPrivilege(scope, serverName, dbName, tableName,
-              columnName, URI, action, grantOption);
-      privileges.add(priv);
-    }
-    return privileges;
-  }
-
-  /**
-   * Drop a given sentry user.
-   *
-   * @param userName the given user name
-   * @throws Exception
-   */
-  public void dropSentryUser(final String userName) throws Exception {
-    tm.executeTransactionWithRetry(
-        new TransactionBlock<Object>() {
-          public Object execute(PersistenceManager pm) throws Exception {
-            pm.setDetachAllOnCommit(false); // No need to detach objects
-            dropSentryUserCore(pm, userName);
-            return null;
-          }
-        });
-  }
-
-  /**
-   * Drop a given sentry user. As well as persist the corresponding
-   * permission change to MSentryPermChange table in a single transaction.
-   *
-   * @param userName the given user name
-   * @param update the corresponding permission delta update
-   * @throws Exception
-   */
-  public synchronized void dropSentryUser(final String userName,
-      final Update update) throws Exception {
-    execute(update, new TransactionBlock<Object>() {
-      public Object execute(PersistenceManager pm) throws Exception {
-        pm.setDetachAllOnCommit(false); // No need to detach objects
-        dropSentryUserCore(pm, userName);
-        return null;
-      }
-    });
-  }
-
-  private void dropSentryUserCore(PersistenceManager pm, String userName)
-      throws SentryNoSuchObjectException {
-    String lUserName = trimAndLower(userName);
-    MSentryUser sentryUser = getUser(pm, lUserName);
-    if (sentryUser == null) {
-      throw noSuchUser(lUserName);
-    }
-    removePrivilegesForUser(pm, sentryUser);
-    pm.deletePersistent(sentryUser);
-  }
-
-  /**
-   * Removes all the privileges associated with
-   * a particular user. After this dis-association if the
-   * privilege doesn't have any users associated it will be
-   * removed from the underlying persistence layer.
-   * @param pm Instance of PersistenceManager
-   * @param sentryUser User for which all the privileges are to be removed.
-   */
-  private void removePrivilegesForUser(PersistenceManager pm, MSentryUser sentryUser) {
-    List<MSentryPrivilege> privilegesCopy = new ArrayList<>(sentryUser.getPrivileges());
-
-    sentryUser.removePrivileges();
-
-    removeStaledPrivileges(pm, privilegesCopy);
-  }
-
-  @SuppressWarnings("unchecked")
-  private List<MSentryPrivilege> getMSentryPrivileges(TSentryPrivilege tPriv, PersistenceManager pm) {
-    Query query = pm.newQuery(MSentryPrivilege.class);
-    QueryParamBuilder paramBuilder = newQueryParamBuilder();
-    paramBuilder
-            .add(SERVER_NAME, tPriv.getServerName())
-            .add("action", tPriv.getAction());
-
-    if (!isNULL(tPriv.getDbName())) {
-      paramBuilder.add(DB_NAME, tPriv.getDbName());
-      if (!isNULL(tPriv.getTableName())) {
-        paramBuilder.add(TABLE_NAME, tPriv.getTableName());
-        if (!isNULL(tPriv.getColumnName())) {
-          paramBuilder.add(COLUMN_NAME, tPriv.getColumnName());
-        }
-      }
-    } else if (!isNULL(tPriv.getURI())) {
-      // if db is null, uri is not null
-      paramBuilder.add(URI, tPriv.getURI(), true);
-    }
-
-    query.setFilter(paramBuilder.toString());
-    return (List<MSentryPrivilege>) query.executeWithMap(paramBuilder.getArguments());
-  }
-
-  private MSentryPrivilege getMSentryPrivilege(TSentryPrivilege tPriv, PersistenceManager pm) {
-    Boolean grantOption = null;
-    if (tPriv.getGrantOption().equals(TSentryGrantOption.TRUE)) {
-      grantOption = true;
-    } else if (tPriv.getGrantOption().equals(TSentryGrantOption.FALSE)) {
-      grantOption = false;
-    }
-
-    QueryParamBuilder paramBuilder = newQueryParamBuilder();
-    paramBuilder.add(SERVER_NAME, tPriv.getServerName())
-            .add(DB_NAME, tPriv.getDbName())
-            .add(TABLE_NAME, tPriv.getTableName())
-            .add(COLUMN_NAME, tPriv.getColumnName())
-            .add(URI, tPriv.getURI(), true)
-            .addObject(GRANT_OPTION, grantOption)
-            .add(ACTION, tPriv.getAction());
-
-    Query query = pm.newQuery(MSentryPrivilege.class);
-    query.setUnique(true);
-    query.setFilter(paramBuilder.toString());
-    return (MSentryPrivilege)query.executeWithMap(paramBuilder.getArguments());
-  }
-
-  /**
-   * Drop a given sentry role.
-   *
-   * @param roleName the given role name
-   * @throws Exception
-   */
-  public void dropSentryRole(final String roleName) throws Exception {
-    tm.executeTransactionWithRetry(
-            pm -> {
-              pm.setDetachAllOnCommit(false); // No need to detach objects
-              dropSentryRoleCore(pm, roleName);
-              return null;
-            });
-  }
-
-  /**
-   * Drop a given sentry role. As well as persist the corresponding
-   * permission change to MSentryPermChange table in a single transaction.
-   *
-   * @param roleName the given role name
-   * @param update the corresponding permission delta update
-   * @throws Exception
-   */
-  public synchronized void dropSentryRole(final String roleName,
-      final Update update) throws Exception {
-    execute(update, pm -> {
-      pm.setDetachAllOnCommit(false); // No need to detach objects
-      dropSentryRoleCore(pm, roleName);
-      return null;
-    });
-  }
-
-  private void dropSentryRoleCore(PersistenceManager pm, String roleName)
-      throws SentryNoSuchObjectException {
-    String lRoleName = trimAndLower(roleName);
-    MSentryRole sentryRole = getRole(pm, lRoleName);
-    if (sentryRole == null) {
-      throw noSuchRole(lRoleName);
-    }
-    removePrivileges(pm, sentryRole);
-    pm.deletePersistent(sentryRole);
-  }
-
-  /**
-   * Removes all the privileges associated with
-   * a particular role. After this dis-association if the
-   * privilege doesn't have any roles associated it will be
-   * removed from the underlying persistence layer.
-   * @param pm Instance of PersistenceManager
-   * @param sentryRole Role for which all the privileges are to be removed.
-   */
-  private void removePrivileges(PersistenceManager pm, MSentryRole sentryRole) {
-    List<MSentryPrivilege> privilegesCopy = new ArrayList<>(sentryRole.getPrivileges());
-    List<MSentryGMPrivilege> gmPrivilegesCopy = new ArrayList<>(sentryRole.getGmPrivileges());
-
-    sentryRole.removePrivileges();
-    // with SENTRY-398 generic model
-    sentryRole.removeGMPrivileges();
-
-    removeStaledPrivileges(pm, privilegesCopy);
-    removeStaledGMPrivileges(pm, gmPrivilegesCopy);
-  }
-
-  private void removeStaledPrivileges(PersistenceManager pm, List<MSentryPrivilege> privilegesCopy) {
-    List<MSentryPrivilege> stalePrivileges = new ArrayList<>(0);
-    for (MSentryPrivilege privilege : privilegesCopy) {
-      if (isPrivilegeStall(privilege)) {
-        stalePrivileges.add(privilege);
-      }
-    }
-    if(!stalePrivileges.isEmpty()) {
-      pm.deletePersistentAll(stalePrivileges);
-    }
-  }
-
-  private void removeStaledGMPrivileges(PersistenceManager pm, List<MSentryGMPrivilege> privilegesCopy) {
-    List<MSentryGMPrivilege> stalePrivileges = new ArrayList<>(0);
-    for (MSentryGMPrivilege privilege : privilegesCopy) {
-      if (isPrivilegeStall(privilege)) {
-        stalePrivileges.add(privilege);
-      }
-    }
-    if(!stalePrivileges.isEmpty()) {
-      pm.deletePersistentAll(stalePrivileges);
-    }
-  }
-
-  /**
-   * Assign a given role to a set of groups.
-   *
-   * @param grantorPrincipal grantorPrincipal currently is not used.
-   * @param roleName the role to be assigned to the groups.
-   * @param groupNames the list of groups to be added to the role,
-   * @throws Exception
-   */
-  public void alterSentryRoleAddGroups(final String grantorPrincipal,
-      final String roleName, final Set<TSentryGroup> groupNames) throws Exception {
-    tm.executeTransactionWithRetry(
-            pm -> {
-              pm.setDetachAllOnCommit(false); // No need to detach objects
-              alterSentryRoleAddGroupsCore(pm, roleName, groupNames);
-              return null;
-            });
-  }
-
-  /**
-   * Assign a given role to a set of groups. As well as persist the corresponding
-   * permission change to MSentryPermChange table in a single transaction.
-   *
-   * @param grantorPrincipal grantorPrincipal currently is not used.
-   * @param roleName the role to be assigned to the groups.
-   * @param groupNames the list of groups to be added to the role,
-   * @param update the corresponding permission delta update
-   * @throws Exception
-   */
-  public synchronized void alterSentryRoleAddGroups(final String grantorPrincipal,
-      final String roleName, final Set<TSentryGroup> groupNames,
-      final Update update) throws Exception {
-
-    execute(update, pm -> {
-      pm.setDetachAllOnCommit(false); // No need to detach objects
-      alterSentryRoleAddGroupsCore(pm, roleName, groupNames);
-      return null;
-    });
-  }
-
-  private void alterSentryRoleAddGroupsCore(PersistenceManager pm, String roleName,
-      Set<TSentryGroup> groupNames) throws SentryNoSuchObjectException {
-
-    // All role names are stored in lowercase.
-    String lRoleName = trimAndLower(roleName);
-    MSentryRole role = getRole(pm, lRoleName);
-    if (role == null) {
-      throw noSuchRole(lRoleName);
-    }
-
-    // Add the group to the specified role if it does not belong to the role yet.
-    Query query = pm.newQuery(MSentryGroup.class);
-    query.setFilter("this.groupName == :groupName");
-    query.setUnique(true);
-    List<MSentryGroup> groups = Lists.newArrayList();
-    for (TSentryGroup tGroup : groupNames) {
-      String groupName = tGroup.getGroupName().trim();
-      MSentryGroup group = (MSentryGroup) query.execute(groupName);
-      if (group == null) {
-        group = new MSentryGroup(groupName, System.currentTimeMillis(), Sets.newHashSet(role));
-      }
-      group.appendRole(role);
-      groups.add(group);
-    }
-    pm.makePersistentAll(groups);
-  }
-
-  public void alterSentryRoleAddUsers(final String roleName,
-      final Set<String> userNames) throws Exception {
-    tm.executeTransactionWithRetry(
-            pm -> {
-              pm.setDetachAllOnCommit(false); // No need to detach objects
-              alterSentryRoleAddUsersCore(pm, roleName, userNames);
-              return null;
-            });
-  }
-
-  private void alterSentryRoleAddUsersCore(PersistenceManager pm, String roleName,
-      Set<String> userNames) throws SentryNoSuchObjectException {
-    String trimmedRoleName = trimAndLower(roleName);
-    MSentryRole role = getRole(pm, trimmedRoleName);
-    if (role == null) {
-      throw noSuchRole(trimmedRoleName);
-    }
-    Query query = pm.newQuery(MSentryUser.class);
-    query.setFilter("this.userName == :userName");
-    query.setUnique(true);
-    List<MSentryUser> users = Lists.newArrayList();
-    for (String userName : userNames) {
-      userName = userName.trim();
-      MSentryUser user = (MSentryUser) query.execute(userName);
-      if (user == null) {
-        user = new MSentryUser(userName, System.currentTimeMillis(), Sets.newHashSet(role));
-      }
-      user.appendRole(role);
-      users.add(user);
-    }
-    pm.makePersistentAll(users);
-  }
-
-  public void alterSentryRoleDeleteUsers(final String roleName,
-      final Set<String> userNames) throws Exception {
-    tm.executeTransactionWithRetry(
-            pm -> {
-              pm.setDetachAllOnCommit(false); // No need to detach objects
-              String trimmedRoleName = trimAndLower(roleName);
-              MSentryRole role = getRole(pm, trimmedRoleName);
-              if (role == null) {
-                throw noSuchRole(trimmedRoleName);
-              } else {
-                Query query = pm.newQuery(MSentryUser.class);
-                query.setFilter("this.userName == :userName");
-                query.setUnique(true);
-                List<MSentryUser> users = Lists.newArrayList();
-                for (String userName : userNames) {
-                  userName = userName.trim();
-                  MSentryUser user = (MSentryUser) query.execute(userName);
-                  if (user != null) {
-                    user.removeRole(role);
-                    users.add(user);
-                  }
-                }
-                pm.makePersistentAll(users);
-              }
-              return null;
-            });
-  }
-
-  /**
-   * Revoke a given role to a set of groups.
-   *
-   * @param roleName the role to be assigned to the groups.
-   * @param groupNames the list of groups to be added to the role,
-   * @throws Exception
-   */
-  public void alterSentryRoleDeleteGroups(final String roleName,
-      final Set<TSentryGroup> groupNames) throws Exception {
-    tm.executeTransactionWithRetry(
-            pm -> {
-              pm.setDetachAllOnCommit(false); // No need to detach objects
-              String trimmedRoleName = trimAndLower(roleName);
-              MSentryRole role = getRole(pm, trimmedRoleName);
-              if (role == null) {
-                throw noSuchRole(trimmedRoleName);
-              }
-              Query query = pm.newQuery(MSentryGroup.class);
-              query.setFilter("this.groupName == :groupName");
-              query.setUnique(true);
-              List<MSentryGroup> groups = Lists.newArrayList();
-              for (TSentryGroup tGroup : groupNames) {
-                String groupName = tGroup.getGroupName().trim();
-                MSentryGroup group = (MSentryGroup) query.execute(groupName);
-                if (group != null) {
-                  group.removeRole(role);
-                  groups.add(group);
-                }
-              }
-              pm.makePersistentAll(groups);
-              return null;
-            });
-  }
-
-  /**
-   * Revoke a given role to a set of groups. As well as persist the corresponding
-   * permission change to MSentryPermChange table in a single transaction.
-   *
-   * @param roleName the role to be assigned to the groups.
-   * @param groupNames the list of groups to be added to the role,
-   * @param update the corresponding permission delta update
-   * @throws Exception
-   */
-  public synchronized void alterSentryRoleDeleteGroups(final String roleName,
-      final Set<TSentryGroup> groupNames, final Update update)
-          throws Exception {
-    execute(update, pm -> {
-      pm.setDetachAllOnCommit(false); // No need to detach objects
-      String trimmedRoleName = trimAndLower(roleName);
-      MSentryRole role = getRole(pm, trimmedRoleName);
-      if (role == null) {
-        throw noSuchRole(trimmedRoleName);
-      }
-
-      // Remove the group from the specified role if it belongs to the role.
-      Query query = pm.newQuery(MSentryGroup.class);
-      query.setFilter("this.groupName == :groupName");
-      query.setUnique(true);
-      List<MSentryGroup> groups = Lists.newArrayList();
-      for (TSentryGroup tGroup : groupNames) {
-        String groupName = tGroup.getGroupName().trim();
-        MSentryGroup group = (MSentryGroup) query.execute(groupName);
-        if (group != null) {
-          group.removeRole(role);
-          groups.add(group);
-        }
-      }
-      pm.makePersistentAll(groups);
-      return null;
-    });
-  }
-
-  @VisibleForTesting
-  public MSentryRole getMSentryRoleByName(final String roleName) throws Exception {
-    return tm.executeTransaction(
-            pm -> {
-              String trimmedRoleName = trimAndLower(roleName);
-              MSentryRole sentryRole = getRole(pm, trimmedRoleName);
-              if (sentryRole == null) {
-                throw noSuchRole(trimmedRoleName);
-              }
-              return sentryRole;
-            });
-  }
-
-  /**
-   * Gets the MSentryPrivilege from sentry persistent storage based on TSentryPrivilege
-   * provided
-   *
-   * Method is currently used only in test framework
-   * @param tPrivilege
-   * @return MSentryPrivilege if the privilege is found in the storage
-   * null, if the privilege is not found in the storage.
-   * @throws Exception
-   */
-  @VisibleForTesting
-  MSentryPrivilege findMSentryPrivilegeFromTSentryPrivilege(final TSentryPrivilege tPrivilege) throws Exception {
-    return tm.executeTransaction(
-            pm -> getMSentryPrivilege(tPrivilege, pm));
-  }
-
-  /**
-   * Returns a list with all the privileges in the sentry persistent storage
-   *
-   * Method is currently used only in test framework
-   * @return List of all sentry privileges in the store
-   * @throws Exception
-   */
-  @VisibleForTesting
-  List<MSentryPrivilege> getAllMSentryPrivileges () throws Exception {
-    return tm.executeTransaction(
-            pm -> getAllMSentryPrivilegesCore(pm));
-  }
-
-  /**
-   * Method Returns all the privileges present in the persistent store as a list.
-   * @param pm PersistenceManager
-   * @returns list of all the privileges in the persistent store
-   */
-  private List<MSentryPrivilege> getAllMSentryPrivilegesCore (PersistenceManager pm) {
-    Query query = pm.newQuery(MSentryPrivilege.class);
-    return (List<MSentryPrivilege>) query.execute();
-  }
-
-  private boolean hasAnyServerPrivileges(final Set<String> roleNames, final String serverName) throws Exception {
-    if (roleNames == null || roleNames.isEmpty()) {
-      return false;
-    }
-    return tm.executeTransaction(
-            pm -> {
-              pm.setDetachAllOnCommit(false); // No need to detach objects
-              Query query = pm.newQuery(MSentryPrivilege.class);
-              query.addExtension(LOAD_RESULTS_AT_COMMIT, "false");
-              QueryParamBuilder paramBuilder = QueryParamBuilder.addRolesFilter(query,null, roleNames);
-              paramBuilder.add(SERVER_NAME, serverName);
-              query.setFilter(paramBuilder.toString());
-              query.setResult("count(this)");
-              Long numPrivs = (Long) query.executeWithMap(paramBuilder.getArguments());
-              return numPrivs > 0;
-            });
-  }
-
-  private List<MSentryPrivilege> getMSentryPrivileges(final SentryEntityType entityType, final Set<String> entityNames,
-      final TSentryAuthorizable authHierarchy)
-      throws Exception {
-    if (entityNames == null || entityNames.isEmpty()) {
-      return Collections.emptyList();
-    }
-
-    return tm.executeTransaction(
-        pm -> {
-          Query query = pm.newQuery(MSentryPrivilege.class);
-          QueryParamBuilder paramBuilder = null;
-          if (entityType == SentryEntityType.ROLE) {
-            paramBuilder = QueryParamBuilder.addRolesFilter(query, null, entityNames);
-          } else if (entityType == SentryEntityType.USER) {
-            paramBuilder = QueryParamBuilder.addUsersFilter(query, null, entityNames);
-          } else {
-            throw new SentryInvalidInputException("entityType" + entityType + " is not valid");
-          }
-
-          if (authHierarchy != null && authHierarchy.getServer() != null) {
-            paramBuilder.add(SERVER_NAME, authHierarchy.getServer());
-            if (authHierarchy.getDb() != null) {
-              paramBuilder.addNull(URI)
-                  .newChild()
-                  .add(DB_NAME, authHierarchy.getDb())
-                  .addNull(DB_NAME);
-              if (authHierarchy.getTable() != null
-                  && !AccessConstants.ALL.equalsIgnoreCase(authHierarchy.getTable())) {
-                if (!AccessConstants.SOME.equalsIgnoreCase(authHierarchy.getTable())) {
-                  paramBuilder.addNull(URI)
-                      .newChild()
-                      .add(TABLE_NAME, authHierarchy.getTable())
-                      .addNull(TABLE_NAME);
-                }
-                if (authHierarchy.getColumn() != null
-                    && !AccessConstants.ALL.equalsIgnoreCase(authHierarchy.getColumn())
-                    && !AccessConstants.SOME.equalsIgnoreCase(authHierarchy.getColumn())) {
-                  paramBuilder.addNull(URI)
-                      .newChild()
-                      .add(COLUMN_NAME, authHierarchy.getColumn())
-                      .addNull(COLUMN_NAME);
-                }
-              }
-            }
-            if (authHierarchy.getUri() != null) {
-              paramBuilder.addNull(DB_NAME)
-                  .newChild()
-                  .addNull(URI)
-                  .newChild()
-                  .addNotNull(URI)
-                  .addCustomParam("\"" + authHierarchy.getUri() +
-                      "\".startsWith(:URI)", URI, authHierarchy.getUri());
-            }
-          }
-
-          query.setFilter(paramBuilder.toString());
-          @SuppressWarnings("unchecked")
-          List<MSentryPrivilege> result =
-              (List<MSentryPrivilege>)
-                  query.executeWithMap(paramBuilder.getArguments());
-          return result;
-        });
-  }
-
-  private List<MSentryPrivilege> getMSentryPrivilegesByAuth(
-      final SentryEntityType entityType,
-      final Set<String> entityNames,
-      final TSentryAuthorizable
-      authHierarchy) throws Exception {
-      return tm.executeTransaction(
-              pm -> {
-                Query query = pm.newQuery(MSentryPrivilege.class);
-                QueryParamBuilder paramBuilder = newQueryParamBuilder();
-                if (entityNames == null || entityNames.isEmpty()) {
-                  if (entityType == SentryEntityType.ROLE) {
-                    paramBuilder.addString("!roles.isEmpty()");
-                  } else if (entityType == SentryEntityType.USER) {
-                    paramBuilder.addString("!users.isEmpty()");
-                  } else {
-                    throw new SentryInvalidInputException("entityType: " + entityType + " is invalid");
-                  }
-                } else {
-                  if (entityType == SentryEntityType.ROLE) {
-                    QueryParamBuilder.addRolesFilter(query, paramBuilder, entityNames)

<TRUNCATED>