Skip to content

Commit

Permalink
Dynamic configuration of record format specific settings
Browse files Browse the repository at this point in the history
Reconfigure record format specific settings as soon as record format selection performed.
Remove default values for properties that now are format dependent.
Add couple of additional  validation checks.
  • Loading branch information
MishaDemianenko committed Apr 6, 2016
1 parent 9b32835 commit 3d445cf
Show file tree
Hide file tree
Showing 12 changed files with 342 additions and 127 deletions.
Expand Up @@ -39,7 +39,6 @@
import org.neo4j.kernel.impl.store.format.lowlimit.DynamicRecordFormat; import org.neo4j.kernel.impl.store.format.lowlimit.DynamicRecordFormat;
import org.neo4j.logging.Level; import org.neo4j.logging.Level;


import static java.lang.String.valueOf;
import static org.neo4j.graphdb.factory.GraphDatabaseSettings.BoltConnector.EncryptionLevel.OPTIONAL; import static org.neo4j.graphdb.factory.GraphDatabaseSettings.BoltConnector.EncryptionLevel.OPTIONAL;
import static org.neo4j.kernel.configuration.Settings.ANY; import static org.neo4j.kernel.configuration.Settings.ANY;
import static org.neo4j.kernel.configuration.Settings.BOOLEAN; import static org.neo4j.kernel.configuration.Settings.BOOLEAN;
Expand Down Expand Up @@ -70,6 +69,13 @@
*/ */
public abstract class GraphDatabaseSettings public abstract class GraphDatabaseSettings
{ {
/**
* Data block sizes for dynamic array stores.
*/
public static final int DEFAULT_BLOCK_SIZE = 128;
public static final int DEFAULT_LABEL_BLOCK_SIZE = 64;
public static final int MINIMAL_BLOCK_SIZE = 16;

@SuppressWarnings("unused") // accessed by reflection @SuppressWarnings("unused") // accessed by reflection
@Migrator @Migrator
private static final ConfigurationMigrator migrator = new GraphDatabaseConfigurationMigrator(); private static final ConfigurationMigrator migrator = new GraphDatabaseConfigurationMigrator();
Expand Down Expand Up @@ -376,23 +382,23 @@ private static String defaultPageCacheMemory()
"than the configured block size" ) "than the configured block size" )
@Internal @Internal
public static final Setting<Integer> string_block_size = setting("unsupported.dbms.block_size.strings", INTEGER, public static final Setting<Integer> string_block_size = setting("unsupported.dbms.block_size.strings", INTEGER,
valueOf( dynamicRecordDataSizeForAligningWith( 128 ) ), min( dynamicRecordDataSizeForAligningWith( 16 ) ) ); "0", min( 0 ) );


@Description("Specifies the block size for storing arrays. This parameter is only honored when the store is " + @Description("Specifies the block size for storing arrays. This parameter is only honored when the store is " +
"created, otherwise it is ignored. " + "created, otherwise it is ignored. " +
"Also note that each block carries a ~10B of overhead so record size on disk will be slightly larger " + "Also note that each block carries a ~10B of overhead so record size on disk will be slightly larger " +
"than the configured block size" ) "than the configured block size" )
@Internal @Internal
public static final Setting<Integer> array_block_size = setting("unsupported.dbms.block_size.array_properties", INTEGER, public static final Setting<Integer> array_block_size = setting("unsupported.dbms.block_size.array_properties", INTEGER,
valueOf( dynamicRecordDataSizeForAligningWith( 128 ) ), min( dynamicRecordDataSizeForAligningWith( 16 ) ) ); "0", min( 0 ) );


