All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.kernel.impl.api.state.NodeStateImpl Maven / Gradle / Ivy

Go to download

Neo4j kernel is a lightweight, embedded Java database designed to store data structured as graphs rather than tables. For more information, see http://neo4j.org.

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.kernel.impl.api.state;

import org.eclipse.collections.api.IntIterable;
import org.eclipse.collections.api.iterator.IntIterator;
import org.eclipse.collections.api.iterator.LongIterator;
import org.eclipse.collections.api.set.primitive.MutableIntSet;
import org.eclipse.collections.impl.factory.primitive.IntSets;
import org.eclipse.collections.impl.iterator.ImmutableEmptyLongIterator;

import org.neo4j.graphdb.Direction;
import org.neo4j.kernel.impl.api.state.RelationshipChangesForNode.DiffStrategy;
import org.neo4j.kernel.impl.util.collection.CollectionsFactory;
import org.neo4j.kernel.impl.util.diffsets.MutableLongDiffSets;
import org.neo4j.memory.HeapEstimator;
import org.neo4j.memory.MemoryTracker;
import org.neo4j.storageengine.api.Degrees;
import org.neo4j.storageengine.api.RelationshipDirection;
import org.neo4j.storageengine.api.RelationshipSelection;
import org.neo4j.storageengine.api.RelationshipVisitorWithProperties;
import org.neo4j.storageengine.api.StorageProperty;
import org.neo4j.storageengine.api.txstate.LongDiffSets;
import org.neo4j.storageengine.api.txstate.NodeState;
import org.neo4j.storageengine.api.txstate.RelationshipModifications;
import org.neo4j.storageengine.api.txstate.RelationshipModifications.RelationshipBatch;
import org.neo4j.values.storable.Value;

import static java.util.Collections.emptyList;
import static org.neo4j.kernel.impl.api.state.RelationshipChangesForNode.createRelationshipChangesForNode;
import static org.neo4j.kernel.impl.util.diffsets.TrackableDiffSets.newMutableLongDiffSets;

class NodeStateImpl extends EntityStateImpl implements NodeState
{
    private static final long SHALLOW_SIZE = HeapEstimator.shallowSizeOfInstance( NodeStateImpl.class );

    static final NodeState EMPTY = new NodeState()
    {
        @Override
        public Iterable addedProperties()
        {
            return emptyList();
        }

        @Override
        public Iterable changedProperties()
        {
            return emptyList();
        }

        @Override
        public IntIterable removedProperties()
        {
            return IntSets.immutable.empty();
        }

        @Override
        public Iterable addedAndChangedProperties()
        {
            return emptyList();
        }

        @Override
        public boolean hasPropertyChanges()
        {
            return false;
        }

        @Override
        public LongDiffSets labelDiffSets()
        {
            return LongDiffSets.EMPTY;
        }

        @Override
        public void fillDegrees( RelationshipSelection selection, Degrees.Mutator degree )
        {
            //do nothing
        }

        @Override
        public long getId()
        {
            throw new UnsupportedOperationException( "id not defined" );
        }

        @Override
        public boolean isPropertyChangedOrRemoved( int propertyKey )
        {
            return false;
        }

        @Override
        public Value propertyValue( int propertyKey )
        {
            return null;
        }

        @Override
        public LongIterator getAddedRelationships()
        {
            return ImmutableEmptyLongIterator.INSTANCE;
        }

        @Override
        public LongIterator getAddedRelationships( Direction direction )
        {
            return ImmutableEmptyLongIterator.INSTANCE;
        }

        @Override
        public LongIterator getAddedRelationships( Direction direction, int relType )
        {
            return ImmutableEmptyLongIterator.INSTANCE;
        }

        @Override
        public IntIterable getAddedRelationshipTypes()
        {
            return IntSets.immutable.empty();
        }

        @Override
        public IntIterable getAddedAndRemovedRelationshipTypes()
        {
            return IntSets.immutable.empty();
        }
    };
    private final boolean addedInThisTx;

