// Copyright 2017 JanusGraph Authors // // Licensed 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.janusgraph.graphdb.relations; import com.carrotsearch.hppc.cursors.LongObjectCursor; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import org.janusgraph.core.schema.ConsistencyModifier; import org.janusgraph.core.PropertyKey; import org.janusgraph.diskstorage.Entry; import org.janusgraph.graphdb.internal.ElementLifeCycle; import org.janusgraph.graphdb.internal.InternalRelation; import org.janusgraph.graphdb.internal.InternalVertex; import org.janusgraph.graphdb.transaction.RelationConstructor; import org.janusgraph.graphdb.types.system.ImplicitKey; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; /** * @author Matthias Broecheler (me@matthiasb.com) */ public class CacheVertexProperty extends AbstractVertexProperty { public CacheVertexProperty(long id, PropertyKey key, InternalVertex start, Object value, Entry data) { super(id, key, start.it(), value); this.data = data; } //############## Similar code as CacheEdge but be careful when copying ############################# private final Entry data; @Override public InternalRelation it() { InternalRelation it = null; InternalVertex startVertex = getVertex(0); if (startVertex.hasAddedRelations() && startVertex.hasRemovedRelations()) { //Test whether this relation has been replaced final long id = super.longId(); it = Iterables.getOnlyElement(startVertex.getAddedRelations(new Predicate<InternalRelation>() { @Override public boolean apply(@Nullable InternalRelation internalRelation) { return (internalRelation instanceof StandardVertexProperty) && ((StandardVertexProperty) internalRelation).getPreviousID() == id; } }), null); } return (it != null) ? it : super.it(); } private void copyProperties(InternalRelation to) { for (LongObjectCursor<Object> entry : getPropertyMap()) { PropertyKey type = tx().getExistingPropertyKey(entry.key); if (!(type instanceof ImplicitKey)) to.setPropertyDirect(type, entry.value); } } private synchronized InternalRelation update() { StandardVertexProperty copy = new StandardVertexProperty(super.longId(), propertyKey(), getVertex(0), value(), ElementLifeCycle.Loaded); copyProperties(copy); copy.remove(); StandardVertexProperty u = (StandardVertexProperty) tx().addProperty(getVertex(0), propertyKey(), value()); if (type.getConsistencyModifier()!= ConsistencyModifier.FORK) u.setId(super.longId()); u.setPreviousID(super.longId()); copyProperties(u); return u; } @Override public long longId() { InternalRelation it = it(); return (it == this) ? super.longId() : it.longId(); } private RelationCache getPropertyMap() { RelationCache map = data.getCache(); if (map == null || !map.hasProperties()) { map = RelationConstructor.readRelationCache(data, tx()); } return map; } @Override public <O> O getValueDirect(PropertyKey key) { return getPropertyMap().get(key.longId()); } @Override public Iterable<PropertyKey> getPropertyKeysDirect() { RelationCache map = getPropertyMap(); List<PropertyKey> types = new ArrayList<>(map.numProperties()); for (LongObjectCursor<Object> entry : map) { types.add(tx().getExistingPropertyKey(entry.key)); } return types; } @Override public void setPropertyDirect(PropertyKey key, Object value) { update().setPropertyDirect(key, value); } @Override public <O> O removePropertyDirect(PropertyKey key) { return update().removePropertyDirect(key); } @Override public byte getLifeCycle() { if ((getVertex(0).hasRemovedRelations() || getVertex(0).isRemoved()) && tx().isRemovedRelation(super.longId())) return ElementLifeCycle.Removed; else return ElementLifeCycle.Loaded; } @Override public void remove() { if (!tx().isRemovedRelation(super.longId()) && !tx().getConfiguration().isReadOnly()) { tx().removeRelation(this); }// else throw InvalidElementException.removedException(this); } }