You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sm...@apache.org on 2015/11/07 15:53:05 UTC

ambari git commit: AMBARI-13741. API call to delete service fails with error: integrity constraint violated - child record found (Sebastian Toader via smohanty)

Repository: ambari
Updated Branches:
  refs/heads/trunk 079293935 -> 66e2eb424


AMBARI-13741. API call to delete service fails with error: integrity constraint violated - child record found (Sebastian Toader via smohanty)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/66e2eb42
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/66e2eb42
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/66e2eb42

Branch: refs/heads/trunk
Commit: 66e2eb424bd8d8e6611f518b66a3dcd44ae9948e
Parents: 0792939
Author: Sumit Mohanty <sm...@hortonworks.com>
Authored: Sat Nov 7 06:51:07 2015 -0800
Committer: Sumit Mohanty <sm...@hortonworks.com>
Committed: Sat Nov 7 06:51:07 2015 -0800

----------------------------------------------------------------------
 .../orm/entities/ClusterServiceEntity.java      |   2 +-
 .../ServiceComponentDesiredStateEntity.java     |   4 +-
 .../server/state/cluster/ClusterImpl.java       |  35 +++++-
 .../svccomphost/ServiceComponentHostImpl.java   |   6 ++
 .../server/state/cluster/ClusterImplTest.java   | 106 ++++++++++++++++++-
 5 files changed, 144 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/66e2eb42/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceEntity.java
index d34e2d5..eade294 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ClusterServiceEntity.java
@@ -52,7 +52,7 @@ public class ClusterServiceEntity {
   @OneToOne(mappedBy = "clusterServiceEntity", cascade = CascadeType.ALL)
   private ServiceDesiredStateEntity serviceDesiredStateEntity;
 
-  @OneToMany(mappedBy = "clusterServiceEntity")
+  @OneToMany(mappedBy = "clusterServiceEntity", cascade = CascadeType.ALL)
   private Collection<ServiceComponentDesiredStateEntity> serviceComponentDesiredStateEntities;
 
   public Long getClusterId() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/66e2eb42/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
index 4195710..c39ecc4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ServiceComponentDesiredStateEntity.java
@@ -66,10 +66,10 @@ public class ServiceComponentDesiredStateEntity {
   @JoinColumns({@javax.persistence.JoinColumn(name = "cluster_id", referencedColumnName = "cluster_id", nullable = false), @JoinColumn(name = "service_name", referencedColumnName = "service_name", nullable = false)})
   private ClusterServiceEntity clusterServiceEntity;
 
-  @OneToMany(mappedBy = "serviceComponentDesiredStateEntity", cascade = CascadeType.PERSIST)
+  @OneToMany(mappedBy = "serviceComponentDesiredStateEntity", cascade = CascadeType.ALL)
   private Collection<HostComponentStateEntity> hostComponentStateEntities;
 
-  @OneToMany(mappedBy = "serviceComponentDesiredStateEntity")
+  @OneToMany(mappedBy = "serviceComponentDesiredStateEntity", cascade = CascadeType.ALL)
   private Collection<HostComponentDesiredStateEntity> hostComponentDesiredStateEntities;
 
   public Long getClusterId() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/66e2eb42/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index 898aa33..c9ffee0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -37,6 +37,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import javax.persistence.RollbackException;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.ConfigGroupNotFoundException;
 import org.apache.ambari.server.DuplicateResourceException;
@@ -1919,9 +1921,8 @@ public class ClusterImpl implements Cluster {
       }
 
       for (Service service : services.values()) {
-        service.delete();
+        deleteService(service);
       }
-
       services.clear();
     } finally {
       clusterGlobalLock.writeLock().unlock();
@@ -1943,13 +1944,41 @@ public class ClusterImpl implements Cluster {
           + ", clusterName=" + getClusterName()
           + ", serviceName=" + service.getName());
       }
-      service.delete();
+      deleteService(service);
       services.remove(serviceName);
+
     } finally {
       clusterGlobalLock.writeLock().unlock();
     }
   }
 
