/** * Copyright (c) 2002-2012 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.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 Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.neo4j.consistency.store; import java.util.Collection; import org.neo4j.kernel.impl.nioneo.store.AbstractBaseRecord; import org.neo4j.kernel.impl.nioneo.store.AbstractNameRecord; import org.neo4j.kernel.impl.nioneo.store.DynamicRecord; import org.neo4j.kernel.impl.nioneo.store.NeoStore; import org.neo4j.kernel.impl.nioneo.store.NeoStoreRecord; import org.neo4j.kernel.impl.nioneo.store.NodeRecord; import org.neo4j.kernel.impl.nioneo.store.PropertyBlock; import org.neo4j.kernel.impl.nioneo.store.PropertyIndexRecord; import org.neo4j.kernel.impl.nioneo.store.PropertyRecord; import org.neo4j.kernel.impl.nioneo.store.PropertyType; import org.neo4j.kernel.impl.nioneo.store.Record; import org.neo4j.kernel.impl.nioneo.store.RecordStore; import org.neo4j.kernel.impl.nioneo.store.RelationshipRecord; import org.neo4j.kernel.impl.nioneo.store.RelationshipTypeRecord; import org.neo4j.kernel.impl.nioneo.store.StoreAccess; import org.neo4j.kernel.impl.nioneo.xa.CommandRecordVisitor; /** * Not thread safe (since DiffRecordStore is not thread safe), intended for * single threaded use. */ public class DiffStore extends StoreAccess implements CommandRecordVisitor { private NeoStoreRecord masterRecord; public DiffStore( NeoStore store ) { super( store ); } @Override protected <R extends AbstractBaseRecord> RecordStore<R> wrapStore( RecordStore<R> store ) { return new DiffRecordStore<R>( store ); } /** * Overridden to increase visibility to public, it's used from * {@link org.neo4j.backup.log.InconsistencyLoggingTransactionInterceptorProvider}. */ @Override public RecordStore<?>[] allStores() { return super.allStores(); } @Override protected void apply( RecordStore.Processor processor, RecordStore<?> store ) { processor.applyById( store, (DiffRecordStore<?>) store ); } @Override public void visitNode( NodeRecord record ) { getNodeStore().forceUpdateRecord( record ); record = getNodeStore().forceGetRaw( record ); if ( record.inUse() ) { markProperty( record.getNextProp() ); markRelationship( record.getNextRel() ); } } @Override public void visitRelationship( RelationshipRecord record ) { getRelationshipStore().forceUpdateRecord( record ); record = getRelationshipStore().forceGetRaw( record ); if ( record.inUse() ) { getNodeStore().markDirty( record.getFirstNode() ); getNodeStore().markDirty( record.getSecondNode() ); markProperty( record.getNextProp() ); markRelationship( record.getFirstNextRel() ); markRelationship( record.getFirstPrevRel() ); markRelationship( record.getSecondNextRel() ); markRelationship( record.getSecondPrevRel() ); } } private void markRelationship( long rel ) { if ( !Record.NO_NEXT_RELATIONSHIP.is( rel ) ) getRelationshipStore().markDirty( rel ); } private void markProperty( long prop ) { if ( !Record.NO_NEXT_PROPERTY.is( prop ) ) getPropertyStore().markDirty( prop ); } @Override public void visitProperty( PropertyRecord record ) { getPropertyStore().forceUpdateRecord( record ); updateDynamic( record ); record = getPropertyStore().forceGetRaw( record ); updateDynamic( record ); if ( record.inUse() ) { markProperty( record.getNextProp() ); markProperty( record.getPrevProp() ); } } private void updateDynamic( PropertyRecord record ) { for ( PropertyBlock block : record.getPropertyBlocks() ) updateDynamic( block.getValueRecords() ); updateDynamic( record.getDeletedRecords() ); } private void updateDynamic( Collection<DynamicRecord> records ) { for ( DynamicRecord record : records ) { DiffRecordStore<DynamicRecord> store = ( record.getType() == PropertyType.STRING.intValue() ) ? getStringStore() : getArrayStore(); store.forceUpdateRecord( record ); if ( !Record.NO_NEXT_BLOCK.is( record.getNextBlock() ) ) getBlockStore(record.getType()).markDirty( record.getNextBlock() ); } } private DiffRecordStore getBlockStore( int type ) { if ( type == PropertyType.STRING.intValue() ) { return getStringStore(); } else { return getArrayStore(); } } @Override public void visitPropertyIndex( PropertyIndexRecord record ) { visitNameStore( getPropertyIndexStore(), getPropertyKeyStore(), record ); } @Override public void visitRelationshipType( RelationshipTypeRecord record ) { visitNameStore( getRelationshipTypeStore(), getTypeNameStore(), record ); } private <R extends AbstractNameRecord> void visitNameStore( RecordStore<R> store, RecordStore<DynamicRecord> nameStore, R record ) { store.forceUpdateRecord( record ); for ( DynamicRecord key : record.getNameRecords() ) nameStore.forceUpdateRecord( key ); } @Override public void visitNeoStore( NeoStoreRecord record ) { this.masterRecord = record; } @Override public DiffRecordStore<NodeRecord> getNodeStore() { return (DiffRecordStore<NodeRecord>) super.getNodeStore(); } @Override public DiffRecordStore<RelationshipRecord> getRelationshipStore() { return (DiffRecordStore<RelationshipRecord>) super.getRelationshipStore(); } @Override public DiffRecordStore<PropertyRecord> getPropertyStore() { return (DiffRecordStore<PropertyRecord>) super.getPropertyStore(); } @Override public DiffRecordStore<DynamicRecord> getStringStore() { return (DiffRecordStore<DynamicRecord>) super.getStringStore(); } @Override public DiffRecordStore<DynamicRecord> getArrayStore() { return (DiffRecordStore<DynamicRecord>) super.getArrayStore(); } @Override public DiffRecordStore<RelationshipTypeRecord> getRelationshipTypeStore() { return (DiffRecordStore<RelationshipTypeRecord>) super.getRelationshipTypeStore(); } @Override public DiffRecordStore<DynamicRecord> getTypeNameStore() { return (DiffRecordStore<DynamicRecord>) super.getTypeNameStore(); } @Override public DiffRecordStore<PropertyIndexRecord> getPropertyIndexStore() { return (DiffRecordStore<PropertyIndexRecord>) super.getPropertyIndexStore(); } @Override public DiffRecordStore<DynamicRecord> getPropertyKeyStore() { return (DiffRecordStore<DynamicRecord>) super.getPropertyKeyStore(); } public NeoStoreRecord getMasterRecord() { return masterRecord; } }