-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
SchemaRuleSerialization.java
362 lines (310 loc) · 12.8 KB
/
SchemaRuleSerialization.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/*
* 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.SchemaComputer;
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.constaints.ConstraintDescriptor;
import org.neo4j.kernel.api.schema_new.constaints.ConstraintDescriptorFactory;
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 = 31, UNIQUE_INDEX = 32;
// Constraint type
private final static byte EXISTS_CONSTRAINT = 61, UNIQUE_CONSTRAINT = 62;
// Schema type
private final static byte SIMPLE_LABEL = 91, SIMPLE_REL_TYPE = 92;
private SchemaRuleSerialization()
{
}
// PUBLIC
/**
* Parse a SchemaRule from the provided buffer.
* @param id the id to give the returned Schema Rule
* @param source the buffer to parse from
* @return a SchemaRule
* @throws MalformedSchemaRuleException if bytes in the buffer do encode a valid SchemaRule
*/
public static SchemaRule deserialize( long id, ByteBuffer source ) throws MalformedSchemaRuleException
{
byte schemaRuleType = source.get();
switch ( schemaRuleType )
{
case INDEX_RULE:
return readIndexRule( id, source );
case CONSTRAINT_RULE:
return readConstraintRule( id, source );
}
throw new UnsupportedOperationException( format( "Got unknown schema rule type '%d'.", schemaRuleType ) );
}
/**
* Serialize the provided IndexRule onto the target buffer
* @param indexRule the IndexRule to serialize
* @param target the target buffer
* @throws MalformedSchemaRuleException if the IndexRule is of type unique, but the owning constrain
* has not been set
*/
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 ) );
}
/**
* Serialize the provided ConstraintRule onto the target buffer
* @param constraintRule the ConstraintRule to serialize
* @param target the target buffer
* @throws MalformedSchemaRuleException if the ConstraintRule is of type unique, but the owned index
* has not been set
*/
public static void serialize( ConstraintRule constraintRule, ByteBuffer target ) throws MalformedSchemaRuleException
{
target.put( CONSTRAINT_RULE );
ConstraintDescriptor constraintDescriptor = constraintRule.getConstraintDescriptor();
switch ( constraintDescriptor.type() )
{
case EXISTS:
target.put( EXISTS_CONSTRAINT );
break;
case UNIQUE:
target.put( UNIQUE_CONSTRAINT );
target.putLong( constraintRule.getOwnedIndex() );
break;
default:
throw new UnsupportedOperationException( format( "Got unknown index descriptor type '%s'.",
constraintDescriptor.type() ) );
}
constraintDescriptor.schema().processWith( new SchemaDescriptorSerializer( target ) );
}
/**
* Compute the byte size needed to serialize the provided IndexRule using serialize.
* @param indexRule the IndexRule
* @return the byte size of indexRule
*/
public static int lengthOf( IndexRule indexRule )
{
int length = 1; // schema rule type
SchemaIndexProvider.Descriptor providerDescriptor = indexRule.getProviderDescriptor();
length += UTF8.computeRequiredByteBufferSize( providerDescriptor.getKey() );
length += UTF8.computeRequiredByteBufferSize( providerDescriptor.getVersion() );
length += 1; // index type
NewIndexDescriptor indexDescriptor = indexRule.getIndexDescriptor();
switch ( indexDescriptor.type() )
{
case UNIQUE:
length += 8; // owning constraint id
}
length += schemaSizeComputer.compute( indexDescriptor.schema() );
return length;
}
/**
* Compute the byte size needed to serialize the provided ConstraintRule using serialize.
* @param constraintRule the ConstraintRule
* @return the byte size of ConstraintRule
*/
public static int lengthOf( ConstraintRule constraintRule )
{
int length = 1; // schema rule type
length += 1; // constraint type
ConstraintDescriptor constraintDescriptor = constraintRule.getConstraintDescriptor();
switch ( constraintDescriptor.type() )
{
case UNIQUE:
length += 8; // owned index id
}
length += schemaSizeComputer.compute( constraintDescriptor.schema() );
return length;
}
// PRIVATE
// READ INDEX
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
);
}
throw new MalformedSchemaRuleException( 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 SchemaIndexProvider.Descriptor readIndexProviderDescriptor( ByteBuffer source )
{
String providerKey = getDecodedStringFrom( source );
String providerVersion = getDecodedStringFrom( source );
return new SchemaIndexProvider.Descriptor( providerKey, providerVersion );
}
// READ CONSTRAINT
private static ConstraintRule readConstraintRule( long id, ByteBuffer source ) throws MalformedSchemaRuleException
{
byte constraintRuleType = source.get();
switch ( constraintRuleType )
{
case EXISTS_CONSTRAINT:
return ConstraintRule.constraintRule(
id,
ConstraintDescriptorFactory.existsForSchema( readSchema( source ) )
);
case UNIQUE_CONSTRAINT:
long ownedIndex = source.getLong();
return ConstraintRule.constraintRule(
id,
ConstraintDescriptorFactory.uniqueForSchema( readSchema( source ) ),
ownedIndex
);
}
throw new MalformedSchemaRuleException( format( "Got unknown constraint rule type '%d'.", constraintRuleType ) );
}
// READ HELP
private static SchemaDescriptor readSchema( ByteBuffer source )
{
byte schemaDescriptorType = source.get();
switch ( schemaDescriptorType )
{
case SIMPLE_LABEL:
return SchemaDescriptorFactory.forLabel( source.getInt(), readPropertyIds( source ) );
case SIMPLE_REL_TYPE:
return SchemaDescriptorFactory.forRelType( 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;
}
// WRITE
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 );
}
}
}
// LENGTH OF
private static SchemaComputer<Integer> schemaSizeComputer = new SchemaComputer<Integer>()
{
@Override
public Integer computeSpecific( LabelSchemaDescriptor schema )
{
return 1 // schema descriptor type
+ 4 // label id
+ 2 // property id count
+ 4 * schema.getPropertyIds().length; // the actual property ids
}
@Override
public Integer computeSpecific( RelationTypeSchemaDescriptor schema )
{
return 1 // schema descriptor type
+ 4 // rel type id
+ 2 // property id count
+ 4 * schema.getPropertyIds().length; // the actual property ids
}
};
}