Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
316 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
205 changes: 205 additions & 0 deletions
205
...nity/kernel/src/main/java/org/neo4j/kernel/impl/store/record/SchemaRuleSerialization.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
/* | ||
* 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.store.record; | ||
|
||
import java.nio.ByteBuffer; | ||
|
||
import org.neo4j.kernel.api.exceptions.schema.MalformedSchemaRuleException; | ||
import org.neo4j.kernel.api.index.SchemaIndexProvider; | ||
import org.neo4j.kernel.api.schema_new.LabelSchemaDescriptor; | ||
import org.neo4j.kernel.api.schema_new.RelationTypeSchemaDescriptor; | ||
import org.neo4j.kernel.api.schema_new.SchemaDescriptor; | ||
import org.neo4j.kernel.api.schema_new.SchemaDescriptorFactory; | ||
import org.neo4j.kernel.api.schema_new.SchemaProcessor; | ||
import org.neo4j.kernel.api.schema_new.index.NewIndexDescriptor; | ||
import org.neo4j.kernel.api.schema_new.index.NewIndexDescriptorFactory; | ||
import org.neo4j.storageengine.api.schema.SchemaRule; | ||
import org.neo4j.string.UTF8; | ||
|
||
import static java.lang.String.format; | ||
import static org.neo4j.string.UTF8.getDecodedStringFrom; | ||
|
||
public class SchemaRuleSerialization | ||
{ | ||
// Schema rule type | ||
private final static byte INDEX_RULE = 1, CONSTRAINT_RULE = 2; | ||
|
||
// Index type | ||
private final static byte GENERAL_INDEX = 51, UNIQUE_INDEX = 52; | ||
|
||
// Schema type | ||
private final static byte SIMPLE_LABEL = 101, SIMPLE_REL_TYPE = 102; | ||
|
||
private SchemaRuleSerialization() | ||
{ | ||
} | ||
|
||
public static SchemaRule deserialize( long id, ByteBuffer source ) throws MalformedSchemaRuleException | ||
{ | ||
byte schemaRuleType = source.get(); | ||
switch ( schemaRuleType ) | ||
{ | ||
case INDEX_RULE: | ||
return readIndexRule( id, source ); | ||
default: | ||
throw new UnsupportedOperationException( format( "Got unknown schema rule type '%d'.", schemaRuleType ) ); | ||
} | ||
} | ||
|
||
private static IndexRule readIndexRule( long id, ByteBuffer source ) throws MalformedSchemaRuleException | ||
{ | ||
SchemaIndexProvider.Descriptor indexProvider = readIndexProviderDescriptor( source ); | ||
byte indexRuleType = source.get(); | ||
switch ( indexRuleType ) | ||
{ | ||
case GENERAL_INDEX: | ||
return IndexRule.indexRule( | ||
id, | ||
NewIndexDescriptorFactory.forSchema( readLabelSchema( source ) ), | ||
indexProvider | ||
); | ||
|
||
case UNIQUE_INDEX: | ||
long owningConstraint = source.getLong(); | ||
return IndexRule.constraintIndexRule( | ||
id, | ||
NewIndexDescriptorFactory.uniqueForSchema( readLabelSchema( source ) ), | ||
indexProvider, | ||
owningConstraint | ||
); | ||
|
||
default: | ||
throw new UnsupportedOperationException( format( "Got unknown index rule type '%d'.", indexRuleType ) ); | ||
} | ||
} | ||
|
||
private static LabelSchemaDescriptor readLabelSchema( ByteBuffer source ) throws MalformedSchemaRuleException | ||
{ | ||
SchemaDescriptor schemaDescriptor = readSchema( source ); | ||
if ( !(schemaDescriptor instanceof LabelSchemaDescriptor) ) | ||
{ | ||
throw new MalformedSchemaRuleException( "IndexRules must have LabelSchemaDescriptors, got " + | ||
""+schemaDescriptor.getClass().getSimpleName() ); | ||
} | ||
return (LabelSchemaDescriptor)schemaDescriptor; | ||
} | ||
|
||
private static SchemaDescriptor readSchema( ByteBuffer source ) | ||
{ | ||
byte schemaDescriptorType = source.get(); | ||
switch ( schemaDescriptorType ) | ||
{ | ||
case SIMPLE_LABEL: | ||
return SchemaDescriptorFactory.forLabel( source.getInt(), readPropertyIds( source ) ); | ||
default: | ||
throw new UnsupportedOperationException( format( "Got unknown schema descriptor type '%d'.", | ||
schemaDescriptorType ) ); | ||
} | ||
} | ||
|
||
private static int[] readPropertyIds( ByteBuffer source ) | ||
{ | ||
short numProperties = source.getShort(); | ||
int[] propertyIds = new int[numProperties]; | ||
for ( int i = 0; i < numProperties; i++ ) | ||
{ | ||
propertyIds[i] = source.getInt(); | ||
} | ||
return propertyIds; | ||
} | ||
|
||
private static SchemaIndexProvider.Descriptor readIndexProviderDescriptor( ByteBuffer source ) | ||
{ | ||
String providerKey = getDecodedStringFrom( source ); | ||
String providerVersion = getDecodedStringFrom( source ); | ||
return new SchemaIndexProvider.Descriptor( providerKey, providerVersion ); | ||
} | ||
|
||
public static void serialize( IndexRule indexRule, ByteBuffer target ) throws MalformedSchemaRuleException | ||
{ | ||
target.put( INDEX_RULE ); | ||
|
||
SchemaIndexProvider.Descriptor providerDescriptor = indexRule.getProviderDescriptor(); | ||
UTF8.putEncodedStringInto( providerDescriptor.getKey(), target ); | ||
UTF8.putEncodedStringInto( providerDescriptor.getVersion(), target ); | ||
|
||
NewIndexDescriptor indexDescriptor = indexRule.getIndexDescriptor(); | ||
switch ( indexDescriptor.type() ) | ||
{ | ||
case GENERAL: | ||
target.put( GENERAL_INDEX ); | ||
break; | ||
|
||
case UNIQUE: | ||
target.put( UNIQUE_INDEX ); | ||
Long owningConstraint = indexRule.getOwningConstraint(); | ||
if ( owningConstraint == null ) | ||
{ | ||
throw new MalformedSchemaRuleException( "Cannot serialize Unique Index before the owning constraint is set." ); | ||
} | ||
target.putLong( owningConstraint ); | ||
break; | ||
|
||
default: | ||
throw new UnsupportedOperationException( format( "Got unknown index descriptor type '%s'.", | ||
indexDescriptor.type() ) ); | ||
} | ||
|
||
indexDescriptor.schema().processWith( new SchemaDescriptorSerializer( target ) ); | ||
} | ||
|
||
private static class SchemaDescriptorSerializer implements SchemaProcessor | ||
{ | ||
private final ByteBuffer target; | ||
|
||
SchemaDescriptorSerializer( ByteBuffer target ) | ||
{ | ||
this.target = target; | ||
} | ||
|
||
@Override | ||
public void processSpecific( LabelSchemaDescriptor schema ) | ||
{ | ||
target.put( SIMPLE_LABEL ); | ||
target.putInt( schema.getLabelId() ); | ||
|
||
int[] propertyIds = schema.getPropertyIds(); | ||
target.putShort( (short)propertyIds.length ); | ||
for ( int propertyId : propertyIds ) | ||
{ | ||
target.putInt( propertyId ); | ||
} | ||
} | ||
|
||
@Override | ||
public void processSpecific( RelationTypeSchemaDescriptor schema ) | ||
{ | ||
target.put( SIMPLE_REL_TYPE ); | ||
target.putInt( schema.getRelTypeId() ); | ||
|
||
int[] propertyIds = schema.getPropertyIds(); | ||
target.putShort( (short)propertyIds.length ); | ||
for ( int propertyId : propertyIds ) | ||
{ | ||
target.putInt( propertyId ); | ||
} | ||
} | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
.../kernel/src/test/java/org/neo4j/kernel/impl/store/record/SchemaRuleSerializationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* 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.store.record; | ||
|
||
import org.junit.Test; | ||
|
||
import java.nio.ByteBuffer; | ||
import java.util.stream.IntStream; | ||
|
||
import org.neo4j.kernel.api.exceptions.schema.MalformedSchemaRuleException; | ||
import org.neo4j.kernel.api.schema_new.index.NewIndexDescriptorFactory; | ||
import org.neo4j.storageengine.api.schema.SchemaRule; | ||
|
||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.junit.Assert.fail; | ||
|
||
public class SchemaRuleSerializationTest extends SchemaRuleTestBase | ||
{ | ||
private static final int VERY_LARGE_CAPACITY = 1024; | ||
|
||
@Test | ||
public void shouldSerializeAndDeserializeIndexRules() throws MalformedSchemaRuleException | ||
{ | ||
IndexRule regular = IndexRule.indexRule( RULE_ID, NewIndexDescriptorFactory.forLabel( LABEL_ID, PROPERTY_ID_1 ), | ||
PROVIDER_DESCRIPTOR ); | ||
assertSerializeAndDeserializeIndexRule( RULE_ID, regular ); | ||
|
||
IndexRule unique = IndexRule | ||
.constraintIndexRule( RULE_ID_2, NewIndexDescriptorFactory.uniqueForLabel( LABEL_ID, PROPERTY_ID_1 ), | ||
PROVIDER_DESCRIPTOR, RULE_ID ); | ||
assertSerializeAndDeserializeIndexRule( RULE_ID_2, unique ); | ||
} | ||
|
||
@Test | ||
public void shouldSerializeAndDeserializeCompositeIndexRules() throws MalformedSchemaRuleException | ||
{ | ||
IndexRule composite = IndexRule.indexRule( RULE_ID, | ||
NewIndexDescriptorFactory.forLabel( LABEL_ID, PROPERTY_ID_1, PROPERTY_ID_2 ), PROVIDER_DESCRIPTOR ); | ||
assertSerializeAndDeserializeIndexRule( RULE_ID, composite ); | ||
|
||
IndexRule compositeUnique = IndexRule.constraintIndexRule( RULE_ID_2, | ||
NewIndexDescriptorFactory.uniqueForLabel( LABEL_ID, PROPERTY_ID_1, PROPERTY_ID_2 ), | ||
PROVIDER_DESCRIPTOR, RULE_ID ); | ||
assertSerializeAndDeserializeIndexRule( RULE_ID_2, compositeUnique ); | ||
} | ||
|
||
@Test | ||
public void shouldSerializeAndDeserialize_Big_CompositeIndexRules() throws MalformedSchemaRuleException | ||
{ | ||
int[] propertIds = IntStream.range(1, 200).toArray(); | ||
IndexRule composite = IndexRule.indexRule( RULE_ID, | ||
NewIndexDescriptorFactory.forLabel( LABEL_ID, propertIds ), PROVIDER_DESCRIPTOR ); | ||
assertSerializeAndDeserializeIndexRule( RULE_ID, composite ); | ||
} | ||
|
||
private void assertSerializeAndDeserializeIndexRule( long ruleId, IndexRule indexRule ) | ||
throws MalformedSchemaRuleException | ||
{ | ||
ByteBuffer buffer = ByteBuffer.allocate( VERY_LARGE_CAPACITY ); | ||
SchemaRuleSerialization.serialize( indexRule, buffer ); | ||
buffer.flip(); | ||
IndexRule deserialized = assertIndexRule( SchemaRuleSerialization.deserialize( ruleId, buffer ) ); | ||
|
||
// THEN | ||
assertThat( deserialized.getId(), equalTo( indexRule.getId() ) ); | ||
assertThat( deserialized.getIndexDescriptor(), equalTo( indexRule.getIndexDescriptor() ) ); | ||
assertThat( deserialized.getSchemaDescriptor(), equalTo( indexRule.getSchemaDescriptor() ) ); | ||
assertThat( deserialized.getProviderDescriptor(), equalTo( indexRule.getProviderDescriptor() ) ); | ||
} | ||
|
||
private IndexRule assertIndexRule( SchemaRule schemaRule ) | ||
{ | ||
if ( !(schemaRule instanceof IndexRule) ) | ||
{ | ||
fail( "Expected IndexRule, but got "+schemaRule.getClass().getSimpleName() ); | ||
} | ||
return (IndexRule)schemaRule; | ||
} | ||
|
||
} |