You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by ak...@apache.org on 2017/06/27 20:43:28 UTC
sentry git commit: SENTRY-1781: Persist new HMS snapshots with a new
generation ID (Sergio Pena, reviewed by Alex Kolbasov)
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 <ak...@cloudera.com>
Authored: Tue Jun 27 13:41:00 2017 -0700
Committer: Alexander Kolbasov <ak...@cloudera.com>
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);