/** * Deletes the specified entity vertices. Deletes any traits, composite entities, and structs * owned by each entity. Also deletes all the references from/to the entity. * * @param instanceVertices * @throws AtlasException */ public void deleteEntities(List<AtlasVertex> instanceVertices) throws AtlasException { RequestContext requestContext = RequestContext.get(); Set<AtlasVertex> deletionCandidateVertices = new HashSet<>(); for (AtlasVertex instanceVertex : instanceVertices) { String guid = GraphHelper.getIdFromVertex(instanceVertex); Id.EntityState state = GraphHelper.getState(instanceVertex); if (requestContext.getDeletedEntityIds().contains(guid) || state == Id.EntityState.DELETED) { LOG.debug("Skipping deletion of {} as it is already deleted", guid); continue; } // Get GUIDs and vertices for all deletion candidates. Set<VertexInfo> compositeVertices = graphHelper.getCompositeVertices(instanceVertex); // Record all deletion candidate GUIDs in RequestContext // and gather deletion candidate vertices. for (VertexInfo vertexInfo : compositeVertices) { requestContext.recordEntityDelete(vertexInfo.getGuid(), vertexInfo.getTypeName()); deletionCandidateVertices.add(vertexInfo.getVertex()); } } // Delete traits and vertices. for (AtlasVertex deletionCandidateVertex : deletionCandidateVertices) { deleteAllTraits(deletionCandidateVertex); deleteTypeVertex(deletionCandidateVertex, false); } }
/** * Deletes the entity vertex - deletes the traits and all the references * * @param instanceVertex * @throws AtlasException */ public void deleteEntity(Vertex instanceVertex) throws AtlasException { RequestContext requestContext = RequestContext.get(); String guid = GraphHelper.getIdFromVertex(instanceVertex); Id.EntityState state = GraphHelper.getState(instanceVertex); if (requestContext.getDeletedEntityIds().contains(guid) || state == Id.EntityState.DELETED) { LOG.debug("Skipping deleting {} as its already deleted", guid); return; } String typeName = GraphHelper.getTypeName(instanceVertex); requestContext.recordEntityDelete(guid, typeName); deleteAllTraits(instanceVertex); deleteTypeVertex(instanceVertex, false); }
protected void deleteVertex(AtlasVertex instanceVertex, boolean force) throws AtlasException { // Update external references(incoming edges) to this vertex LOG.debug( "Setting the external references to {} to null(removing edges)", string(instanceVertex)); Iterator<AtlasEdge> edges = instanceVertex.getEdges(AtlasEdgeDirection.IN).iterator(); while (edges.hasNext()) { AtlasEdge edge = edges.next(); Id.EntityState edgeState = GraphHelper.getState(edge); if (edgeState == Id.EntityState.ACTIVE) { // Delete only the active edge references AttributeInfo attribute = getAttributeForEdge(edge.getLabel()); // TODO use delete edge instead?? deleteEdgeBetweenVertices(edge.getOutVertex(), edge.getInVertex(), attribute.name); } } _deleteVertex(instanceVertex, force); }
/** * Deletes the edge between outvertex and inVertex. The edge is for attribute attributeName of * outVertex * * @param outVertex * @param inVertex * @param attributeName * @throws AtlasException */ protected void deleteEdgeBetweenVertices(Vertex outVertex, Vertex inVertex, String attributeName) throws AtlasException { LOG.debug( "Removing edge from {} to {} with attribute name {}", string(outVertex), string(inVertex), attributeName); String typeName = GraphHelper.getTypeName(outVertex); String outId = GraphHelper.getIdFromVertex(outVertex); Id.EntityState state = GraphHelper.getState(outVertex); if ((outId != null && RequestContext.get().isDeletedEntity(outId)) || state == Id.EntityState.DELETED) { // If the reference vertex is marked for deletion, skip updating the reference return; } IDataType type = typeSystem.getDataType(IDataType.class, typeName); AttributeInfo attributeInfo = getFieldMapping(type).fields.get(attributeName); String propertyName = GraphHelper.getQualifiedFieldName(type, attributeName); String edgeLabel = EDGE_LABEL_PREFIX + propertyName; Edge edge = null; switch (attributeInfo.dataType().getTypeCategory()) { case CLASS: // If its class attribute, its the only edge between two vertices if (attributeInfo.multiplicity.nullAllowed()) { edge = GraphHelper.getEdgeForLabel(outVertex, edgeLabel); if (shouldUpdateReverseAttribute) { GraphHelper.setProperty(outVertex, propertyName, null); } } else { // Cannot unset a required attribute. throw new NullRequiredAttributeException( "Cannot unset required attribute " + GraphHelper.getQualifiedFieldName(type, attributeName) + " on " + string(outVertex) + " edge = " + edgeLabel); } break; case ARRAY: // If its array attribute, find the right edge between the two vertices and update array // property List<String> elements = outVertex.getProperty(propertyName); if (elements != null) { elements = new ArrayList<>( elements); // Make a copy, else list.remove reflects on titan.getProperty() for (String elementEdgeId : elements) { Edge elementEdge = graphHelper.getEdgeByEdgeId(outVertex, edgeLabel, elementEdgeId); if (elementEdge == null) { continue; } Vertex elementVertex = elementEdge.getVertex(Direction.IN); if (elementVertex.getId().toString().equals(inVertex.getId().toString())) { edge = elementEdge; // TODO element.size includes deleted items as well. should exclude if (!attributeInfo.multiplicity.nullAllowed() && elements.size() <= attributeInfo.multiplicity.lower) { // Deleting this edge would violate the attribute's lower bound. throw new NullRequiredAttributeException( "Cannot remove array element from required attribute " + GraphHelper.getQualifiedFieldName(type, attributeName) + " on " + string(outVertex) + " " + string(elementEdge)); } if (shouldUpdateReverseAttribute) { // if composite attribute, remove the reference as well. else, just remove the edge // for example, when table is deleted, process still references the table // but when column is deleted, table will not reference the deleted column LOG.debug( "Removing edge {} from the array attribute {}", string(elementEdge), attributeName); elements.remove(elementEdge.getId().toString()); GraphHelper.setProperty(outVertex, propertyName, elements); break; } } } } break; case MAP: // If its map attribute, find the right edge between two vertices and update map property List<String> keys = outVertex.getProperty(propertyName); if (keys != null) { keys = new ArrayList<>( keys); // Make a copy, else list.remove reflects on titan.getProperty() for (String key : keys) { String keyPropertyName = GraphHelper.getQualifiedNameForMapKey(propertyName, key); String mapEdgeId = outVertex.getProperty(keyPropertyName); Edge mapEdge = graphHelper.getEdgeByEdgeId(outVertex, keyPropertyName, mapEdgeId); Vertex mapVertex = mapEdge.getVertex(Direction.IN); if (mapVertex.getId().toString().equals(inVertex.getId().toString())) { // TODO keys.size includes deleted items as well. should exclude if (attributeInfo.multiplicity.nullAllowed() || keys.size() > attributeInfo.multiplicity.lower) { edge = mapEdge; } else { // Deleting this entry would violate the attribute's lower bound. throw new NullRequiredAttributeException( "Cannot remove map entry " + keyPropertyName + " from required attribute " + GraphHelper.getQualifiedFieldName(type, attributeName) + " on " + string(outVertex) + " " + string(mapEdge)); } if (shouldUpdateReverseAttribute) { // remove this key LOG.debug( "Removing edge {}, key {} from the map attribute {}", string(mapEdge), key, attributeName); keys.remove(key); GraphHelper.setProperty(outVertex, propertyName, keys); GraphHelper.setProperty(outVertex, keyPropertyName, null); } break; } } } break; case STRUCT: case TRAIT: break; default: throw new IllegalStateException( "There can't be an edge from " + string(outVertex) + " to " + string(inVertex) + " with attribute name " + attributeName + " which is not class/array/map attribute"); } if (edge != null) { deleteEdge(edge, false); RequestContext requestContext = RequestContext.get(); GraphHelper.setProperty( outVertex, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY, requestContext.getRequestTime()); requestContext.recordEntityUpdate(outId); } }