Repository: sentry Updated Branches: refs/heads/sentry-ha-redesign 7770b6ea0 -> 4cfc08be4
SENTRY-1599: Remove fencing suppor (Reviewed by Vamsee Yarlagadda) Project: http://git-wip-us.apache.org/repos/asf/sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/4cfc08be Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/4cfc08be Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/4cfc08be Branch: refs/heads/sentry-ha-redesign Commit: 4cfc08be4c6b30345867ab3210b6a6dd76e190db Parents: 7770b6e Author: Alexander Kolbasov <[email protected]> Authored: Mon Feb 6 15:14:26 2017 -0800 Committer: Alexander Kolbasov <[email protected]> Committed: Mon Feb 6 15:14:26 2017 -0800 ---------------------------------------------------------------------- .../provider/db/service/persistent/Fencer.java | 262 ---------------- .../db/service/persistent/SqlAccessor.java | 309 ------------------- .../db/service/persistent/TestFencer.java | 87 ------ 3 files changed, 658 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/sentry/blob/4cfc08be/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/Fencer.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/Fencer.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/Fencer.java deleted file mode 100644 index 77aaac5..0000000 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/Fencer.java +++ /dev/null @@ -1,262 +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 java.util.List; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Joiner; - -import javax.jdo.JDOException; -import javax.jdo.JDOFatalDataStoreException; -import javax.jdo.PersistenceManager; -import javax.jdo.PersistenceManagerFactory; -import javax.jdo.Query; -import javax.jdo.Transaction; - -import org.apache.sentry.core.common.exception.SentryStandbyException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Fences the SQL database.<p/> - * - * Fencing ensures that any SQL requests that were sent by a previously active - * (but now standby) sentry daemon will not be honored. It also ensures that if - * users start up multiple non-HA sentry daemons, only one can become - * active.<p/> - * - * The fencer uses a special SQL table, the SENTRY_FENCE table. When a sentry - * process becomes active, it renames this table so that the name contains the - * current "incarnation ID." The incarnation ID is a randomly generated 128-bit - * ID, which changes each time the process is restarted. From that point - * forward, the sentry process includes a SELECT query for the SENTRY_FENCE - * table in all update transactions. This ensures that if the SENTRY_FENCE - * table is subsequently renamed again, those update transactions will not - * succeed.<p/> - * - * It is important to distinguish between fencing and leader election. - * ZooKeeper is responsible for leader election and ensures that there is only - * ever one active sentry daemon at any one time. However, sentry exists in an - * asynchronous network where requests from a previously active daemon may be - * arbitrarily delayed before reaching the SQL databse. There is also a delay - * between a process being "de-leadered" by ZooKeeper, and the process itself - * becoming aware of this situation. Java's garbage collection pauses tend to - * expose these kinds of race conditions. The SQL database must be prepared to - * reject these stale updates.<p/> - * - * Given that we need this SQL fencing, why bother with ZooKeeper at all? - * ZooKeeper detects when nodes have stopped responding, and elects a new - * leader. The SQL fencing code cannot do that.<p/> - */ -public class Fencer { - private static final Logger LOGGER = LoggerFactory - .getLogger(Fencer.class); - - /** - * The base name of the sentry fencer table.<p/> - * - * We will append the incarnation ID on to this base name to make the final - * table name. - */ - private final static String SENTRY_FENCE_TABLE_BASE = "SENTRY_FENCE"; - - /** - * The fencer table name, including the incarnation ID. - */ - private final String tableIncarnationName; - - /** - * The SQL accessor that we're using. - */ - private final SqlAccessor sql; - - /** - * Create the Fencer. - * - * @param incarnationId The ID of the current sentry daemon incarnation. - * @param pmf The PersistenceManagerFactory to use. - */ - public Fencer(String incarnationId, PersistenceManagerFactory pmf) { - this.tableIncarnationName = String. - format("%s_%s", SENTRY_FENCE_TABLE_BASE, incarnationId); - this.sql = SqlAccessor.get(pmf); - LOGGER.info("Loaded Fencer for " + sql.getDatabaseName()); - } - - /** - * Finds the name of the fencing table.<p/> - * - * The name of the fencer table will always begin with SENTRY_FENCE, - * but it may have the ID of a previous sentry incarnation tacked on to it. - * - * @return the current name of the update log table, or null if there is none. - * - * @throws JDOFatalDataStoreException If there is more than one sentry - * fencing table. - * JDOException If there was a JDO error. - */ - private String findFencingTable(PersistenceManagerFactory pmf) { - // Perform a SQL query to find the name of the update log table. - PersistenceManager pm = pmf.getPersistenceManager(); - Query query = pm.newQuery(SqlAccessor.JDO_SQL_ESCAPE, - sql.getFindTableByPrefixSql(SENTRY_FENCE_TABLE_BASE)); - Transaction tx = pm.currentTransaction(); - try { - tx.begin(); - List<Object> results = (List<Object>) query.execute(); - if (results.isEmpty()) { - return null; - } else if (results.size() != 1) { - throw new JDOFatalDataStoreException( - "Found more than one table whose name begins with " + - "SENTRY_UPDATE_LOG: " + Joiner.on(",").join(results)); - } - String tableName = (String)results.get(0); - if (!tableName.startsWith(SENTRY_FENCE_TABLE_BASE)) { - throw new JDOFatalDataStoreException( - "The result of our attempt to locate the update log table was " + - "a table name which did not begin with " + - SENTRY_FENCE_TABLE_BASE + ", named " + tableName); - } - LOGGER.info("Found sentry update log table named " + tableName); - tx.commit(); - return tableName; - } finally { - if (tx.isActive()) { - tx.rollback(); - } - query.closeAll(); - } - } - - /** - * Creates the fencing table. - * - * @param pmf The PersistenceManagerFactory to use. - * - * @throws JDOException If there was a JDO error. - */ - private void createFenceTable(PersistenceManagerFactory pmf) { - PersistenceManager pm = pmf.getPersistenceManager(); - Transaction tx = pm.currentTransaction(); - Query query = null; - try { - tx.begin(); - query = pm.newQuery(SqlAccessor.JDO_SQL_ESCAPE, - sql.getCreateTableSql(tableIncarnationName)); - query.execute(); - tx.commit(); - } finally { - if (query != null) { - query.closeAll(); - } - if (tx.isActive()) { - tx.rollback(); - } - pm.close(); - } - } - - /** - * Renames one table to another. - * - * @param pmf The PersistenceManagerFactory to use. - * @param src The table to rename - * @param dst The new name of the table. - * - * @throws JDOException If there was a JDO error. - */ - private void renameTable(PersistenceManagerFactory pmf, String src, - String dst) { - boolean success = false; - PersistenceManager pm = pmf.getPersistenceManager(); - Transaction tx = pm.currentTransaction(); - Query query = null; - try { - tx.begin(); - query = pm.newQuery(SqlAccessor.JDO_SQL_ESCAPE, - sql.getRenameTableSql(src, dst)); - query.execute(); - tx.commit(); - success = true; - } finally { - if (query != null) { - query.closeAll(); - } - if (!success) { - LOGGER.info("Failed to rename table " + src + " to " + dst); - tx.rollback(); - } - pm.close(); - } - } - - /** - * Renames the update log table so that only this incarnation can modify it. - * - * @param pmf The PersistenceManagerFactory to use. - * - * @throws JDOException If there was a JDO error. - */ - public void fence(PersistenceManagerFactory pmf) { - String curTableName = findFencingTable(pmf); - if (curTableName == null) { - createFenceTable(pmf); - LOGGER.info("Created sentry fence table."); - } else if (curTableName.equals(tableIncarnationName)) { - LOGGER.info("Sentry fence table is already named " + - tableIncarnationName); - } else { - renameTable(pmf, curTableName, tableIncarnationName); - LOGGER.info("Renamed sentry fence table " + curTableName + " to " + - tableIncarnationName); - } - } - - /** - * Verify that the fencing table still exists by running a query on it. - */ - public void checkSqlFencing(PersistenceManager pm) - throws SentryStandbyException { - try { - Query query = pm.newQuery(SqlAccessor.JDO_SQL_ESCAPE, - sql.getFetchAllRowsSql(tableIncarnationName)); - query.execute(); - } catch (JDOException e) { - throw new SentryStandbyException("Failed to verify that " + - "the daemon was still active", e); - } - } - - String getTableIncarnationName() { - return tableIncarnationName; - } - - /** - * Rename the update log table so that fencing is no longer active. - * This is only used in unit tests currently. - */ - @VisibleForTesting - public void unfence(PersistenceManagerFactory pmf) { - renameTable(pmf, tableIncarnationName, SENTRY_FENCE_TABLE_BASE); - LOGGER.info("Renamed " + tableIncarnationName + " to " + - SENTRY_FENCE_TABLE_BASE); - } -} http://git-wip-us.apache.org/repos/asf/sentry/blob/4cfc08be/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SqlAccessor.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SqlAccessor.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SqlAccessor.java deleted file mode 100644 index 93fa92c..0000000 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SqlAccessor.java +++ /dev/null @@ -1,309 +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 java.sql.Connection; - -import javax.jdo.PersistenceManager; -import javax.jdo.PersistenceManagerFactory; -import javax.jdo.datastore.JDOConnection; - -/** - * An accessor for a SQL database. - * - * SqlAccessor objects generate raw SQL statements in a variety of dialects. - * We use this to do stuff that the DataNucleus architects didn't anticipate, - * like rename tables or search for tables by a prefix name.<p/> - * - * This class exists only to implement fencing. While it's theoretically - * possible to do other things with it, it is almost always better to use the - * functionality provided by DataNucleus if it is at all possible.<p/> - * - * Note: do NOT pass any untrusted user input into these functions. You must - * NOT create SQL statements from unsanitized user input because they may expose - * you to SQL injection attacks. Use prepared statements if you need to do that - * (yes, it's possible via DataNucleus.)<p/> - */ -abstract class SqlAccessor { - /** - * The string which we can use with PersistenceManager#newQuery to perform raw - * SQL operations. - */ - final static String JDO_SQL_ESCAPE = "javax.jdo.query.SQL"; - - /** - * Get an accessor for the SQL database that we're using. - * - * @return The singleton accessor instance for the SQL database we are using. - * - * @throws RuntimeException If there was an error loading the SqlAccessor. - * This could happen because we don't know the - * type of database that we're using. In theory - * it could also happen because JDO is being run - * against something that is not a SQL databse at - * all. - */ - static SqlAccessor get(PersistenceManagerFactory pmf) { - String productName = getProductNameString(pmf).toLowerCase(); - if (productName.contains("postgresql")) { - return PostgresSqlAccessor.INSTANCE; - } else if (productName.contains("mysql")) { - return MySqlSqlAccessor.INSTANCE; - } else if (productName.contains("oracle")) { - return OracleSqlAccessor.INSTANCE; - } else if (productName.contains("derby")) { - return DerbySqlAccessor.INSTANCE; - } else if (productName.contains("db2")) { - return Db2SqlAccessor.INSTANCE; - } else { - throw new RuntimeException("Unknown database type " + - "'" + productName + "'. Supported database types are " + - "postgres, mysql, oracle, mssql, and derby."); - } - } - - /** - * @return An string describing the type of database that we're using. - */ - static private String getProductNameString(PersistenceManagerFactory pmf) { - PersistenceManager pm = pmf.getPersistenceManager(); - JDOConnection jdoConn = pm.getDataStoreConnection(); - try { - return ((Connection)jdoConn.getNativeConnection()).getMetaData(). - getDatabaseProductName(); - } catch (Throwable t) { - throw new RuntimeException("Error retrieving database product " + - "name", t); - } finally { - // We must release the connection before we call other pm methods. - jdoConn.close(); - } - } - - /** - * Get the name of this database. - * - * @return The name of this databse. - */ - abstract String getDatabaseName(); - - /** - * Get the SQL for finding a table that starts with the given prefix. - * - * @param prefix The prefix of the table to find. - * @return The SQL. - */ - abstract String getFindTableByPrefixSql(String prefix); - - /** - * Get the SQL for creating a table with the given name. - * - * @param name The name of the table to create. - * @return The SQL. - */ - abstract String getCreateTableSql(String name); - - /** - * Get the SQL for renaming a table. - * - * @param src The name of the table to rename. - * @param dst The new name to give to the table. - * @return The SQL. - */ - abstract String getRenameTableSql(String src, String dst); - - /** - * Get the SQL for fetching all rows from the given table. - * - * @param name The table name. - * @return The SQL. - */ - abstract String getFetchAllRowsSql(String name); - - /** - * The postgres database type.<p/> - * - * Postgres is case-senstitive, but will translate all identifiers to - * lowercase unless you quote them. So we quote all identifiers when using - * postgres. - */ - private static class PostgresSqlAccessor extends SqlAccessor { - static final PostgresSqlAccessor INSTANCE = new PostgresSqlAccessor(); - - @Override - String getDatabaseName() { - return "postgres"; - } - - @Override - String getFindTableByPrefixSql(String prefix) { - return "SELECT table_name FROM information_schema.tables " + - "WHERE table_name LIKE '" + prefix + "%'"; - } - - @Override - String getCreateTableSql(String name) { - return "CREATE TABLE \"" + name + "\" (\"VAL\" VARCHAR(512))"; - } - - @Override - String getRenameTableSql(String src, String dst) { - return "ALTER TABLE \"" + src + "\" RENAME TO \"" + dst + "\""; - } - - @Override - String getFetchAllRowsSql(String tableName) { - return "SELECT * FROM \"" + tableName + "\""; - } - } - - /** - * The MySQL database type.<p/> - * - * MySQL can't handle quotes unless specifically configured to accept them. - */ - private static class MySqlSqlAccessor extends SqlAccessor { - static final MySqlSqlAccessor INSTANCE = new MySqlSqlAccessor(); - - @Override - String getDatabaseName() { - return "mysql"; - } - - @Override - String getFindTableByPrefixSql(String prefix) { - return "SELECT table_name FROM information_schema.tables " + - "WHERE table_name LIKE '" + prefix + "%'"; - } - - @Override - String getCreateTableSql(String name) { - return "CREATE TABLE " + name + " (VAL VARCHAR(512))"; - } - - @Override - String getRenameTableSql(String src, String dst) { - return "RENAME TABLE " + src + " TO " + dst; - } - - @Override - String getFetchAllRowsSql(String tableName) { - return "SELECT * FROM " + tableName; - } - } - - /** - * The Oracle database type.<p/> - */ - private static class OracleSqlAccessor extends SqlAccessor { - static final OracleSqlAccessor INSTANCE = new OracleSqlAccessor(); - - @Override - String getDatabaseName() { - return "oracle"; - } - - @Override - String getFindTableByPrefixSql(String prefix) { - return "SELECT table_name FROM all_tables " + - "WHERE table_name LIKE '" + prefix + "%'"; - } - - @Override - String getCreateTableSql(String name) { - return "CREATE TABLE " + name + " (VAL VARCHAR(512))"; - } - - @Override - String getRenameTableSql(String src, String dst) { - return "RENAME " + src + " TO " + dst; - } - - @Override - String getFetchAllRowsSql(String tableName) { - return "SELECT * FROM " + tableName; - } - } - - /** - * The Derby database type.</p> - */ - private static class DerbySqlAccessor extends SqlAccessor { - static final DerbySqlAccessor INSTANCE = new DerbySqlAccessor(); - - @Override - String getFindTableByPrefixSql(String prefix) { - return "SELECT tablename FROM SYS.SYSTABLES " + - "WHERE tablename LIKE '" + prefix + "%'"; - } - - @Override - String getCreateTableSql(String name) { - return "CREATE TABLE " + name + " (VAL VARCHAR(512))"; - } - - @Override - String getRenameTableSql(String src, String dst) { - return "RENAME TABLE " + src + " TO " + dst; - } - - @Override - String getDatabaseName() { - return "derby"; - } - - @Override - String getFetchAllRowsSql(String tableName) { - return "SELECT * FROM " + tableName; - } - } - - /** - * The DB2 database type.</p> - */ - private static class Db2SqlAccessor extends SqlAccessor { - static final Db2SqlAccessor INSTANCE = new Db2SqlAccessor(); - - @Override - String getFindTableByPrefixSql(String prefix) { - return "SELECT tablename FROM SYS.SYSTABLES " + - "WHERE tablename LIKE '" + prefix + "%'"; - } - - @Override - String getCreateTableSql(String name) { - return "CREATE TABLE " + name + " (VAL VARCHAR(512))"; - } - - @Override - String getRenameTableSql(String src, String dst) { - return "RENAME TABLE " + src + " TO " + dst; - } - - @Override - String getDatabaseName() { - return "db2"; - } - - @Override - String getFetchAllRowsSql(String tableName) { - return "SELECT * FROM " + tableName; - } - } -} http://git-wip-us.apache.org/repos/asf/sentry/blob/4cfc08be/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestFencer.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestFencer.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestFencer.java deleted file mode 100644 index 7c080fa..0000000 --- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestFencer.java +++ /dev/null @@ -1,87 +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 java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.util.Properties; - -import org.apache.commons.io.FileUtils; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.io.IOUtils; -import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.io.Files; - -import javax.jdo.JDOHelper; -import javax.jdo.PersistenceManagerFactory; - -public class TestFencer { - private static final Logger LOGGER = LoggerFactory - .getLogger(TestFencer.class); - - private static class DatabaseContext implements Closeable { - private final Configuration conf; - private final File dataDir; - - DatabaseContext() { - this.conf = new Configuration(); - this.dataDir = new File(Files.createTempDir(), "sentry_policy_db"); - this.conf.set(ServerConfig.SENTRY_STORE_JDBC_URL, - "jdbc:derby:;databaseName=" + dataDir.getPath() + ";create=true"); - this.conf.set(ServerConfig.SENTRY_STORE_JDBC_PASS, "dummy"); - } - - @Override - public void close() throws IOException { - FileUtils.deleteQuietly(dataDir); - } - - public Configuration getConf() { - return conf; - } - } - - @Test(timeout = 60000) - public void testInvokingFencer() throws Exception { - DatabaseContext dbCtx = null; - PersistenceManagerFactory pmf = null; - try { - dbCtx = new DatabaseContext(); - Properties prop = SentryStore.getDataNucleusProperties(dbCtx.getConf()); - pmf = JDOHelper.getPersistenceManagerFactory(prop); - Fencer fencer = new Fencer("abc", pmf); - fencer.fence(pmf); - fencer.unfence(pmf); - } finally { - IOUtils.cleanup(null, dbCtx); - if (pmf != null) { - try { - pmf.close(); - } catch (Exception e) { - LOGGER.error("error closing pmf" , e); - } - } - } - } -}
