SENTRY-2441: When MAuthzPathsMapping is deleted all associated MPaths should be deleted automatically.. (Kalyan Kumar Kalvagadda reviewed by Arjun Mishra and Na Li)
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo
index 20ec0de..e3ae24b 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model/package.jdo
@@ -274,7 +274,10 @@
          <column name="CREATE_TIME_MS" jdbc-type="BIGINT"/>
        </field>
        <field name = "paths">
-         <collection element-type="org.apache.sentry.provider.db.service.model.MPath"/>
+         <!-- Setting attribute dependent-element to true enables JDO cascading operations. in this case we need it to
+         cascade delete.
+         -->
+         <collection element-type="org.apache.sentry.provider.db.service.model.MPath" dependent-element="true"/>
            <element>
              <column name="AUTHZ_OBJ_ID"/>
            </element>
diff --git a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
index 33c4061..e2d6c85 100644
--- a/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
+++ b/sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
@@ -430,7 +430,8 @@
    * @param <T> Class type
    * @return count of objects or -1 in case of error
      */
-  private <T> Long getCount(final Class<T> tClass) {
+  @VisibleForTesting
+  <T> Long getCount(final Class<T> tClass) {
     try {
       return tm.executeTransaction(
               pm -> {
@@ -3500,10 +3501,6 @@
 
     MAuthzPathsMapping mAuthzPathsMapping = getMAuthzPathsMappingCore(pm, currentSnapshotID, authzObj);
     if (mAuthzPathsMapping != null) {
-      for (MPath mPath : mAuthzPathsMapping.getPaths()) {
-        mAuthzPathsMapping.removePath(mPath);
-        pm.deletePersistent(mPath);
-      }
       pm.deletePersistent(mAuthzPathsMapping);
     } else {
       LOGGER.error("nonexistent authzObj: {} on current paths snapshot ID #{}",
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
index 66db6ae..ca8c416 100644
--- a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/service/persistent/TestSentryStore.java
@@ -67,6 +67,7 @@
 import org.apache.sentry.provider.db.service.model.MSentryPathChange;
 import org.apache.sentry.provider.db.service.model.MSentryPrivilege;
 import org.apache.sentry.provider.db.service.model.MSentryRole;
+import org.apache.sentry.provider.db.service.model.MPath;
 import org.apache.sentry.api.service.thrift.TSentryActiveRoleSet;
 import org.apache.sentry.api.service.thrift.TSentryAuthorizable;
 import org.apache.sentry.api.service.thrift.TSentryGrantOption;
@@ -2646,6 +2647,7 @@
     assertEquals(1, nodeMap.size());//Tree size
     assertEquals(0, pathImage.size());
     assertEquals(0, sentryStore.getMPaths().size());
+    assertEquals(0, sentryStore.getCount(MPath.class).intValue());
 
     // Query the persisted path change and ensure it equals to the original one
     lastChangeID = sentryStore.getLastProcessedPathChangeID();
@@ -2658,6 +2660,41 @@
   }
 
   @Test
+  public void testDeleteAuthzPathsMapping() throws Exception {
+
+    long notificationID = 0;
+
+    // Persist an empty image so that we can add paths to it.
+    sentryStore.persistFullPathsImage(new HashMap<String, Collection<String>>(), notificationID);
+
+    // Add a mapping to two paths
+    sentryStore.addAuthzPathsMapping("db1.table",
+            Sets.newHashSet("db1/tbl1", "db1/tbl2"), null);
+
+    // Verify the Path count
+    assertEquals(2, sentryStore.getCount(MPath.class).intValue());
+
+    // Add a mapping to three paths
+    sentryStore.addAuthzPathsMapping("db2.table",
+            Sets.newHashSet("db2/tbl1", "db2/tbl2", "db2/tbl3"), null);
+
+
+    // Verify the Path count
+    assertEquals(5, sentryStore.getCount(MPath.class).intValue());
+
+    // deleting the mapping and verifying the MPath count
+    sentryStore.deleteAllAuthzPathsMapping("db1.table", null);
+   // Verify the Path count
+    assertEquals(3, sentryStore.getCount(MPath.class).intValue());
+
+
+    // deleting the mapping and verifying the MPath count
+    sentryStore.deleteAllAuthzPathsMapping("db2.table", null);
+    // Verify the Path count
+    assertEquals(0, sentryStore.getCount(MPath.class).intValue());
+  }
+
+  @Test
   public void testRenameUpdateAuthzPathsMapping() throws Exception {
     Map<String, Collection<String>> authzPaths = new HashMap<>();
     Long lastNotificationId = sentryStore.getLastProcessedNotificationID();