Repository: sentry Updated Branches: refs/heads/sentry-ha-redesign 3105a1bfb -> 627469f31
SENTRY-1781: Persist new HMS snapshots with a new generation ID (Sergio Pena, reviewed by Alex Kolbasov) Project: http://git-wip-us.apache.org/repos/asf/sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/627469f3 Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/627469f3 Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/627469f3 Branch: refs/heads/sentry-ha-redesign Commit: 627469f314444fe52dfce20c07b49acfa1830edf Parents: 3105a1b Author: Alexander Kolbasov <[email protected]> Authored: Tue Jun 27 13:41:00 2017 -0700 Committer: Alexander Kolbasov <[email protected]> Committed: Tue Jun 27 13:41:00 2017 -0700 ---------------------------------------------------------------------- .../db/service/persistent/SentryStore.java | 158 +++++++++++++------ .../db/service/persistent/TestSentryStore.java | 142 +++++++++++++++++ 2 files changed, 249 insertions(+), 51 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/sentry/blob/627469f3/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 index 27999cf..9ad97bc 100644 --- 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 @@ -53,6 +53,7 @@ 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.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; @@ -126,7 +127,7 @@ public class SentryStore { public static final long EMPTY_NOTIFICATION_ID = 0L; // Representation for empty HMS snapshots not found on MAuthzPathsSnapshotId - public static final long EMPTY_AUTHZ_SNAPSHOT_ID = 0L; + public static final long EMPTY_PATHS_SNAPSHOT_ID = 0L; // For counters, representation of the "unknown value" private static final long COUNT_VALUE_UNKNOWN = -1L; @@ -480,6 +481,7 @@ public class SentryStore { pm.newQuery(MAuthzPathsMapping.class).deletePersistentAll(); pm.newQuery(MPath.class).deletePersistentAll(); pm.newQuery(MSentryHmsNotification.class).deletePersistentAll(); + pm.newQuery(MAuthzPathsSnapshotId.class).deletePersistentAll(); return null; } }); @@ -2528,24 +2530,36 @@ public class SentryStore { /** * Retrieves an up-to-date hive paths snapshot from {@code MAuthzPathsMapping} table. - * The snapshot is represented by a hiveObj to paths map. + * The snapshot is represented by a snapshot ID, and a map from hiveObj to paths. * * @return a mapping of hiveObj to < Paths >. */ private Map<String, Set<String>> retrieveFullPathsImageCore(PersistenceManager pm) { - Map<String, Set<String>> retVal = new HashMap<>(); + long currentSnapshotID = getCurrentAuthzPathsSnapshotID(pm); + if (currentSnapshotID <= EMPTY_PATHS_SNAPSHOT_ID) { + return Collections.emptyMap(); + } + Query query = pm.newQuery(MAuthzPathsMapping.class); - Iterable<MAuthzPathsMapping> authzToPathsMappings = - (Iterable<MAuthzPathsMapping>) query.execute(); + query.setFilter("this.authzSnapshotID == currentSnapshotID"); + query.declareParameters("long currentSnapshotID"); + Collection<MAuthzPathsMapping> authzToPathsMappings = + (Collection<MAuthzPathsMapping>) query.execute(currentSnapshotID); + + if (authzToPathsMappings.isEmpty()) { + return Collections.emptyMap(); + } + Map<String, Set<String>> retVal = new HashMap<>(authzToPathsMappings.size()); for (MAuthzPathsMapping authzToPaths : authzToPathsMappings) { retVal.put(authzToPaths.getAuthzObjName(), authzToPaths.getPathStrings()); } + return retVal; } /** - * Persist an up-to-date hive snapshot into Sentry DB in a single transaction. + * Persist an up-to-date HMS snapshot into Sentry DB in a single transaction. * * @param authzPaths Mapping of hiveObj to < Paths < * @throws Exception @@ -2555,8 +2569,13 @@ public class SentryStore { new TransactionBlock() { public Object execute(PersistenceManager pm) throws Exception { pm.setDetachAllOnCommit(false); // No need to detach objects + + long snapshotID = getCurrentAuthzPathsSnapshotID(pm); + long nextSnapshotID = snapshotID + 1; + + pm.makePersistent(new MAuthzPathsSnapshotId(nextSnapshotID)); for (Map.Entry<String, Set<String>> authzPath : authzPaths.entrySet()) { - createAuthzPathsMappingCore(pm, authzPath.getKey(), authzPath.getValue()); + pm.makePersistent(new MAuthzPathsMapping(nextSnapshotID, authzPath.getKey(), authzPath.getValue())); } return null; } @@ -2564,26 +2583,13 @@ public class SentryStore { } /** - * Create an entry for the given authzObj and with a set of paths in - * the authzObj -> [Paths] mapping. + * Gets the last authorization path snapshot ID persisted. * - * @param authzObj an authzObj - * @param paths a set of paths need to be added into the authzObj -> [Paths] mapping - * @throws SentryAlreadyExistsException if this authzObj has already exist - * in the mapping. + * @param pm The PersistenceManager object. + * @return the last persisted snapshot ID. It returns 0 if no rows are found. */ - private void createAuthzPathsMappingCore(PersistenceManager pm, String authzObj, - Set<String> paths) throws SentryAlreadyExistsException { - - MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, authzObj); - - if (mAuthzPathsMapping == null) { - mAuthzPathsMapping = - new MAuthzPathsMapping(EMPTY_AUTHZ_SNAPSHOT_ID, authzObj, paths); - pm.makePersistent(mAuthzPathsMapping); - } else { - throw new SentryAlreadyExistsException("AuthzObj: " + authzObj); - } + private static long getCurrentAuthzPathsSnapshotID(PersistenceManager pm) { + return getMaxPersistedIDCore(pm, MAuthzPathsSnapshotId.class, "authzSnapshotID", EMPTY_PATHS_SNAPSHOT_ID); } /** @@ -2618,9 +2624,14 @@ public class SentryStore { */ private void addAuthzPathsMappingCore(PersistenceManager pm, String authzObj, Collection<String> paths) { - MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, authzObj); + long currentSnapshotID = getCurrentAuthzPathsSnapshotID(pm); + if (currentSnapshotID <= EMPTY_PATHS_SNAPSHOT_ID) { + LOGGER.error("AuthzObj: {} cannot be persisted if an paths snapshot ID does not exist yet."); + } + + MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, currentSnapshotID, authzObj); if (mAuthzPathsMapping == null) { - mAuthzPathsMapping = new MAuthzPathsMapping(EMPTY_AUTHZ_SNAPSHOT_ID, authzObj, paths); + mAuthzPathsMapping = new MAuthzPathsMapping(currentSnapshotID, authzObj, paths); } else { for (String path : paths) { mAuthzPathsMapping.addPath(new MPath(path)); @@ -2659,7 +2670,12 @@ public class SentryStore { */ private void deleteAuthzPathsMappingCore(PersistenceManager pm, String authzObj, Iterable<String> paths) { - MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, authzObj); + long currentSnapshotID = getCurrentAuthzPathsSnapshotID(pm); + if (currentSnapshotID <= EMPTY_PATHS_SNAPSHOT_ID) { + LOGGER.error("No paths snapshot ID is found. Cannot delete authzoObj: {}", authzObj); + } + + MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, currentSnapshotID, authzObj); if (mAuthzPathsMapping != null) { for (String path : paths) { MPath mPath = mAuthzPathsMapping.getPath(path); @@ -2672,7 +2688,8 @@ public class SentryStore { } pm.makePersistent(mAuthzPathsMapping); } else { - LOGGER.error("nonexistent authzObj: {}", authzObj); + LOGGER.error("nonexistent authzObj: {} on current paths snapshot ID #{}", + authzObj, currentSnapshotID); } } @@ -2703,7 +2720,12 @@ public class SentryStore { * @throws SentryNoSuchObjectException if cannot find the existing authzObj */ private void deleteAllAuthzPathsMappingCore(PersistenceManager pm, String authzObj) { - MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, authzObj); + long currentSnapshotID = getCurrentAuthzPathsSnapshotID(pm); + if (currentSnapshotID <= EMPTY_PATHS_SNAPSHOT_ID) { + LOGGER.error("No paths snapshot ID is found. Cannot delete authzoObj: {}", authzObj); + } + + MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, currentSnapshotID, authzObj); if (mAuthzPathsMapping != null) { for (MPath mPath : mAuthzPathsMapping.getPaths()) { mAuthzPathsMapping.removePath(mPath); @@ -2711,7 +2733,8 @@ public class SentryStore { } pm.deletePersistent(mAuthzPathsMapping); } else { - LOGGER.error("nonexistent authzObj: {}", authzObj); + LOGGER.error("nonexistent authzObj: {} on current paths snapshot ID #{}", + authzObj, currentSnapshotID); } } @@ -2752,7 +2775,12 @@ public class SentryStore { */ private void renameAuthzPathsMappingCore(PersistenceManager pm, String oldObj, String newObj, String oldPath, String newPath) { - MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, oldObj); + long currentSnapshotID = getCurrentAuthzPathsSnapshotID(pm); + if (currentSnapshotID <= EMPTY_PATHS_SNAPSHOT_ID) { + LOGGER.error("No paths snapshot ID is found. Cannot rename authzoObj: {}", oldObj); + } + + MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, currentSnapshotID, oldObj); if (mAuthzPathsMapping != null) { MPath mOldPath = mAuthzPathsMapping.getPath(oldPath); if (mOldPath == null) { @@ -2765,7 +2793,8 @@ public class SentryStore { mAuthzPathsMapping.setAuthzObjName(newObj); pm.makePersistent(mAuthzPathsMapping); } else { - LOGGER.error("nonexistent authzObj: {}", oldObj); + LOGGER.error("nonexistent authzObj: {} on current paths snapshot ID #{}", + oldObj, currentSnapshotID); } } @@ -2800,12 +2829,18 @@ public class SentryStore { */ private void renameAuthzObjCore(PersistenceManager pm, String oldObj, String newObj) { - MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, oldObj); + long currentSnapshotID = getCurrentAuthzPathsSnapshotID(pm); + if (currentSnapshotID <= EMPTY_PATHS_SNAPSHOT_ID) { + LOGGER.error("No paths snapshot ID is found. Cannot rename authzoObj: {}", oldObj); + } + + MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, currentSnapshotID, oldObj); if (mAuthzPathsMapping != null) { mAuthzPathsMapping.setAuthzObjName(newObj); pm.makePersistent(mAuthzPathsMapping); } else { - LOGGER.error("nonexistent authzObj: {}", oldObj); + LOGGER.error("nonexistent authzObj: {} on current paths snapshot ID #{}", + oldObj, currentSnapshotID); } } @@ -2862,9 +2897,14 @@ public class SentryStore { private void updateAuthzPathsMappingCore(PersistenceManager pm, String authzObj, String oldPath, String newPath) { - MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, authzObj); + long currentSnapshotID = getCurrentAuthzPathsSnapshotID(pm); + if (currentSnapshotID <= EMPTY_PATHS_SNAPSHOT_ID) { + LOGGER.error("No paths snapshot ID is found. Cannot update authzoObj: {}", authzObj); + } + + MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, currentSnapshotID, authzObj); if (mAuthzPathsMapping == null) { - mAuthzPathsMapping = new MAuthzPathsMapping(EMPTY_AUTHZ_SNAPSHOT_ID, authzObj, Sets.newHashSet(newPath)); + mAuthzPathsMapping = new MAuthzPathsMapping(currentSnapshotID, authzObj, Sets.newHashSet(newPath)); } else { MPath mOldPath = mAuthzPathsMapping.getPath(oldPath); if (mOldPath == null) { @@ -2883,12 +2923,12 @@ public class SentryStore { * Get the MAuthzPathsMapping object from authzObj */ private MAuthzPathsMapping getMAuthzPathsMappingCore(PersistenceManager pm, - String authzObj) { + long authzSnapshotID, String authzObj) { Query query = pm.newQuery(MAuthzPathsMapping.class); - query.setFilter("this.authzObjName == authzObjName"); - query.declareParameters("java.lang.String authzObjName"); + query.setFilter("this.authzSnapshotID == authzSnapshotID && this.authzObjName == authzObjName"); + query.declareParameters("long authzSnapshotID, java.lang.String authzObjName"); query.setUnique(true); - return (MAuthzPathsMapping) query.execute(authzObj); + return (MAuthzPathsMapping) query.execute(authzSnapshotID, authzObj); } /** @@ -2910,12 +2950,34 @@ public class SentryStore { return ((List<MAuthzPathsMapping>) query.execute()).isEmpty(); } + /** + * Generic method used to query the maximum number (or ID) of a column from a specified class. + * + * @param pm The PersistenceManager object. + * @param clazz The class name to query. + * @param columnName The column name to query. + * @return the maximum number persisted on the class. It returns NULL if the class has no rows. + */ + private static long getMaxPersistedIDCore(PersistenceManager pm, Class clazz, String columnName, long defaultValue) { + Query query = pm.newQuery(clazz); + query.setResult(String.format("max(%s)", columnName)); + Long maxValue = (Long) query.execute(); + return (maxValue != null) ? maxValue : defaultValue; + } + @VisibleForTesting List<MPath> getMPaths() throws Exception { return tm.executeTransaction(new TransactionBlock<List<MPath>>() { public List<MPath> execute(PersistenceManager pm) throws Exception { - Query query = pm.newQuery(MPath.class); - return (List<MPath>) query.execute(); + long currentSnapshotID = getCurrentAuthzPathsSnapshotID(pm); + + Query query = pm.newQuery("SQL", + "SELECT p.PATH_NAME FROM AUTHZ_PATH p " + + "JOIN AUTHZ_PATHS_MAPPING a ON a.AUTHZ_OBJ_ID = p.AUTHZ_OBJ_ID " + + "WHERE a.AUTHZ_SNAPSHOT_ID = ?" + ); + query.setResultClass(MPath.class); + return (List<MPath>) query.execute(currentSnapshotID); } }); } @@ -3480,10 +3542,7 @@ public class SentryStore { */ static <T extends MSentryChange> Long getLastProcessedChangeIDCore( PersistenceManager pm, Class<T> changeCls) { - Query query = pm.newQuery(changeCls); - query.setResult("max(changeID)"); - Long changeID = (Long) query.execute(); - return changeID == null ? EMPTY_CHANGE_ID : changeID; + return getMaxPersistedIDCore(pm, changeCls, "changeID", EMPTY_CHANGE_ID); } /** @@ -3498,10 +3557,7 @@ public class SentryStore { */ static Long getLastProcessedNotificationIDCore( PersistenceManager pm) { - Query query = pm.newQuery(MSentryHmsNotification.class); - query.setResult("max(notificationId)"); - Long notificationId = (Long) query.execute(); - return notificationId == null ? EMPTY_NOTIFICATION_ID : notificationId; + return getMaxPersistedIDCore(pm, MSentryHmsNotification.class, "notificationId", EMPTY_NOTIFICATION_ID); } /** http://git-wip-us.apache.org/repos/asf/sentry/blob/627469f3/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java index 29878c5..ac266fe 100644 --- a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java +++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java @@ -2463,6 +2463,9 @@ public class TestSentryStore extends org.junit.Assert { @Test public void testAddDeleteAuthzPathsMapping() throws Exception { + // Persist an empty image so that we can add paths to it. + sentryStore.persistFullPathsImage(new HashMap<String, Set<String>>()); + // Add "db1.table1" authzObj Long lastNotificationId = sentryStore.getLastProcessedNotificationID(); PathsUpdate addUpdate = new PathsUpdate(1, false); @@ -2605,6 +2608,142 @@ public class TestSentryStore extends org.junit.Assert { } @Test + public void testPersistAndReplaceANewPathsImage() throws Exception { + Map<String, Set<String>> authzPaths = new HashMap<>(); + + // First image to persist (this will be replaced later) + authzPaths.put("db1.table1", Sets.newHashSet("/user/hive/warehouse/db2.db/table1.1", + "/user/hive/warehouse/db2.db/table1.2")); + authzPaths.put("db1.table2", Sets.newHashSet("/user/hive/warehouse/db2.db/table2.1", + "/user/hive/warehouse/db2.db/table2.2")); + sentryStore.persistFullPathsImage(authzPaths); + + // Second image to persist (it should replace first image) + authzPaths.clear(); + authzPaths.put("db3.table1", Sets.newHashSet("/another-warehouse/db2.db/table1.1", + "/another-warehouse/db2.db/table1.2")); + authzPaths.put("db3.table2", Sets.newHashSet("/another-warehouse/db2.db/table2.1", + "/another-warehouse/db2.db/table2.2")); + authzPaths.put("db4.table2", Sets.newHashSet("/another-warehouse/db2.db/table2.1", + "/another-warehouse/db2.db/table2.3")); + sentryStore.persistFullPathsImage(authzPaths); + + PathsImage pathsImage = sentryStore.retrieveFullPathsImage(); + Map<String, Set<String>> pathImage = pathsImage.getPathImage(); + assertEquals(3, pathImage.size()); + + for (Map.Entry<String, Set<String>> entry : pathImage.entrySet()) { + assertEquals(2, entry.getValue().size()); + } + + assertEquals(2, pathImage.get("db4.table2").size()); + + assertEquals(Sets.newHashSet("/another-warehouse/db2.db/table1.1", + "/another-warehouse/db2.db/table1.2"), + pathImage.get("db3.table1")); + assertEquals(Sets.newHashSet("/another-warehouse/db2.db/table2.1", + "/another-warehouse/db2.db/table2.2"), + pathImage.get("db3.table2")); + assertEquals(Sets.newHashSet("/another-warehouse/db2.db/table2.1", + "/another-warehouse/db2.db/table2.3"), + pathImage.get("db4.table2")); + + assertEquals(6, sentryStore.getMPaths().size()); + } + + @Test + public void testAddDeleteAfterReplacingANewPathsImage() throws Exception { + // Add some paths first (these should be replaced) + PathsUpdate addUpdate = new PathsUpdate(1, false); + addUpdate.newPathChange("db1.table").addToAddPaths(Arrays.asList("db1", "tbl1")); + addUpdate.newPathChange("db1.table").addToAddPaths(Arrays.asList("db1", "tbl2")); + sentryStore.addAuthzPathsMapping("db1.table", Sets.newHashSet("db1/tbl1", "db1/tbl2"), addUpdate); + + // Persist a new image that contains a new image ID (it replaces previous paths) + Map<String, Set<String>> authzPaths = new HashMap<>(); + authzPaths.put("db2.table3", Sets.newHashSet("/user/hive/warehouse/db2.db/table1.1", + "/user/hive/warehouse/db2.db/table1.2")); + sentryStore.persistFullPathsImage(authzPaths); + + // Add new paths + PathsUpdate newAddUpdate = new PathsUpdate(2, false); + newAddUpdate.newPathChange("db2.table").addToAddPaths(Arrays.asList("db2", "tbl1")); + newAddUpdate.newPathChange("db2.table").addToAddPaths(Arrays.asList("db2", "tbl2")); + sentryStore.addAuthzPathsMapping("db2.table", Sets.newHashSet("db2/tbl1", "db2/tbl2"), newAddUpdate); + PathsImage pathsImage = sentryStore.retrieveFullPathsImage(); + Map<String, Set<String>> pathImage = pathsImage.getPathImage(); + assertEquals(2, pathImage.size()); + assertEquals(2, pathImage.get("db2.table").size()); + assertEquals(4, sentryStore.getMPaths().size()); + + // Delete one path + PathsUpdate delUpdate = new PathsUpdate(3, false); + delUpdate.newPathChange("db2.table").addToDelPaths(Arrays.asList("db2", "tbl1")); + sentryStore.deleteAuthzPathsMapping("db2.table", Sets.newHashSet("db2/tbl1"), delUpdate); + pathsImage = sentryStore.retrieveFullPathsImage(); + pathImage = pathsImage.getPathImage(); + assertEquals(2, pathImage.size()); + assertEquals(1, pathImage.get("db2.table").size()); + assertEquals(3, sentryStore.getMPaths().size()); + + Long lastNotificationId = sentryStore.getLastProcessedNotificationID(); + assertEquals(3, lastNotificationId.longValue()); + } + + @Test + public void testRenameUpdateAfterReplacingANewPathsImage() throws Exception { + Map<String, Set<String>> authzPaths = new HashMap<>(); + + // First image to persist (this will be replaced later) + authzPaths.put("db1.table1", Sets.newHashSet("/user/hive/warehouse/db2.db/table1.1", + "/user/hive/warehouse/db2.db/table1.2")); + authzPaths.put("db1.table2", Sets.newHashSet("/user/hive/warehouse/db2.db/table2.1", + "/user/hive/warehouse/db2.db/table2.2")); + sentryStore.persistFullPathsImage(authzPaths); + + // Second image to persist (it should replace first image) + authzPaths.clear(); + authzPaths.put("db3.table1", Sets.newHashSet("/another-warehouse/db3.db/table1.1", + "/another-warehouse/db3.db/table1.2")); + authzPaths.put("db3.table2", Sets.newHashSet("/another-warehouse/db3.db/table2.1", + "/another-warehouse/db3.db/table2.2")); + sentryStore.persistFullPathsImage(authzPaths); + + // Rename path of 'db1.table1' from 'db1.table1' to 'db1.newTable1' + PathsUpdate renameUpdate = new PathsUpdate(1, false); + renameUpdate.newPathChange("db3.table1") + .addToDelPaths(Arrays.asList("another-warehouse", "db3.db", "table1.1")); + renameUpdate.newPathChange("db1.newTable1") + .addToAddPaths(Arrays.asList("user", "hive", "warehouse", "db1.db", "newTable1")); + sentryStore.renameAuthzPathsMapping("db3.table1", "db1.newTable1", + "/another-warehouse/db3.db/table1.1", "user/hive/warehouse/db1.db/newTable1", renameUpdate); + Map<String, Set<String>> pathsImage = sentryStore.retrieveFullPathsImage().getPathImage(); + assertEquals(2, pathsImage.size()); + assertEquals(4, sentryStore.getMPaths().size()); + assertTrue(pathsImage.containsKey("db1.newTable1")); + assertEquals(Sets.newHashSet("/another-warehouse/db3.db/table1.2", + "user/hive/warehouse/db1.db/newTable1"), + pathsImage.get("db1.newTable1")); + + // Update path of 'db1.newTable2' from 'db1.newTable1' to 'db1.newTable2' + PathsUpdate update = new PathsUpdate(2, false); + update.newPathChange("db1.newTable1") + .addToDelPaths(Arrays.asList("user", "hive", "warehouse", "db1.db", "newTable1")); + update.newPathChange("db1.newTable1") + .addToAddPaths(Arrays.asList("user", "hive", "warehouse", "db1.db", "newTable2")); + sentryStore.updateAuthzPathsMapping("db1.newTable2", + "user/hive/warehouse/db1.db/newTable1", + "user/hive/warehouse/db1.db/newTable2", + update); + pathsImage = sentryStore.retrieveFullPathsImage().getPathImage(); + assertEquals(3, pathsImage.size()); + assertEquals(5, sentryStore.getMPaths().size()); + assertTrue(pathsImage.containsKey("db1.newTable2")); + assertEquals(Sets.newHashSet("user/hive/warehouse/db1.db/newTable2"), + pathsImage.get("db1.newTable2")); + } + + @Test public void testQueryParamBuilder() { QueryParamBuilder paramBuilder; paramBuilder = newQueryParamBuilder(); @@ -3052,6 +3191,9 @@ public class TestSentryStore extends org.junit.Assert { addUpdate.newPathChange("db1.table"). addToAddPaths(Arrays.asList("db1", "tbl2")); + // Persist an empty image so that we can add paths to it. + sentryStore.persistFullPathsImage(new HashMap<String, Set<String>>()); + assertEquals(sentryStore.isAuthzPathsMappingEmpty(), true); sentryStore.addAuthzPathsMapping("db1.table", Sets.newHashSet("db1/tbl1", "db1/tbl2"), addUpdate);