+  /**
+   * Deletes the specified service also removes references to it from {@link this.serviceComponentHosts}
+   * and references to ServiceComponentHost objects that belong to the service from {@link this.serviceComponentHostsByHost}
+   * <p>
+   *   Note: This method must be called only with write lock acquired.
+   * </p>
+   * @param service the service to be deleted
+   * @throws AmbariException
+   * @see   ServiceComponentHost
+   */
+  private void deleteService(Service service) throws AmbariException {
+    final String serviceName = service.getName();
+
+    service.delete();
+
+    serviceComponentHosts.remove(serviceName);
+
+    for (List<ServiceComponentHost> serviceComponents: serviceComponentHostsByHost.values()){
+      Iterables.removeIf(serviceComponents, new Predicate<ServiceComponentHost>() {
+        @Override
+        public boolean apply(ServiceComponentHost serviceComponentHost) {
+          return serviceComponentHost.getServiceName().equals(serviceName);
+        }
+      });
+    }
+  }
+
   @Override
   public boolean canBeRemoved() {
     loadServices();

http://git-wip-us.apache.org/repos/asf/ambari/blob/66e2eb42/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
index c0804ff..7b1c6ca 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/svccomphost/ServiceComponentHostImpl.java
@@ -1373,6 +1373,12 @@ public class ServiceComponentHostImpl implements ServiceComponentHost {
       try {
         if (persisted) {
           removeEntities();
+
+          // host must be re-loaded from db to refresh the cached JPA HostEntity
+          // that references HostComponentDesiredStateEntity
+          // and HostComponentStateEntity JPA entities
+          host.refresh();
+
           persisted = false;
           fireRemovalEvent = true;
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/66e2eb42/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterImplTest.java
index 39431ed..178adc5 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/cluster/ClusterImplTest.java
@@ -18,19 +18,52 @@
 
 package org.apache.ambari.server.state.cluster;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.persist.PersistService;
 import org.apache.ambari.server.controller.AmbariSessionManager;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.StackId;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
-
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import static org.easymock.EasyMock.*;
-import static org.junit.Assert.*;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.verify;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 public class ClusterImplTest {
 
+  private static Injector injector;
+  private static Clusters clusters;
+
+  @BeforeClass
+  public static void setUpClass() throws Exception {
+    Injector injector = Guice.createInjector(new InMemoryDefaultTestModule());
+    injector.getInstance(GuiceJpaInitializer.class);
+    clusters = injector.getInstance(Clusters.class);
+  }
+  
   @Test
   public void testAddSessionAttributes() throws Exception {
     Map<String, Object> attributes = new HashMap<String, Object>();
@@ -156,4 +189,71 @@ public class ClusterImplTest {
 
     verify(sessionManager, cluster);
   }
+
+  @Test
+  public void testDeleteService() throws Exception {
+    // Given
+    String serviceToDelete = "TEZ";
+
+    String clusterName = "TEST_CLUSTER";
+    String hostName1 = "HOST1", hostName2 = "HOST2";
+
+    clusters.addCluster(clusterName, new StackId("HDP-2.1.1"));
+
+    Cluster cluster = clusters.getCluster(clusterName);
+
+    clusters.addHost(hostName1);
+    clusters.addHost(hostName2);
+
+    Host host1 = clusters.getHost(hostName1);
+    host1.setHostAttributes(ImmutableMap.of("os_family", "centos", "os_release_version", "6.0"));
+    host1.persist();
+
+    Host host2 = clusters.getHost(hostName2);
+    host2.setHostAttributes(ImmutableMap.of("os_family", "centos", "os_release_version", "6.0"));
+    host2.persist();
+
+    clusters.mapHostsToCluster(Sets.newHashSet(hostName1, hostName2), clusterName);
+
+    Service hdfs = cluster.addService("HDFS");
+    hdfs.persist();
+
+    ServiceComponent nameNode = hdfs.addServiceComponent("NAMENODE");
+    nameNode.persist();
+    nameNode.addServiceComponentHost(hostName1).persist();
+
+    ServiceComponent dataNode = hdfs.addServiceComponent("DATANODE");
+    dataNode.persist();
+    dataNode.addServiceComponentHost(hostName1).persist();
+    dataNode.addServiceComponentHost(hostName2).persist();
+
+    ServiceComponent hdfsClient = hdfs.addServiceComponent("HDFS_CLIENT");
+    hdfsClient.persist();
+    hdfsClient.addServiceComponentHost(hostName1).persist();
+    hdfsClient.addServiceComponentHost(hostName2).persist();
+
+    Service tez = cluster.addService(serviceToDelete);
+    tez.persist();
+
+    ServiceComponent tezClient = tez.addServiceComponent("TEZ_CLIENT");
+    tezClient.persist();
+    ServiceComponentHost tezClientHost1 =  tezClient.addServiceComponentHost(hostName1);
+    tezClientHost1.persist();
+    ServiceComponentHost tezClientHost2 = tezClient.addServiceComponentHost(hostName2);
+    tezClientHost2.persist();
+
+    // When
+    cluster.deleteService(serviceToDelete);
+
+    // Then
+    assertFalse("Deleted service should be removed from the service collection !", cluster.getServices().containsKey(serviceToDelete));
+
+    assertEquals("All components of the deleted service should be removed from all hosts", 0, cluster.getServiceComponentHosts(serviceToDelete, null).size());
+
+    boolean checkHost1 = !cluster.getServiceComponentHosts(hostName1).contains(tezClientHost1);
+    boolean checkHost2 = !cluster.getServiceComponentHosts(hostName2).contains(tezClientHost2);
+
+    assertTrue("All components of the deleted service should be removed from all hosts", checkHost1 && checkHost2);
+
+  }
 }
\ No newline at end of file