org.neo4j.kernel.impl.index.schema.PointIndexProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neo4j-kernel Show documentation
Show all versions of neo4j-kernel Show documentation
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.
/*
* 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.index.schema;
import java.nio.file.Path;
import java.util.Map;
import org.neo4j.common.TokenNameLookup;
import org.neo4j.configuration.Config;
import org.neo4j.configuration.GraphDatabaseInternalSettings;
import org.neo4j.gis.spatial.index.curves.SpaceFillingCurveConfiguration;
import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
import org.neo4j.internal.schema.IndexCapability;
import org.neo4j.internal.schema.IndexConfig;
import org.neo4j.internal.schema.IndexDescriptor;
import org.neo4j.internal.schema.IndexOrderCapability;
import org.neo4j.internal.schema.IndexPrototype;
import org.neo4j.internal.schema.IndexProviderDescriptor;
import org.neo4j.internal.schema.IndexQuery;
import org.neo4j.internal.schema.IndexQuery.IndexQueryType;
import org.neo4j.internal.schema.IndexType;
import org.neo4j.internal.schema.IndexValueCapability;
import org.neo4j.io.memory.ByteBufferFactory;
import org.neo4j.kernel.api.index.IndexAccessor;
import org.neo4j.kernel.api.index.IndexDirectoryStructure;
import org.neo4j.kernel.api.index.IndexPopulator;
import org.neo4j.kernel.impl.index.schema.config.ConfiguredSpaceFillingCurveSettingsCache;
import org.neo4j.kernel.impl.index.schema.config.IndexSpecificSpaceFillingCurveSettings;
import org.neo4j.kernel.impl.index.schema.config.SpaceFillingCurveSettings;
import org.neo4j.memory.MemoryTracker;
import org.neo4j.util.Preconditions;
import org.neo4j.values.storable.CoordinateReferenceSystem;
import org.neo4j.values.storable.ValueCategory;
import static org.neo4j.kernel.impl.index.schema.config.SpaceFillingCurveSettingsFactory.getConfiguredSpaceFillingCurveConfiguration;
public class PointIndexProvider extends NativeIndexProvider
{
public static final IndexProviderDescriptor DESCRIPTOR = new IndexProviderDescriptor( "point", "1.0" );
public static final IndexCapability CAPABILITY = new PointIndexCapability();
// Ignore everything except GEOMETRY values
static final IndexUpdateIgnoreStrategy UPDATE_IGNORE_STRATEGY = values -> values[0].valueGroup().category() != ValueCategory.GEOMETRY;
/**
* Cache of all setting for various specific CRS's found in the config at instantiation of this provider.
* The config is read once and all relevant CRS configs cached here.
*/
private final ConfiguredSpaceFillingCurveSettingsCache configuredSettings;
/**
* A space filling curve configuration used when reading spatial index values.
*/
private final SpaceFillingCurveConfiguration configuration;
private final boolean archiveFailedIndex;
private final Config config;
public PointIndexProvider( DatabaseIndexContext databaseIndexContext, IndexDirectoryStructure.Factory directoryStructureFactory,
RecoveryCleanupWorkCollector recoveryCleanupWorkCollector, Config config )
{
super( databaseIndexContext, DESCRIPTOR, directoryStructureFactory, recoveryCleanupWorkCollector );
this.configuredSettings = new ConfiguredSpaceFillingCurveSettingsCache( config );
this.configuration = getConfiguredSpaceFillingCurveConfiguration( config );
this.archiveFailedIndex = config.get( GraphDatabaseInternalSettings.archive_failed_index );
this.config = config;
}
@Override
PointLayout layout( IndexDescriptor descriptor, Path storeFile )
{
IndexConfig indexConfig = descriptor.getIndexConfig();
Map settings = SpatialIndexConfig.extractSpatialConfig( indexConfig );
IndexSpecificSpaceFillingCurveSettings spatialSettings = new IndexSpecificSpaceFillingCurveSettings( settings );
return new PointLayout( spatialSettings );
}
@Override
protected IndexPopulator newIndexPopulator( IndexFiles indexFiles, PointLayout layout, IndexDescriptor descriptor, ByteBufferFactory bufferFactory,
MemoryTracker memoryTracker, TokenNameLookup tokenNameLookup )
{
return new PointBlockBasedIndexPopulator( databaseIndexContext, indexFiles, layout, descriptor, layout.getSpaceFillingCurveSettings(), configuration,
archiveFailedIndex, bufferFactory, config, memoryTracker );
}
@Override
protected IndexAccessor newIndexAccessor( IndexFiles indexFiles, PointLayout layout, IndexDescriptor descriptor, TokenNameLookup tokenNameLookup )
{
return new PointIndexAccessor( databaseIndexContext, indexFiles, layout, recoveryCleanupWorkCollector, descriptor,
layout.getSpaceFillingCurveSettings(), configuration );
}
@Override
public IndexDescriptor completeConfiguration( IndexDescriptor index )
{
IndexConfig indexConfig = index.getIndexConfig();
indexConfig = completeSpatialConfiguration( indexConfig );
index = index.withIndexConfig( indexConfig );
if ( index.getCapability().equals( IndexCapability.NO_CAPABILITY ) )
{
index = index.withIndexCapability( CAPABILITY );
}
return index;
}
private IndexConfig completeSpatialConfiguration( IndexConfig indexConfig )
{
for ( CoordinateReferenceSystem crs : CoordinateReferenceSystem.all() )
{
SpaceFillingCurveSettings spaceFillingCurveSettings = configuredSettings.forCRS( crs );
indexConfig = SpatialIndexConfig.addSpatialConfig( indexConfig, crs, spaceFillingCurveSettings );
}
return indexConfig;
}
@Override
public void validatePrototype( IndexPrototype prototype )
{
IndexType indexType = prototype.getIndexType();
if ( indexType != IndexType.POINT )
{
String providerName = getProviderDescriptor().name();
throw new IllegalArgumentException( "The '" + providerName + "' index provider does not support " + indexType + " indexes: " + prototype );
}
if ( !(prototype.schema().isLabelSchemaDescriptor() || prototype.schema().isRelationshipTypeSchemaDescriptor()) )
{
throw new IllegalArgumentException(
"The " + prototype.schema() + " index schema is not a point index schema, which it is required to be for the '" +
getProviderDescriptor().name() + "' index provider to be able to create an index." );
}
if ( !prototype.getIndexProvider().equals( DESCRIPTOR ) )
{
throw new IllegalArgumentException(
"The '" + getProviderDescriptor().name() + "' index provider does not support " + prototype.getIndexProvider() + " indexes: " + prototype );
}
if ( prototype.isUnique() )
{
throw new IllegalArgumentException(
"The '" + getProviderDescriptor().name() + "' index provider does not support uniqueness indexes: " + prototype );
}
if ( prototype.schema().getPropertyIds().length != 1 )
{
throw new IllegalArgumentException( "The '" + getProviderDescriptor().name()
+ "' index provider does not support composite indexes: " + prototype );
}
IndexConfig indexConfig = prototype.getIndexConfig();
indexConfig = completeSpatialConfiguration( indexConfig );
try
{
SpatialIndexConfig.validateSpatialConfig( indexConfig );
}
catch ( IllegalArgumentException e )
{
throw new IllegalArgumentException( "Invalid spatial index settings.", e );
}
}
@Override
public IndexType getIndexType()
{
return IndexType.POINT;
}
private static class PointIndexCapability implements IndexCapability
{
@Override
public IndexOrderCapability orderCapability( ValueCategory... valueCategories )
{
return IndexOrderCapability.NONE;
}
@Override
public IndexValueCapability valueCapability( ValueCategory... valueCategories )
{
// The point index has values for all the queries it supports.
return IndexValueCapability.YES;
}
@Override
public boolean areValueCategoriesAccepted( ValueCategory... valueCategories )
{
Preconditions.requireNonEmpty( valueCategories );
Preconditions.requireNoNullElements( valueCategories );
return valueCategories.length == 1 && valueCategories[0] == ValueCategory.GEOMETRY;
}
@Override
public boolean isQuerySupported( IndexQueryType queryType, ValueCategory valueCategory )
{
if ( queryType == IndexQueryType.ALL_ENTRIES )
{
return true;
}
if ( !areValueCategoriesAccepted( valueCategory ) )
{
return false;
}
switch ( queryType )
{
case EXACT:
case RANGE:
return true;
default:
return false;
}
}
@Override
public double getCostMultiplier( IndexQueryType... queryTypes )
{
return 1.0;
}
@Override
public boolean supportPartitionedScan( IndexQuery... queries )
{
Preconditions.requireNonEmpty( queries );
Preconditions.requireNoNullElements( queries );
return false;
}
}
}