    private MutableLongDiffSets labelDiffSets;
    private RelationshipChangesForNode relationshipsAdded;
    private RelationshipChangesForNode relationshipsRemoved;
    private boolean deleted;

    static NodeStateImpl createNodeState( long id, boolean addedInThisTx, CollectionsFactory collectionsFactory, MemoryTracker memoryTracker )
    {
        memoryTracker.allocateHeap( SHALLOW_SIZE );
        return new NodeStateImpl( id, addedInThisTx, collectionsFactory, memoryTracker );
    }

    private NodeStateImpl( long id, boolean addedInThisTx, CollectionsFactory collectionsFactory, MemoryTracker memoryTracker )
    {
        super( id, collectionsFactory, memoryTracker );
        this.addedInThisTx = addedInThisTx;
    }

    @Override
    public LongDiffSets labelDiffSets()
    {
        return labelDiffSets == null ? LongDiffSets.EMPTY : labelDiffSets;
    }

    MutableLongDiffSets getOrCreateLabelDiffSets()
    {
        if ( labelDiffSets == null )
        {
            labelDiffSets = newMutableLongDiffSets( collectionsFactory, memoryTracker );
        }
        return labelDiffSets;
    }

    public void addRelationship( long relId, int typeId, RelationshipDirection direction )
    {
        if ( !hasAddedRelationships() )
        {
            relationshipsAdded = createRelationshipChangesForNode( DiffStrategy.ADD, memoryTracker );
        }
        relationshipsAdded.addRelationship( relId, typeId, direction );
    }

    public void removeRelationship( long relId, int typeId, RelationshipDirection direction )
    {
        if ( hasAddedRelationships() )
        {
            if ( relationshipsAdded.removeRelationship( relId, typeId, direction ) )
            {
                // This was a rel that was added in this tx, no need to add it to the remove list, instead we just
                // remove it from added relationships.
                return;
            }
        }
        if ( !hasRemovedRelationships() )
        {
            relationshipsRemoved = createRelationshipChangesForNode( DiffStrategy.REMOVE, memoryTracker );
        }
        relationshipsRemoved.addRelationship( relId, typeId, direction );
    }

    @Override
    public void clear()
    {
        super.clear();
        // Intentionally don't clear the relationships because we need those grouped per node in command creation
        // Even the added relationships we need to know when to add to the removed set in some cases
        if ( labelDiffSets != null )
        {
            labelDiffSets = null;
        }
    }

    private int augmentDegree( RelationshipDirection direction, int typeId )
    {
        int degree = 0;
        if ( hasAddedRelationships() )
        {
            degree = relationshipsAdded.augmentDegree( direction, degree, typeId );
        }
        if ( hasRemovedRelationships() )
        {
            degree = relationshipsRemoved.augmentDegree( direction, degree, typeId );
        }
        return degree;
    }

    @Override
    public void fillDegrees( RelationshipSelection selection, Degrees.Mutator degrees )
    {
        IntIterator txTypes = getAddedAndRemovedRelationshipTypes().intIterator();
        while ( txTypes.hasNext() )
        {
            int type = txTypes.next();
            if ( selection.test( type ) )
            {
                int outgoing = selection.test( RelationshipDirection.OUTGOING )
                               ? augmentDegree( RelationshipDirection.OUTGOING, type )
                               : 0;
                int incoming = selection.test( RelationshipDirection.INCOMING )
                               ? augmentDegree( RelationshipDirection.INCOMING, type )
                               : 0;
                int loop = selection.test( RelationshipDirection.LOOP )
                           ? augmentDegree( RelationshipDirection.LOOP, type )
                           : 0;
                if ( !degrees.add( type, outgoing, incoming, loop ) )
                {
                    return;
                }
            }
        }
    }

