/** * 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.ambari.server.orm.dao; import java.util.Collection; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.NonUniqueResultException; import javax.persistence.TypedQuery; import org.apache.ambari.server.orm.RequiresSession; import org.apache.ambari.server.orm.entities.HostVersionEntity; import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; import org.apache.ambari.server.state.RepositoryVersionState; import org.apache.ambari.server.state.StackId; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.inject.persist.Transactional; /** * The {@link org.apache.ambari.server.orm.dao.HostVersionDAO} class manages the {@link org.apache.ambari.server.orm.entities.HostVersionEntity} * instances associated with a host. Each host can have multiple stack versions in {@link org.apache.ambari.server.state.RepositoryVersionState#INSTALLED} * which are installed, exactly one stack version that is either {@link org.apache.ambari.server.state.RepositoryVersionState#CURRENT} or * {@link org.apache.ambari.server.state.RepositoryVersionState#UPGRADING}. */ @Singleton public class HostVersionDAO extends CrudDAO<HostVersionEntity, Long> { @Inject Provider<EntityManager> entityManagerProvider; @Inject DaoUtils daoUtils; /** * Constructor. */ public HostVersionDAO() { super(HostVersionEntity.class); } /** * Construct a Host Version. Additionally this will update parent connection relations without * forcing refresh of parent entity * @param entity entity to create */ @Override @Transactional public void create(HostVersionEntity entity) throws IllegalArgumentException{ // check if repository version is not missing, to avoid NPE if (entity.getRepositoryVersion() == null) { throw new IllegalArgumentException("RepositoryVersion argument is not set for the entity"); } super.create(entity); entity.getRepositoryVersion().updateHostVersionEntityRelation(entity); } /** * Retrieve all of the host versions for the given cluster name, stack name, * and stack version. * * @param clusterName * Cluster name * @param stackId * Stack (e.g., HDP-2.2) * @param version * Stack version (e.g., 2.2.0.1-995) * @return Return all of the host versions that match the criteria. */ @RequiresSession public List<HostVersionEntity> findByClusterStackAndVersion( String clusterName, StackId stackId, String version) { final TypedQuery<HostVersionEntity> query = entityManagerProvider.get().createNamedQuery("hostVersionByClusterAndStackAndVersion", HostVersionEntity.class); query.setParameter("clusterName", clusterName); query.setParameter("stackName", stackId.getStackName()); query.setParameter("stackVersion", stackId.getStackVersion()); query.setParameter("version", version); return daoUtils.selectList(query); } /** * Retrieve all of the host versions for the given host name across all clusters. * * @param hostName FQDN of host * @return Return all of the host versions that match the criteria. */ @RequiresSession public List<HostVersionEntity> findByHost(String hostName) { final TypedQuery<HostVersionEntity> query = entityManagerProvider.get() .createNamedQuery("hostVersionByHostname", HostVersionEntity.class); query.setParameter("hostName", hostName); return daoUtils.selectList(query); } /** * Retrieve all of the host versions for the given cluster name and host name. * * @param clusterName Cluster name * @param hostName FQDN of host * @return Return all of the host versions that match the criteria. */ @RequiresSession public List<HostVersionEntity> findByClusterAndHost(String clusterName, String hostName) { final TypedQuery<HostVersionEntity> query = entityManagerProvider.get() .createNamedQuery("hostVersionByClusterAndHostname", HostVersionEntity.class); query.setParameter("clusterName", clusterName); query.setParameter("hostName", hostName); return daoUtils.selectList(query); } /** * Retrieve all of the host versions for the given cluster name, host name, and state. <br/> * Consider using faster method: {@link HostVersionDAO#findByClusterHostAndState(long, long, org.apache.ambari.server.state.RepositoryVersionState)} * @param clusterName Cluster name * @param hostName FQDN of host * @param state repository version state * @return Return all of the host versions that match the criteria. */ @RequiresSession public List<HostVersionEntity> findByClusterHostAndState(String clusterName, String hostName, RepositoryVersionState state) { final TypedQuery<HostVersionEntity> query = entityManagerProvider.get() .createNamedQuery("hostVersionByClusterHostnameAndState", HostVersionEntity.class); query.setParameter("clusterName", clusterName); query.setParameter("hostName", hostName); query.setParameter("state", state); return daoUtils.selectList(query); } /** * Faster version of {@link HostVersionDAO#findByClusterHostAndState(java.lang.String, java.lang.String, org.apache.ambari.server.state.RepositoryVersionState)} * * @param clusterId Cluster ID * @param hostId Host ID * @param state repository version state * @return Return all of the host versions that match the criteria. */ @RequiresSession public List<HostVersionEntity> findByClusterHostAndState(long clusterId, long hostId, RepositoryVersionState state) { TypedQuery<HostVersionEntity> query = entityManagerProvider.get().createNamedQuery("hostVersionByClusterHostIdAndState", HostVersionEntity.class); query.setParameter("clusterId", clusterId); query.setParameter("hostId", hostId); query.setParameter("state", state); return daoUtils.selectList(query); } /** * Retrieve the single host version whose state is {@link org.apache.ambari.server.state.RepositoryVersionState#CURRENT}, of which there should be exactly one at all times * for the given host. * Consider using faster method {@link HostVersionDAO#findByHostAndStateCurrent(long, long)} * * @param clusterName Cluster name * @param hostName Host name * @return Returns the single host version for this host whose state is {@link org.apache.ambari.server.state.RepositoryVersionState#CURRENT}, or {@code null} otherwise. */ @RequiresSession public HostVersionEntity findByHostAndStateCurrent(String clusterName, String hostName) { try { List<?> results = findByClusterHostAndState(clusterName, hostName, RepositoryVersionState.CURRENT); if (results.isEmpty()) { return null; } else { if (results.size() == 1) { return (HostVersionEntity) results.get(0); } } throw new NonUniqueResultException(); } catch (NoResultException ignored) { return null; } } /** * Retrieve the single host version whose state is {@link org.apache.ambari.server.state.RepositoryVersionState#CURRENT}, of which there should be exactly one at all times * for the given host. * Faster version of {@link HostVersionDAO#findByHostAndStateCurrent(java.lang.String, java.lang.String)} * @param clusterId Cluster ID * @param hostId host ID * @return Returns the single host version for this host whose state is {@link org.apache.ambari.server.state.RepositoryVersionState#CURRENT}, or {@code null} otherwise. */ @RequiresSession public HostVersionEntity findByHostAndStateCurrent(long clusterId, long hostId) { try { List<?> results = findByClusterHostAndState(clusterId, hostId, RepositoryVersionState.CURRENT); if (results.isEmpty()) { return null; } else { if (results.size() == 1) { return (HostVersionEntity) results.get(0); } } throw new NonUniqueResultException(); } catch (NoResultException ignored) { return null; } } /** * Retrieve the single host version for the given cluster, stack name, stack * version, and host name. <br/> * This query is slow and not suitable for frequent use. <br/> * Please, use {@link HostVersionDAO#findByClusterStackVersionAndHost(long, org.apache.ambari.server.state.StackId, java.lang.String, long)} <br/> * It is ~50 times faster * * @param clusterName * Cluster name * @param stackId * Stack ID (e.g., HDP-2.2) * @param version * Stack version (e.g., 2.2.0.1-995) * @param hostName * FQDN of host * @return Returns the single host version that matches the criteria. */ @RequiresSession public HostVersionEntity findByClusterStackVersionAndHost(String clusterName, StackId stackId, String version, String hostName) { final TypedQuery<HostVersionEntity> query = entityManagerProvider.get() .createNamedQuery("hostVersionByClusterStackVersionAndHostname", HostVersionEntity.class); query.setParameter("clusterName", clusterName); query.setParameter("stackName", stackId.getStackName()); query.setParameter("stackVersion", stackId.getStackVersion()); query.setParameter("version", version); query.setParameter("hostName", hostName); return daoUtils.selectSingle(query); } /** * Optimized version of {@link HostVersionDAO#findByClusterStackVersionAndHost(java.lang.String, org.apache.ambari.server.state.StackId, java.lang.String, java.lang.String)} * @param clusterId Id of cluster * @param stackId Stack ID (e.g., HDP-2.2) * @param version Stack version (e.g., 2.2.0.1-995) * @param hostId Host Id * @return Returns the single host version that matches the criteria. */ @RequiresSession public HostVersionEntity findByClusterStackVersionAndHost(long clusterId, StackId stackId, String version, long hostId) { TypedQuery<HostVersionEntity> query = entityManagerProvider.get() .createNamedQuery("hostVersionByClusterStackVersionAndHostId", HostVersionEntity.class); query.setParameter("clusterId", clusterId); query.setParameter("stackName", stackId.getStackName()); query.setParameter("stackVersion", stackId.getStackVersion()); query.setParameter("version", version); query.setParameter("hostId", hostId); return daoUtils.selectSingle(query); } @Transactional public void removeByHostName(String hostName) { Collection<HostVersionEntity> hostVersions = this.findByHost(hostName); this.remove(hostVersions); } /** * Updates the host versions existing CURRENT record to the INSTALLED, and the target * becomes CURRENT. This method invokes {@code clear()} on the entity manager to force entities to be refreshed. * @param target the repo version that all hosts to mark as CURRENT * @param current the repo version that all hosts marked as INSTALLED */ @Transactional public void updateVersions(RepositoryVersionEntity target, RepositoryVersionEntity current) { // !!! first update target to be current StringBuilder sb = new StringBuilder("UPDATE HostVersionEntity hve"); sb.append(" SET hve.state = ?1 "); sb.append(" WHERE hve.repositoryVersion = ?2"); EntityManager em = entityManagerProvider.get(); TypedQuery<Long> query = em.createQuery(sb.toString(), Long.class); daoUtils.executeUpdate(query, RepositoryVersionState.CURRENT, target); // !!! then move existing current to installed sb = new StringBuilder("UPDATE HostVersionEntity hve"); sb.append(" SET hve.state = ?1 "); sb.append(" WHERE hve.repositoryVersion = ?2"); sb.append(" AND hve.state = ?3"); query = em.createQuery(sb.toString(), Long.class); daoUtils.executeUpdate(query, RepositoryVersionState.INSTALLED, current, RepositoryVersionState.CURRENT); em.clear(); } }