Skip to content

Commit

Permalink
Make sure id limit is respected
Browse files Browse the repository at this point in the history
This is done by validating id of the record being updated in
CommonAbstractStore#updateRecord(). Same validation logic is used in
IdGenerator to guard against illegal and too high ids.
  • Loading branch information
lutovich committed Mar 21, 2016
1 parent a7f45f5 commit 845edc7
Show file tree
Hide file tree
Showing 30 changed files with 368 additions and 158 deletions.
Expand Up @@ -37,8 +37,8 @@
import org.neo4j.kernel.impl.store.format.RecordFormat; import org.neo4j.kernel.impl.store.format.RecordFormat;
import org.neo4j.kernel.impl.store.id.IdGenerator; import org.neo4j.kernel.impl.store.id.IdGenerator;
import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory;
import org.neo4j.kernel.impl.store.id.IdGeneratorImpl;
import org.neo4j.kernel.impl.store.id.IdType; import org.neo4j.kernel.impl.store.id.IdType;
import org.neo4j.kernel.impl.store.id.validation.IdValidator;
import org.neo4j.kernel.impl.store.record.AbstractBaseRecord; import org.neo4j.kernel.impl.store.record.AbstractBaseRecord;
import org.neo4j.kernel.impl.store.record.Record; import org.neo4j.kernel.impl.store.record.Record;
import org.neo4j.kernel.impl.store.record.RecordLoad; import org.neo4j.kernel.impl.store.record.RecordLoad;
Expand Down Expand Up @@ -120,11 +120,6 @@ public CommonAbstractStore(
this.log = logProvider.getLog( getClass() ); this.log = logProvider.getLog( getClass() );
} }


protected static long longFromIntAndMod( long base, long modifier )
{
return modifier == 0 && base == IdGeneratorImpl.INTEGER_MINUS_ONE ? -1 : base | modifier;
}

void initialise( boolean createIfNotExists ) void initialise( boolean createIfNotExists )
{ {
try try
Expand Down Expand Up @@ -1009,6 +1004,8 @@ public RECORD getRecord( long id, RECORD record, RecordLoad mode )
public void updateRecord( RECORD record ) public void updateRecord( RECORD record )
{ {
long id = record.getId(); long id = record.getId();
IdValidator.assertValidId( id, recordFormat.getMaxId() );

long pageId = pageIdForRecord( id ); long pageId = pageIdForRecord( id );
int offset = offsetForId( id ); int offset = offsetForId( id );
try ( PageCursor cursor = storeFile.io( pageId, PF_SHARED_WRITE_LOCK ) ) try ( PageCursor cursor = storeFile.io( pageId, PF_SHARED_WRITE_LOCK ) )
Expand Down
Expand Up @@ -37,9 +37,9 @@ public abstract class BaseOneByteHeaderRecordFormat<RECORD extends AbstractBaseR
private final int inUseBitMaskForFirstByte; private final int inUseBitMaskForFirstByte;


protected BaseOneByteHeaderRecordFormat( Function<StoreHeader,Integer> recordSize, int recordHeaderSize, protected BaseOneByteHeaderRecordFormat( Function<StoreHeader,Integer> recordSize, int recordHeaderSize,
int inUseBitMaskForFirstByte ) int inUseBitMaskForFirstByte, int idBits )
{ {
super( recordSize, recordHeaderSize ); super( recordSize, recordHeaderSize, idBits );
this.inUseBitMaskForFirstByte = inUseBitMaskForFirstByte; this.inUseBitMaskForFirstByte = inUseBitMaskForFirstByte;
} }


Expand Down
Expand Up @@ -25,8 +25,8 @@
import org.neo4j.io.pagecache.PagedFile; import org.neo4j.io.pagecache.PagedFile;
import org.neo4j.kernel.impl.store.IntStoreHeader; import org.neo4j.kernel.impl.store.IntStoreHeader;
import org.neo4j.kernel.impl.store.StoreHeader; import org.neo4j.kernel.impl.store.StoreHeader;
import org.neo4j.kernel.impl.store.id.IdGeneratorImpl;
import org.neo4j.kernel.impl.store.id.IdSequence; import org.neo4j.kernel.impl.store.id.IdSequence;
import org.neo4j.kernel.impl.store.id.validation.IdValidator;
import org.neo4j.kernel.impl.store.record.AbstractBaseRecord; import org.neo4j.kernel.impl.store.record.AbstractBaseRecord;
import org.neo4j.kernel.impl.store.record.Record; import org.neo4j.kernel.impl.store.record.Record;


Expand All @@ -50,11 +50,13 @@ public static Function<StoreHeader,Integer> fixedRecordSize( int recordSize )


private final Function<StoreHeader,Integer> recordSize; private final Function<StoreHeader,Integer> recordSize;
private final int recordHeaderSize; private final int recordHeaderSize;
private final long maxId;


protected BaseRecordFormat( Function<StoreHeader,Integer> recordSize, int recordHeaderSize ) protected BaseRecordFormat( Function<StoreHeader,Integer> recordSize, int recordHeaderSize, int idBits )
{ {
this.recordSize = recordSize; this.recordSize = recordSize;
this.recordHeaderSize = recordHeaderSize; this.recordHeaderSize = recordHeaderSize;
this.maxId = (1L << idBits) - 1;
} }


@Override @Override
Expand All @@ -77,7 +79,7 @@ public long getNextRecordReference( RECORD record )


public static long longFromIntAndMod( long base, long modifier ) public static long longFromIntAndMod( long base, long modifier )
{ {
return modifier == 0 && base == IdGeneratorImpl.INTEGER_MINUS_ONE ? -1 : base | modifier; return modifier == 0 && IdValidator.isReservedId( base ) ? -1 : base | modifier;
} }


@Override @Override
Expand All @@ -98,8 +100,9 @@ public int hashCode()


} }


protected long getMaxId(int bits) @Override
public final long getMaxId()
{ {
return (1L << bits) - 1; return maxId;
} }
} }
Expand Up @@ -28,7 +28,6 @@
import org.neo4j.kernel.impl.store.record.RecordLoad; import org.neo4j.kernel.impl.store.record.RecordLoad;


import static java.lang.String.format; import static java.lang.String.format;

import static org.neo4j.kernel.impl.store.record.DynamicRecord.NO_DATA; import static org.neo4j.kernel.impl.store.record.DynamicRecord.NO_DATA;


public class DynamicRecordFormat extends BaseOneByteHeaderRecordFormat<DynamicRecord> public class DynamicRecordFormat extends BaseOneByteHeaderRecordFormat<DynamicRecord>
Expand All @@ -38,7 +37,8 @@ public class DynamicRecordFormat extends BaseOneByteHeaderRecordFormat<DynamicRe


public DynamicRecordFormat() public DynamicRecordFormat()
{ {
super( INT_STORE_HEADER_READER, RECORD_HEADER_SIZE, 0x10/*the inUse bit is the lsb in the second nibble*/ ); super( INT_STORE_HEADER_READER, RECORD_HEADER_SIZE, 0x10/*the inUse bit is the lsb in the second nibble*/,
LowLimitFormatSettings.DYNAMIC_RECORD_MAXIMUM_ID_BITS );
} }


@Override @Override
Expand Down Expand Up @@ -142,10 +142,4 @@ public long getNextRecordReference( DynamicRecord record )
{ {
return record.getNextBlock(); return record.getNextBlock();
} }

@Override
public long getMaxId()
{
return getMaxId( LowLimitFormatSettings.DYNAMIC_RECORD_MAXIMUM_ID_BITS );
}
} }
Expand Up @@ -25,18 +25,12 @@ public class LabelTokenRecordFormat extends TokenRecordFormat<LabelTokenRecord>
{ {
public LabelTokenRecordFormat() public LabelTokenRecordFormat()
{ {
super( BASE_RECORD_SIZE ); super( BASE_RECORD_SIZE, LowLimitFormatSettings.LABEL_TOKEN_MAXIMUM_ID_BITS );
} }


@Override @Override
public LabelTokenRecord newRecord() public LabelTokenRecord newRecord()
{ {
return new LabelTokenRecord( -1 ); return new LabelTokenRecord( -1 );
} }

@Override
public long getMaxId()
{
return getMaxId( LowLimitFormatSettings.LABEL_TOKEN_MAXIMUM_ID_BITS );
}
} }
Expand Up @@ -20,6 +20,7 @@
package org.neo4j.kernel.impl.store.format.lowlimit; package org.neo4j.kernel.impl.store.format.lowlimit;


import java.io.IOException; import java.io.IOException;

import org.neo4j.io.pagecache.PageCursor; import org.neo4j.io.pagecache.PageCursor;
import org.neo4j.io.pagecache.PagedFile; import org.neo4j.io.pagecache.PagedFile;
import org.neo4j.kernel.impl.store.MetaDataStore.Position; import org.neo4j.kernel.impl.store.MetaDataStore.Position;
Expand All @@ -32,10 +33,11 @@ public class MetaDataRecordFormat extends BaseOneByteHeaderRecordFormat<MetaData
{ {
public static final int RECORD_SIZE = 9; public static final int RECORD_SIZE = 9;
public static final long FIELD_NOT_PRESENT = -1; public static final long FIELD_NOT_PRESENT = -1;
private static final int ID_BITS = 32;


public MetaDataRecordFormat() public MetaDataRecordFormat()
{ {
super( fixedRecordSize( RECORD_SIZE ), 0, IN_USE_BIT ); super( fixedRecordSize( RECORD_SIZE ), 0, IN_USE_BIT, ID_BITS );
} }


@Override @Override
Expand Down Expand Up @@ -72,10 +74,4 @@ public void write( MetaDataRecord record, PageCursor cursor, int recordSize, Pag
cursor.putByte( Record.IN_USE.byteValue() ); cursor.putByte( Record.IN_USE.byteValue() );
cursor.putLong( record.getValue() ); cursor.putLong( record.getValue() );
} }

@Override
public long getMaxId()
{
return 32;
}
} }
Expand Up @@ -36,7 +36,7 @@ public class NodeRecordFormat extends BaseOneByteHeaderRecordFormat<NodeRecord>


public NodeRecordFormat() public NodeRecordFormat()
{ {
super( fixedRecordSize( RECORD_SIZE ), 0, IN_USE_BIT ); super( fixedRecordSize( RECORD_SIZE ), 0, IN_USE_BIT, LowLimitFormatSettings.NODE_RECORD_MAXIMUM_ID_BITS );
} }


@Override @Override
Expand All @@ -45,12 +45,6 @@ public NodeRecord newRecord()
return new NodeRecord( -1 ); return new NodeRecord( -1 );
} }


@Override
public long getMaxId()
{
return getMaxId( LowLimitFormatSettings.NODE_RECORD_MAXIMUM_ID_BITS );
}

public void read( NodeRecord record, PageCursor cursor, RecordLoad mode, int recordSize, PagedFile storeFile ) public void read( NodeRecord record, PageCursor cursor, RecordLoad mode, int recordSize, PagedFile storeFile )
throws IOException throws IOException
{ {
Expand Down
Expand Up @@ -20,6 +20,7 @@
package org.neo4j.kernel.impl.store.format.lowlimit; package org.neo4j.kernel.impl.store.format.lowlimit;


import java.io.IOException; import java.io.IOException;

import org.neo4j.io.pagecache.PageCursor; import org.neo4j.io.pagecache.PageCursor;
import org.neo4j.io.pagecache.PagedFile; import org.neo4j.io.pagecache.PagedFile;
import org.neo4j.kernel.impl.store.format.BaseOneByteHeaderRecordFormat; import org.neo4j.kernel.impl.store.format.BaseOneByteHeaderRecordFormat;
Expand All @@ -30,7 +31,7 @@ class NodeRecordFormatV2_0 extends BaseOneByteHeaderRecordFormat<NodeRecord>
{ {
NodeRecordFormatV2_0() NodeRecordFormatV2_0()
{ {
super( fixedRecordSize( 14 ), 0, IN_USE_BIT ); super( fixedRecordSize( 14 ), 0, IN_USE_BIT, LowLimitFormatSettings.NODE_RECORD_MAXIMUM_ID_BITS );
} }


@Override @Override
Expand All @@ -39,12 +40,6 @@ public NodeRecord newRecord()
return new NodeRecord( -1 ); return new NodeRecord( -1 );
} }


@Override
public long getMaxId()
{
return LowLimitFormatSettings.NODE_RECORD_MAXIMUM_ID_BITS;
}

public void read( NodeRecord record, PageCursor cursor, RecordLoad mode, int recordSize, PagedFile storeFile ) public void read( NodeRecord record, PageCursor cursor, RecordLoad mode, int recordSize, PagedFile storeFile )
throws IOException throws IOException
{ {
Expand Down
Expand Up @@ -26,7 +26,7 @@ public class PropertyKeyTokenRecordFormat extends TokenRecordFormat<PropertyKeyT
{ {
public PropertyKeyTokenRecordFormat() public PropertyKeyTokenRecordFormat()
{ {
super( BASE_RECORD_SIZE + 4/*prop count field*/ ); super( BASE_RECORD_SIZE + 4/*prop count field*/, LowLimitFormatSettings.PROPERTY_TOKEN_MAXIMUM_ID_BITS );
} }


@Override @Override
Expand All @@ -49,10 +49,4 @@ protected void writeRecordData( PropertyKeyTokenRecord record, PageCursor cursor
cursor.putInt( record.getPropertyCount() ); cursor.putInt( record.getPropertyCount() );
cursor.putInt( record.getNameId() ); cursor.putInt( record.getNameId() );
} }

@Override
public long getMaxId()
{
return getMaxId( LowLimitFormatSettings.PROPERTY_TOKEN_MAXIMUM_ID_BITS );
}
} }
Expand Up @@ -41,7 +41,7 @@ public class PropertyRecordFormat extends BaseRecordFormat<PropertyRecord>


public PropertyRecordFormat() public PropertyRecordFormat()
{ {
super( fixedRecordSize( RECORD_SIZE ), 0 ); super( fixedRecordSize( RECORD_SIZE ), 0, LowLimitFormatSettings.PROPERTY_RECORD_MAXIMUM_ID_BITS );
} }


@Override @Override
Expand Down Expand Up @@ -135,12 +135,6 @@ public long getNextRecordReference( PropertyRecord record )
return record.getNextProp(); return record.getNextProp();
} }


@Override
public long getMaxId()
{
return getMaxId( LowLimitFormatSettings.PROPERTY_RECORD_MAXIMUM_ID_BITS );
}

/** /**
* For property records there's no "inUse" byte and we need to read the whole record to * For property records there's no "inUse" byte and we need to read the whole record to
* see if there are any PropertyBlocks in use in it. * see if there are any PropertyBlocks in use in it.
Expand Down
Expand Up @@ -42,7 +42,8 @@ public class RelationshipGroupRecordFormat extends BaseOneByteHeaderRecordFormat


public RelationshipGroupRecordFormat() public RelationshipGroupRecordFormat()
{ {
super( fixedRecordSize( RECORD_SIZE ), 0, IN_USE_BIT ); super( fixedRecordSize( RECORD_SIZE ), 0, IN_USE_BIT,
LowLimitFormatSettings.RELATIONSHIP_GROUP_MAXIMUM_ID_BITS );
} }


@Override @Override
Expand Down Expand Up @@ -126,10 +127,4 @@ public long getNextRecordReference( RelationshipGroupRecord record )
{ {
return record.getNext(); return record.getNext();
} }

@Override
public long getMaxId()
{
return getMaxId( LowLimitFormatSettings.RELATIONSHIP_GROUP_MAXIMUM_ID_BITS );
}
} }
Expand Up @@ -39,7 +39,7 @@ public class RelationshipRecordFormat extends BaseOneByteHeaderRecordFormat<Rela


public RelationshipRecordFormat() public RelationshipRecordFormat()
{ {
super( fixedRecordSize( RECORD_SIZE ), 0, IN_USE_BIT ); super( fixedRecordSize( RECORD_SIZE ), 0, IN_USE_BIT, LowLimitFormatSettings.RELATIONSHIP_MAXIMUM_ID_BITS );
} }


@Override @Override
Expand All @@ -48,13 +48,6 @@ public RelationshipRecord newRecord()
return new RelationshipRecord( -1 ); return new RelationshipRecord( -1 );
} }


@Override
public long getMaxId()
{
return getMaxId( LowLimitFormatSettings.RELATIONSHIP_MAXIMUM_ID_BITS );
}


public void read( RelationshipRecord record, PageCursor cursor, RecordLoad mode, int recordSize, public void read( RelationshipRecord record, PageCursor cursor, RecordLoad mode, int recordSize,
PagedFile storeFile ) throws IOException PagedFile storeFile ) throws IOException
{ {
Expand Down
Expand Up @@ -20,6 +20,7 @@
package org.neo4j.kernel.impl.store.format.lowlimit; package org.neo4j.kernel.impl.store.format.lowlimit;


import java.io.IOException; import java.io.IOException;

import org.neo4j.io.pagecache.PageCursor; import org.neo4j.io.pagecache.PageCursor;
import org.neo4j.io.pagecache.PagedFile; import org.neo4j.io.pagecache.PagedFile;
import org.neo4j.kernel.impl.store.format.BaseOneByteHeaderRecordFormat; import org.neo4j.kernel.impl.store.format.BaseOneByteHeaderRecordFormat;
Expand All @@ -30,7 +31,7 @@ class RelationshipRecordFormatV2_0 extends BaseOneByteHeaderRecordFormat<Relatio
{ {
RelationshipRecordFormatV2_0() RelationshipRecordFormatV2_0()
{ {
super( fixedRecordSize( 33 ), 0, IN_USE_BIT ); super( fixedRecordSize( 33 ), 0, IN_USE_BIT, LowLimitFormatSettings.RELATIONSHIP_MAXIMUM_ID_BITS );
} }


@Override @Override
Expand Down Expand Up @@ -99,10 +100,4 @@ public void write( RelationshipRecord record, PageCursor cursor, int recordSize,
{ {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

}
@Override
public long getMaxId()
{
return LowLimitFormatSettings.RELATIONSHIP_MAXIMUM_ID_BITS;
}
}
Expand Up @@ -25,18 +25,12 @@ public class RelationshipTypeTokenRecordFormat extends TokenRecordFormat<Relatio
{ {
public RelationshipTypeTokenRecordFormat() public RelationshipTypeTokenRecordFormat()
{ {
super( BASE_RECORD_SIZE ); super( BASE_RECORD_SIZE, LowLimitFormatSettings.RELATIONSHIP_TYPE_TOKEN_MAXIMUM_ID_BITS );
} }


@Override @Override
public RelationshipTypeTokenRecord newRecord() public RelationshipTypeTokenRecord newRecord()
{ {
return new RelationshipTypeTokenRecord( -1 ); return new RelationshipTypeTokenRecord( -1 );
} }

@Override
public long getMaxId()
{
return getMaxId( LowLimitFormatSettings.RELATIONSHIP_TYPE_TOKEN_MAXIMUM_ID_BITS );
}
} }
Expand Up @@ -30,9 +30,9 @@ public abstract class TokenRecordFormat<RECORD extends TokenRecord> extends Base
{ {
protected static final int BASE_RECORD_SIZE = 1/*inUse*/ + 4/*nameId*/; protected static final int BASE_RECORD_SIZE = 1/*inUse*/ + 4/*nameId*/;


protected TokenRecordFormat( int recordSize ) protected TokenRecordFormat( int recordSize, int idBits )
{ {
super( fixedRecordSize( recordSize ), 0, IN_USE_BIT ); super( fixedRecordSize( recordSize ), 0, IN_USE_BIT, idBits );
} }


@Override @Override
Expand Down

0 comments on commit 845edc7

Please sign in to comment.