Skip to content

Commit

Permalink
Split store cursor in order to flat them with the tx cursors
Browse files Browse the repository at this point in the history
  • Loading branch information
davidegrohmann committed May 8, 2017
1 parent 77b436b commit 8cf9e50
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 100 deletions.
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2002-2017 "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 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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.api.store;

import java.util.function.IntPredicate;

import org.neo4j.cursor.Cursor;
import org.neo4j.kernel.impl.locking.Lock;
import org.neo4j.kernel.impl.store.RecordCursor;
import org.neo4j.kernel.impl.store.RecordCursors;
import org.neo4j.kernel.impl.store.record.PropertyRecord;
import org.neo4j.kernel.impl.store.record.Record;
import org.neo4j.storageengine.api.PropertyItem;

import static org.neo4j.kernel.impl.store.record.RecordLoad.FORCE;

public abstract class StoreAbstractPropertyCursor implements Cursor<PropertyItem>, PropertyItem
{
protected final StorePropertyPayloadCursor payload;
private final RecordCursor<PropertyRecord> recordCursor;

protected boolean fetched;
private IntPredicate propertyKeyIds;
private Lock lock;

StoreAbstractPropertyCursor( RecordCursors cursors )
{
this.payload = new StorePropertyPayloadCursor( cursors.propertyString(), cursors.propertyArray() );
this.recordCursor = cursors.property();
}

protected final void initialize( IntPredicate propertyKeyIds, long firstPropertyId, Lock lock )
{
this.propertyKeyIds = propertyKeyIds;
this.lock = lock;
recordCursor.placeAt( firstPropertyId, FORCE );
}

@Override
public final boolean next()
{
return fetched = fetchNext();
}

private boolean fetchNext()
{
while ( loop() )
{
// Are there more properties to return for this current record we're at?
if ( payload.next() )
{
return true;
}

// No, OK continue down the chain and hunt for more...
if ( recordCursor.next() )
{
// All good, we can get values off of this record
PropertyRecord propertyRecord = recordCursor.get();
payload.init( propertyKeyIds, propertyRecord.getBlocks(), propertyRecord.getNumberOfBlocks() );
if ( payload.next() )
{
return true;
}
}
else if ( Record.NO_NEXT_PROPERTY.is( recordCursor.get().getNextProp() ) )
{
// No more records in this chain, i.e. no more properties.
return false;
}

// Sort of alright, this record isn't in use, but could just be due to concurrent delete.
// Continue to next record in the chain and try there.
}
return false;
}

protected abstract boolean loop();

@Override
public final PropertyItem get()
{
if ( !fetched )
{
throw new IllegalStateException();
}
return this;
}

@Override
public final int propertyKeyId()
{
return payload.propertyKeyId();
}

@Override
public final Object value()
{
return payload.value();
}

@Override
public final void close()
{
try
{
fetched = false;
payload.close();
propertyKeyIds = null;
doClose();
}
finally
{
lock.release();
lock = null;
}
}

protected abstract void doClose();
}
Expand Up @@ -103,7 +103,7 @@ public final long otherNode( long nodeId )
}

@Override
public void visit( long relId, int type, long startNode, long endNode ) throws RuntimeException
public final void visit( long relId, int type, long startNode, long endNode ) throws RuntimeException
{
relationshipRecord.setId( relId );
relationshipRecord.setType( type );
Expand Down
Expand Up @@ -20,131 +20,40 @@
package org.neo4j.kernel.impl.api.store;

import java.util.function.Consumer;
import java.util.function.IntPredicate;

import org.neo4j.cursor.Cursor;
import org.neo4j.kernel.impl.locking.Lock;
import org.neo4j.kernel.impl.store.RecordCursor;
import org.neo4j.kernel.impl.store.RecordCursors;
import org.neo4j.kernel.impl.store.record.PropertyRecord;
import org.neo4j.kernel.impl.store.record.Record;
import org.neo4j.storageengine.api.PropertyItem;

import static org.neo4j.function.Predicates.ALWAYS_TRUE_INT;
import static org.neo4j.kernel.impl.store.record.RecordLoad.FORCE;

/**
* Cursor for all properties on a node or relationship.
*/
public class StorePropertyCursor implements Cursor<PropertyItem>, PropertyItem
public class StorePropertyCursor extends StoreAbstractPropertyCursor
{
private final Consumer<StorePropertyCursor> instanceCache;
private final StorePropertyPayloadCursor payload;
private final RecordCursor<PropertyRecord> recordCursor;

private boolean fetched;
private Lock lock;
private IntPredicate propertyKeyIds;

public StorePropertyCursor( RecordCursors cursors, Consumer<StorePropertyCursor> instanceCache )
{
super( cursors );
this.instanceCache = instanceCache;
this.payload = new StorePropertyPayloadCursor( cursors.propertyString(), cursors.propertyArray() );
this.recordCursor = cursors.property();
}

public StorePropertyCursor init( long firstPropertyId, Lock lock )
{
return init( ALWAYS_TRUE_INT, firstPropertyId, lock );
}

public StorePropertyCursor init( int propertyKeyId, long firstPropertyId, Lock lock )
{
return init( key -> key == propertyKeyId, firstPropertyId, lock );
}

public StorePropertyCursor init( IntPredicate propertyKeyIds, long firstPropertyId, Lock lock )
{
this.propertyKeyIds = propertyKeyIds;
recordCursor.placeAt( firstPropertyId, FORCE );
this.lock = lock;
initialize( ALWAYS_TRUE_INT, firstPropertyId, lock );
return this;
}

@Override
public boolean next()
protected boolean loop()
{
return fetched = fetchNext();
}

private boolean fetchNext()
{
while ( true )
{
// Are there more properties to return for this current record we're at?
if ( payload.next() )
{
return true;
}

// No, OK continue down the chain and hunt for more...
if ( recordCursor.next() )
{
// All good, we can get values off of this record
PropertyRecord propertyRecord = recordCursor.get();
payload.init( propertyKeyIds, propertyRecord.getBlocks(), propertyRecord.getNumberOfBlocks() );
if ( payload.next() )
{
return true;
}
}
else if ( Record.NO_NEXT_PROPERTY.is( recordCursor.get().getNextProp() ) )
{
// No more records in this chain, i.e. no more properties.
return false;
}

// Sort of alright, this record isn't in use, but could just be due to concurrent delete.
// Continue to next record in the chain and try there.
}
}

@Override
public int propertyKeyId()
{
return payload.propertyKeyId();
}

@Override
public Object value()
{
return payload.value();
}

@Override
public PropertyItem get()
{
if ( !fetched )
{
throw new IllegalStateException();
}
return this;
return true;
}

@Override
public void close()
protected void doClose()
{
try
{
propertyKeyIds = null;
fetched = false;
payload.close();
instanceCache.accept( this );
}
finally
{
lock.release();
lock = null;
}
instanceCache.accept( this );
}
}
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2002-2017 "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 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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.api.store;

import java.util.function.Consumer;

import org.neo4j.kernel.impl.locking.Lock;
import org.neo4j.kernel.impl.store.RecordCursors;

public class StoreSinglePropertyCursor extends StoreAbstractPropertyCursor
{
private final Consumer<StoreSinglePropertyCursor> instanceCache;

StoreSinglePropertyCursor( RecordCursors cursors, Consumer<StoreSinglePropertyCursor> instanceCache )
{
super( cursors );
this.instanceCache = instanceCache;
}

public StoreSinglePropertyCursor init( int propertyKeyId, long firstPropertyId, Lock lock )
{
initialize( key -> key == propertyKeyId, firstPropertyId, lock );
return this;
}

@Override
protected boolean loop()
{
return !fetched;
}

@Override
protected void doClose()
{
instanceCache.accept( this );
}
}
Expand Up @@ -58,6 +58,7 @@ public class StoreStatement implements StorageStatement
private final InstanceCache<StoreIteratorRelationshipCursor> iteratorRelationshipCursor;
private final InstanceCache<StoreNodeRelationshipCursor> nodeRelationshipsCursor;
private final InstanceCache<StorePropertyCursor> propertyCursorCache;
private final InstanceCache<StoreSinglePropertyCursor> singlePropertyCursorCache;
private final NeoStores neoStores;
private final NodeStore nodeStore;
private final RelationshipStore relationshipStore;
Expand Down Expand Up @@ -126,6 +127,14 @@ protected StorePropertyCursor create()
return new StorePropertyCursor( recordCursors, this );
}
};
singlePropertyCursorCache = new InstanceCache<StoreSinglePropertyCursor>()
{
@Override
protected StoreSinglePropertyCursor create()
{
return new StoreSinglePropertyCursor( recordCursors, this );
}
};
}

@Override
Expand Down Expand Up @@ -176,7 +185,7 @@ public Cursor<PropertyItem> acquirePropertyCursor( long propertyId, Lock lock )
@Override
public Cursor<PropertyItem> acquireSinglePropertyCursor( long propertyId, int propertyKeyId, Lock lock )
{
return propertyCursorCache.get().init( propertyKeyId, propertyId, lock );
return singlePropertyCursorCache.get().init( propertyKeyId, propertyId, lock );
}

@Override
Expand Down

0 comments on commit 8cf9e50

Please sign in to comment.