@Description("Specifies the block size for storing labels exceeding in-lined space in node record. " + @Description("Specifies the block size for storing labels exceeding in-lined space in node record. " +
"This parameter is only honored when the store is created, otherwise it is ignored. " + "This parameter is only honored when the store is created, otherwise it is ignored. " +
"Also note that each block carries a ~10B of overhead so record size on disk will be slightly larger " + "Also note that each block carries a ~10B of overhead so record size on disk will be slightly larger " +
"than the configured block size" ) "than the configured block size" )
@Internal @Internal
public static final Setting<Integer> label_block_size = setting("unsupported.dbms.block_size.labels", INTEGER, public static final Setting<Integer> label_block_size = setting("unsupported.dbms.block_size.labels", INTEGER,
valueOf( dynamicRecordDataSizeForAligningWith( 64 ) ), min( dynamicRecordDataSizeForAligningWith( 16 ) ) ); "0", min( 0 ) );


@Description("An identifier that uniquely identifies this graph database instance within this JVM. " + @Description("An identifier that uniquely identifies this graph database instance within this JVM. " +
"Defaults to an auto-generated number depending on how many instance are started in this JVM.") "Defaults to an auto-generated number depending on how many instance are started in this JVM.")
Expand Down
Expand Up @@ -85,6 +85,7 @@
import org.neo4j.kernel.impl.store.MetaDataStore; import org.neo4j.kernel.impl.store.MetaDataStore;
import org.neo4j.kernel.impl.store.StoreId; import org.neo4j.kernel.impl.store.StoreId;
import org.neo4j.kernel.impl.store.UnderlyingStorageException; import org.neo4j.kernel.impl.store.UnderlyingStorageException;
import org.neo4j.kernel.impl.store.format.RecordFormatPropertyConfigurator;
import org.neo4j.kernel.impl.store.format.RecordFormatSelector; import org.neo4j.kernel.impl.store.format.RecordFormatSelector;
import org.neo4j.kernel.impl.store.format.RecordFormats; import org.neo4j.kernel.impl.store.format.RecordFormats;
import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory;
Expand Down Expand Up @@ -364,7 +365,9 @@ public NeoStoreDataSource(
this.tracers = tracers; this.tracers = tracers;
this.procedures = procedures; this.procedures = procedures;
this.ioLimiter = ioLimiter; this.ioLimiter = ioLimiter;

this.formats = RecordFormatSelector.select( config, formats, logService ); this.formats = RecordFormatSelector.select( config, formats, logService );
new RecordFormatPropertyConfigurator( this.formats, this.config ).configure();


readOnly = config.get( Configuration.read_only ); readOnly = config.get( Configuration.read_only );
msgLog = logProvider.getLog( getClass() ); msgLog = logProvider.getLog( getClass() );
Expand Down
Expand Up @@ -65,7 +65,6 @@
public abstract class AbstractDynamicStore extends CommonAbstractStore<DynamicRecord,IntStoreHeader> public abstract class AbstractDynamicStore extends CommonAbstractStore<DynamicRecord,IntStoreHeader>
implements DynamicRecordAllocator implements DynamicRecordAllocator
{ {
public static final byte[] NO_DATA = new byte[0];


public AbstractDynamicStore( public AbstractDynamicStore(
File fileName, File fileName,
Expand Down Expand Up @@ -234,10 +233,10 @@ private static class DynamicStoreHeaderFormat extends IntStoreHeaderFormat
@Override @Override
public void writeHeader( PageCursor cursor ) public void writeHeader( PageCursor cursor )
{ {
if ( defaultValue < 1 || defaultValue > 0xFFFF ) if ( header < 1 || header > 0xFFFF )
{ {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Illegal block size[" + defaultValue + "], limit is 65535" ); "Illegal block size[" + header + "], limit is 65535" );
} }
super.writeHeader( cursor ); super.writeHeader( cursor );
} }
Expand Down
Expand Up @@ -23,11 +23,11 @@


public class IntStoreHeaderFormat implements StoreHeaderFormat<IntStoreHeader> public class IntStoreHeaderFormat implements StoreHeaderFormat<IntStoreHeader>
{ {
protected final int defaultValue; protected final int header;


public IntStoreHeaderFormat( int defaultValue ) public IntStoreHeaderFormat( int header )
{ {
this.defaultValue = defaultValue; this.header = header;
} }


@Override @Override
Expand All @@ -39,7 +39,7 @@ public int numberOfReservedRecords()
@Override @Override
public void writeHeader( PageCursor cursor ) public void writeHeader( PageCursor cursor )
{ {
cursor.putInt( defaultValue ); cursor.putInt( header );
} }


@Override @Override
Expand Down
Expand Up @@ -493,6 +493,10 @@ CommonAbstractStore createDynamicArrayStore( String storeName, IdType idType, Se


CommonAbstractStore createDynamicArrayStore( String storeName, IdType idType, int blockSize ) CommonAbstractStore createDynamicArrayStore( String storeName, IdType idType, int blockSize )
{ {
if ( blockSize <= 0 )
{
throw new IllegalArgumentException( "Block size of dynamic array store should be positive integer." );
}
File storeFile = getStoreFile( storeName ); File storeFile = getStoreFile( storeName );
return initialize( new DynamicArrayStore( storeFile, config, idType, idGeneratorFactory, pageCache, return initialize( new DynamicArrayStore( storeFile, config, idType, idGeneratorFactory, pageCache,
logProvider, blockSize, recordFormats.dynamic(), recordFormats.storeVersion() ) ); logProvider, blockSize, recordFormats.dynamic(), recordFormats.storeVersion() ) );
Expand Down
Expand Up @@ -22,11 +22,10 @@
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;


import org.neo4j.graphdb.config.Setting;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.io.pagecache.PageCache; import org.neo4j.io.pagecache.PageCache;
import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.store.format.RecordFormatPropertyConfigurator;
import org.neo4j.kernel.impl.store.format.RecordFormats; import org.neo4j.kernel.impl.store.format.RecordFormats;
import org.neo4j.kernel.impl.store.id.DefaultIdGeneratorFactory; import org.neo4j.kernel.impl.store.id.DefaultIdGeneratorFactory;
import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory;
Expand Down Expand Up @@ -87,6 +86,8 @@ public StoreFactory( File storeDir, Config config,
this.idGeneratorFactory = idGeneratorFactory; this.idGeneratorFactory = idGeneratorFactory;
this.fileSystemAbstraction = fileSystemAbstraction; this.fileSystemAbstraction = fileSystemAbstraction;
this.recordFormats = recordFormats; this.recordFormats = recordFormats;
new RecordFormatPropertyConfigurator( recordFormats, config ).configure();

setLogProvider( logProvider ); setLogProvider( logProvider );
setStoreDir( storeDir ); setStoreDir( storeDir );
this.pageCache = pageCache; this.pageCache = pageCache;
Expand Down Expand Up @@ -182,10 +183,4 @@ public NeoStores openNeoStores( boolean createStoreIfNotExists, StoreType... sto
return new NeoStores( neoStoreFileName, config, idGeneratorFactory, pageCache, logProvider, return new NeoStores( neoStoreFileName, config, idGeneratorFactory, pageCache, logProvider,
fileSystemAbstraction, recordFormats, createStoreIfNotExists, storeTypes ); fileSystemAbstraction, recordFormats, createStoreIfNotExists, storeTypes );
} }

public abstract static class Configuration
{
public static final Setting<Integer> string_block_size = GraphDatabaseSettings.string_block_size;
public static final Setting<Integer> array_block_size = GraphDatabaseSettings.array_block_size;
}
} }
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2002-2016 "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.store.format;

import java.util.Map;

import org.neo4j.graphdb.config.Setting;
import org.neo4j.helpers.collection.MapUtil;
import org.neo4j.kernel.configuration.Config;

import static org.neo4j.graphdb.factory.GraphDatabaseSettings.DEFAULT_BLOCK_SIZE;
import static org.neo4j.graphdb.factory.GraphDatabaseSettings.DEFAULT_LABEL_BLOCK_SIZE;
import static org.neo4j.graphdb.factory.GraphDatabaseSettings.MINIMAL_BLOCK_SIZE;
import static org.neo4j.graphdb.factory.GraphDatabaseSettings.array_block_size;
import static org.neo4j.graphdb.factory.GraphDatabaseSettings.label_block_size;
import static org.neo4j.graphdb.factory.GraphDatabaseSettings.string_block_size;

/**
* There are couple of configuration options that should be adapted for each particular implementation of record format.
* In case if user already set value of those properties we will keep them, otherwise format specific value will be
* evaluated and configuration will be adapted.
*/
public class RecordFormatPropertyConfigurator
{
private final RecordFormats recordFormats;
private final Config config;

public RecordFormatPropertyConfigurator( RecordFormats recordFormats, Config config )
{
this.recordFormats = recordFormats;
this.config = config;
}

private static void configureIntegerSetting( Config config, Setting<Integer> setting,
int fullBlockSize, int headerSize, Map<String,String> formatConfig )
{
Integer defaultValue = Integer.parseInt( setting.getDefaultValue() );
int propertyValue = config.get( setting );
if ( propertyValue == defaultValue )
{
int updatedBlockSize = fullBlockSize - headerSize;
if ( updatedBlockSize != propertyValue )
{
if ( updatedBlockSize < MINIMAL_BLOCK_SIZE )
{
throw new IllegalArgumentException( "Block size should be bigger then " + MINIMAL_BLOCK_SIZE );
}
addFormatSetting( formatConfig, setting, updatedBlockSize );
}
}
}

private static void addFormatSetting( Map<String,String> configMap, Setting setting, int value )
{
configMap.put( setting.name(), String.valueOf( value ) );
}

public void configure()
{
Map<String,String> formatConfig = MapUtil.stringMap();
int headerSize = recordFormats.dynamic().getRecordHeaderSize();

configureIntegerSetting( config, string_block_size, DEFAULT_BLOCK_SIZE, headerSize, formatConfig );
configureIntegerSetting( config, array_block_size, DEFAULT_BLOCK_SIZE, headerSize, formatConfig );
configureIntegerSetting( config, label_block_size, DEFAULT_LABEL_BLOCK_SIZE, headerSize, formatConfig );
if ( !formatConfig.isEmpty() )
{
config.augment( formatConfig );
}
}
}

This file was deleted.

Expand Up @@ -65,6 +65,7 @@
import org.neo4j.kernel.impl.store.format.lowlimit.DynamicRecordFormat; import org.neo4j.kernel.impl.store.format.lowlimit.DynamicRecordFormat;
import org.neo4j.kernel.impl.store.format.lowlimit.LowLimitV3_0; import org.neo4j.kernel.impl.store.format.lowlimit.LowLimitV3_0;
import org.neo4j.kernel.impl.store.id.DefaultIdGeneratorFactory; import org.neo4j.kernel.impl.store.id.DefaultIdGeneratorFactory;
import org.neo4j.kernel.impl.store.id.IdType;
import org.neo4j.kernel.impl.store.record.PropertyBlock; import org.neo4j.kernel.impl.store.record.PropertyBlock;
import org.neo4j.kernel.impl.store.record.PropertyKeyTokenRecord; import org.neo4j.kernel.impl.store.record.PropertyKeyTokenRecord;
import org.neo4j.kernel.impl.store.record.PropertyRecord; import org.neo4j.kernel.impl.store.record.PropertyRecord;
Expand Down Expand Up @@ -102,15 +103,13 @@ public class NeoStoresTest


private final PageCacheRule pageCacheRule = new PageCacheRule(); private final PageCacheRule pageCacheRule = new PageCacheRule();
private final ExpectedException exception = ExpectedException.none(); private final ExpectedException exception = ExpectedException.none();
private EphemeralFileSystemRule fs = new EphemeralFileSystemRule();
private TargetDirectory.TestDirectory dir = TargetDirectory.testDirForTestWithEphemeralFS( fs.get(), getClass() );
private NeoStoreDataSourceRule dsRule = new NeoStoreDataSourceRule();


@Rule @Rule
public EphemeralFileSystemRule fs = new EphemeralFileSystemRule(); public RuleChain ruleChain = RuleChain.outerRule( exception ).around( pageCacheRule )
@Rule .around( fs ).around( dir ).around( dsRule );
public TargetDirectory.TestDirectory dir = TargetDirectory.testDirForTestWithEphemeralFS( fs.get(), getClass() );
@Rule
public NeoStoreDataSourceRule dsRule = new NeoStoreDataSourceRule();
@Rule
public RuleChain ruleChain = RuleChain.outerRule( exception ).around( pageCacheRule );


private PageCache pageCache; private PageCache pageCache;
private File storeDir; private File storeDir;
Expand Down Expand Up @@ -150,6 +149,22 @@ public void impossibleToGetStoreFromClosedNeoStoresContainer()
neoStores.getMetaDataStore(); neoStores.getMetaDataStore();
} }


@Test
public void notAllowCreateDynamicStoreWithNegativeBlockSize()
{
Config config = new Config( new HashMap<>(), GraphDatabaseSettings.class );
StoreFactory sf = new StoreFactory( storeDir, config, new DefaultIdGeneratorFactory( fs.get() ), pageCache,
fs.get(), LowLimitV3_0.RECORD_FORMATS, NullLogProvider.getInstance() );

exception.expect( IllegalArgumentException.class );
exception.expectMessage( "Block size of dynamic array store should be positive integer." );

try (NeoStores neoStores = sf.openNeoStores( true ))
{
neoStores.createDynamicArrayStore( "someStore", IdType.ARRAY_BLOCK, -2 );
}
}

@Test @Test
public void impossibleToGetNotRequestedStore() public void impossibleToGetNotRequestedStore()
{ {
Expand Down
Expand Up @@ -30,14 +30,13 @@
import org.neo4j.test.docs.DocsIncludeFile; import org.neo4j.test.docs.DocsIncludeFile;


import static java.util.Arrays.asList; import static java.util.Arrays.asList;

import static org.neo4j.graphdb.factory.GraphDatabaseSettings.array_block_size;
import static org.neo4j.graphdb.factory.GraphDatabaseSettings.string_block_size;
import static org.neo4j.kernel.impl.store.StoreFactory.NODE_STORE_NAME; import static org.neo4j.kernel.impl.store.StoreFactory.NODE_STORE_NAME;
import static org.neo4j.kernel.impl.store.StoreFactory.PROPERTY_ARRAYS_STORE_NAME; import static org.neo4j.kernel.impl.store.StoreFactory.PROPERTY_ARRAYS_STORE_NAME;
import static org.neo4j.kernel.impl.store.StoreFactory.PROPERTY_STORE_NAME; import static org.neo4j.kernel.impl.store.StoreFactory.PROPERTY_STORE_NAME;
import static org.neo4j.kernel.impl.store.StoreFactory.PROPERTY_STRINGS_STORE_NAME; import static org.neo4j.kernel.impl.store.StoreFactory.PROPERTY_STRINGS_STORE_NAME;
import static org.neo4j.kernel.impl.store.StoreFactory.RELATIONSHIP_STORE_NAME; import static org.neo4j.kernel.impl.store.StoreFactory.RELATIONSHIP_STORE_NAME;
import static org.neo4j.kernel.impl.store.StoreFactory.Configuration.array_block_size;
import static org.neo4j.kernel.impl.store.StoreFactory.Configuration.string_block_size;


public class RecordSizesDocTest public class RecordSizesDocTest
{ {
Expand Down

0 comments on commit 3d445cf

Please sign in to comment.