    boolean hasAddedRelationships()
    {
        return relationshipsAdded != null && !relationshipsAdded.isEmpty();
    }

    public boolean hasAddedRelationships( int type )
    {
        return relationshipsAdded.hasRelationships( type );
    }

    boolean hasRemovedRelationships()
    {
        return relationshipsRemoved != null && !relationshipsRemoved.isEmpty();
    }

    @Override
    public LongIterator getAddedRelationships()
    {
        return relationshipsAdded != null ? relationshipsAdded.getRelationships() :
               ImmutableEmptyLongIterator.INSTANCE;
    }

    @Override
    public LongIterator getAddedRelationships( Direction direction )
    {
        return relationshipsAdded != null ? relationshipsAdded.getRelationships( direction ) :
               ImmutableEmptyLongIterator.INSTANCE;
    }

    @Override
    public LongIterator getAddedRelationships( Direction direction, int relType )
    {
        return relationshipsAdded != null ? relationshipsAdded.getRelationships( direction, relType ) :
               ImmutableEmptyLongIterator.INSTANCE;
    }

    @Override
    public IntIterable getAddedRelationshipTypes()
    {
        return relationshipsAdded != null ? relationshipsAdded.relationshipTypes() : IntSets.immutable.empty();
    }

    @Override
    public IntIterable getAddedAndRemovedRelationshipTypes()
    {
        if ( relationshipsAdded == null && relationshipsRemoved == null )
        {
            return IntSets.immutable.empty();
        }
        if ( relationshipsAdded != null && relationshipsRemoved != null )
        {
            MutableIntSet types = IntSets.mutable.withAll( relationshipsAdded.relationshipTypes() );
            types.addAll( relationshipsRemoved.relationshipTypes() );
            return types;
        }
        return relationshipsAdded != null ? relationshipsAdded.relationshipTypes() : relationshipsRemoved.relationshipTypes();
    }

    RelationshipBatch additionsAsRelationshipBatch( RelationshipModifications.IdDataDecorator decorator )
    {
        return new RelationshipBatchImpl( relationshipsAdded, decorator );
    }

    RelationshipBatch removalsAsRelationshipBatch( RelationshipModifications.IdDataDecorator decorator )
    {
        return new RelationshipBatchImpl( relationshipsRemoved, decorator );
    }

    void visitAddedIdsSplit( RelationshipModifications.InterruptibleTypeIdsVisitor visitor,
            RelationshipModifications.IdDataDecorator idDataDecorator )
    {
        if ( hasAddedRelationships() )
        {
            relationshipsAdded.visitIdsSplit( visitor, idDataDecorator );
        }
    }

    void visitRemovedIdsSplit( RelationshipModifications.InterruptibleTypeIdsVisitor visitor )
    {
        if ( hasRemovedRelationships() )
        {
            relationshipsRemoved.visitIdsSplit( visitor, RelationshipModifications.noAdditionalDataDecorator() );
        }
    }

    boolean isDeleted()
    {
        return deleted;
    }

    boolean isAddedInThisTx()
    {
        return addedInThisTx;
    }

    void markAsDeleted()
    {
        this.deleted = true;
        clear();
    }

    private static class RelationshipBatchImpl implements RelationshipBatch
    {
        private final RelationshipChangesForNode relationships;
        private final RelationshipModifications.IdDataDecorator decorator;

        RelationshipBatchImpl( RelationshipChangesForNode relationships, RelationshipModifications.IdDataDecorator decorator )
        {
            this.relationships = relationships;
            this.decorator = decorator;
        }

        @Override
        public int size()
        {
            return relationships != null ? relationships.totalCount() : 0;
        }

        @Override
        public boolean isEmpty()
        {
            return relationships == null;
        }

        @Override
        public  void forEach( RelationshipVisitorWithProperties relationship ) throws E
        {
            relationships.visitIds( id -> decorator.accept( id, relationship ) );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy