-
Notifications
You must be signed in to change notification settings - Fork 70
Validator Interface Update & Converter Changes #533
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
41a8899
f26457c
fd69f8b
fdb9d98
dcecf18
b12c609
3621172
8435d0e
71451a7
2a882d4
c177894
add6eb3
366daff
e362fe9
66680f9
6829614
bb9fb56
a1235ce
6eb8a43
f7bf292
fd59bbb
4c264d7
1e1e73d
65f12f0
705f7d4
02b3b7a
6191c15
7d6418a
9c533a5
364acb4
31e70f4
69dfe0b
767d008
0b1e590
ce59fb0
2d6a9e3
664cece
b4b02c8
f4e90e9
8075684
4dec79f
11d3747
7281c2f
08cc929
3cf0185
a8f9c08
1d82d23
8fb1016
9f3e434
c48b2d7
9b77963
49f2963
ee1e231
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,20 +18,24 @@ | |
| import java.io.ByteArrayOutputStream; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.io.OutputStream; | ||
| import java.util.function.LongFunction; | ||
|
|
||
| import org.agrona.DirectBuffer; | ||
| import org.agrona.ExpandableDirectByteBuffer; | ||
| import org.agrona.collections.Int2IntHashMap; | ||
| import org.agrona.collections.Int2ObjectCache; | ||
| import org.agrona.concurrent.UnsafeBuffer; | ||
| import org.agrona.io.DirectBufferInputStream; | ||
| import org.agrona.io.ExpandableDirectBufferOutputStream; | ||
| import org.apache.avro.AvroRuntimeException; | ||
| import org.apache.avro.Schema; | ||
| import org.apache.avro.generic.GenericData; | ||
| import org.apache.avro.generic.GenericDatumReader; | ||
| import org.apache.avro.generic.GenericDatumWriter; | ||
| import org.apache.avro.generic.GenericRecord; | ||
| import org.apache.avro.io.BinaryDecoder; | ||
| import org.apache.avro.io.BinaryEncoder; | ||
| import org.apache.avro.io.DecoderFactory; | ||
| import org.apache.avro.io.EncoderFactory; | ||
|
|
||
|
|
@@ -45,7 +49,8 @@ public abstract class AvroValidator | |
| protected static final byte MAGIC_BYTE = 0x0; | ||
| protected static final String FORMAT_JSON = "json"; | ||
|
|
||
| private static final InputStream EMPTY_STREAM = new ByteArrayInputStream(new byte[0]); | ||
| private static final InputStream EMPTY_INPUT_STREAM = new ByteArrayInputStream(new byte[0]); | ||
| private static final OutputStream EMPTY_OUTPUT_STREAM = new ByteArrayOutputStream(0); | ||
| private static final int JSON_FIELD_STRUCTURE_LENGTH = "\"\":\"\",".length(); | ||
|
|
||
| protected final DirectBuffer valueRO; | ||
|
|
@@ -54,9 +59,10 @@ public abstract class AvroValidator | |
| protected final DecoderFactory decoderFactory; | ||
| protected final EncoderFactory encoderFactory; | ||
| protected final BinaryDecoder decoder; | ||
| protected final BinaryEncoder encoder; | ||
| protected final String subject; | ||
| protected final String format; | ||
| protected final ByteArrayOutputStream encoded; | ||
| protected final ExpandableDirectBufferOutputStream encoded; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest renaming this to |
||
| protected final DirectBufferInputStream in; | ||
|
|
||
| private final Int2ObjectCache<Schema> schemas; | ||
|
|
@@ -70,8 +76,9 @@ protected AvroValidator( | |
| LongFunction<CatalogHandler> supplyCatalog) | ||
| { | ||
| this.decoderFactory = DecoderFactory.get(); | ||
| this.decoder = decoderFactory.binaryDecoder(EMPTY_STREAM, null); | ||
| this.decoder = decoderFactory.binaryDecoder(EMPTY_INPUT_STREAM, null); | ||
| this.encoderFactory = EncoderFactory.get(); | ||
| this.encoder = encoderFactory.binaryEncoder(EMPTY_OUTPUT_STREAM, null); | ||
| CatalogedConfig cataloged = config.cataloged.get(0); | ||
| this.handler = supplyCatalog.apply(cataloged.id); | ||
| this.catalog = cataloged.schemas.size() != 0 ? cataloged.schemas.get(0) : null; | ||
|
|
@@ -85,7 +92,7 @@ protected AvroValidator( | |
| this.records = new Int2ObjectCache<>(1, 1024, i -> {}); | ||
| this.paddings = new Int2IntHashMap(-1); | ||
| this.valueRO = new UnsafeBuffer(); | ||
| this.encoded = new ByteArrayOutputStream(); | ||
| this.encoded = new ExpandableDirectBufferOutputStream(new ExpandableDirectByteBuffer()); | ||
| this.in = new DirectBufferInputStream(); | ||
| } | ||
|
|
||
|
|
@@ -100,7 +107,7 @@ protected final boolean validate( | |
| { | ||
| GenericRecord record = supplyRecord(schemaId); | ||
| in.wrap(buffer, index, length); | ||
| GenericDatumReader<GenericRecord> reader = readers.computeIfAbsent(schemaId, this::supplyReader); | ||
| GenericDatumReader<GenericRecord> reader = supplyReader(schemaId); | ||
| reader.read(record, decoderFactory.binaryDecoder(in, decoder)); | ||
| status = true; | ||
| } | ||
|
|
@@ -126,24 +133,25 @@ protected final int supplyPadding( | |
| protected final GenericDatumReader<GenericRecord> supplyReader( | ||
| int schemaId) | ||
| { | ||
| return readers.computeIfAbsent(schemaId, id -> createReader(supplySchema(id))); | ||
| return readers.computeIfAbsent(schemaId, this::createReader); | ||
| } | ||
|
|
||
| protected final GenericDatumWriter<GenericRecord> supplyWriter( | ||
| int schemaId) | ||
| { | ||
| return writers.computeIfAbsent(schemaId, id -> createWriter(supplySchema(id))); | ||
| return writers.computeIfAbsent(schemaId, this::createWriter); | ||
| } | ||
|
|
||
| protected final GenericRecord supplyRecord( | ||
| int schemaId) | ||
| { | ||
| return records.computeIfAbsent(schemaId, id -> createRecord(supplySchema(schemaId))); | ||
| return records.computeIfAbsent(schemaId, this::createRecord); | ||
| } | ||
|
|
||
| private GenericDatumReader<GenericRecord> createReader( | ||
| Schema schema) | ||
| int schemaId) | ||
| { | ||
| Schema schema = supplySchema(schemaId); | ||
| GenericDatumReader<GenericRecord> reader = null; | ||
| if (schema != null) | ||
| { | ||
|
|
@@ -153,8 +161,9 @@ private GenericDatumReader<GenericRecord> createReader( | |
| } | ||
|
|
||
| private GenericDatumWriter<GenericRecord> createWriter( | ||
| Schema schema) | ||
| int schemaId) | ||
| { | ||
| Schema schema = supplySchema(schemaId); | ||
| GenericDatumWriter<GenericRecord> writer = null; | ||
| if (schema != null) | ||
| { | ||
|
|
@@ -164,8 +173,9 @@ private GenericDatumWriter<GenericRecord> createWriter( | |
| } | ||
|
|
||
| private GenericRecord createRecord( | ||
| Schema schema) | ||
| int schemaId) | ||
| { | ||
| Schema schema = supplySchema(schemaId); | ||
| GenericRecord record = null; | ||
| if (schema != null) | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,7 +23,6 @@ | |
| import org.apache.avro.generic.GenericDatumReader; | ||
| import org.apache.avro.generic.GenericDatumWriter; | ||
| import org.apache.avro.generic.GenericRecord; | ||
| import org.apache.avro.io.BinaryEncoder; | ||
|
|
||
| import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler; | ||
| import io.aklivity.zilla.runtime.engine.validator.FragmentValidator; | ||
|
|
@@ -91,13 +90,13 @@ private int validateComplete( | |
| { | ||
| if (FORMAT_JSON.equals(format)) | ||
| { | ||
| byte[] record = serializeJsonRecord(schemaId, data, index, length); | ||
|
|
||
| int recordLength = record.length; | ||
| int recordLength = encoded.position(); | ||
| serializeJsonRecord(schemaId, data, index, length); | ||
| recordLength = encoded.position() - recordLength; | ||
| if (recordLength > 0) | ||
| { | ||
| valLength = recordLength + handler.enrich(schemaId, next); | ||
| valueRO.wrap(record); | ||
| valueRO.wrap(encoded.buffer()); | ||
| next.accept(valueRO, 0, recordLength); | ||
| } | ||
| } | ||
|
|
@@ -110,13 +109,12 @@ else if (validate(schemaId, data, index, length)) | |
| return valLength; | ||
| } | ||
|
|
||
| private byte[] serializeJsonRecord( | ||
| private void serializeJsonRecord( | ||
| int schemaId, | ||
| DirectBuffer buffer, | ||
| int index, | ||
| int length) | ||
| { | ||
| encoded.reset(); | ||
| try | ||
| { | ||
| Schema schema = supplySchema(schemaId); | ||
|
|
@@ -125,15 +123,14 @@ private byte[] serializeJsonRecord( | |
| GenericRecord record = supplyRecord(schemaId); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can the json decoder below be precreated and reused instead of creating afresh each time?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this doesn't seems possible as we don't have a method to take reuse JsonDecoder.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but I was able to optimise BinaryEncoder & reuse the same instance. |
||
| in.wrap(buffer, index, length); | ||
| record = reader.read(record, decoderFactory.jsonDecoder(schema, in)); | ||
| BinaryEncoder out = encoderFactory.binaryEncoder(encoded, null); | ||
| writer.write(record, out); | ||
| out.flush(); | ||
| encoderFactory.binaryEncoder(encoded, encoder); | ||
| writer.write(record, encoder); | ||
| encoder.flush(); | ||
| encoded.close(); | ||
| } | ||
| catch (IOException | AvroRuntimeException ex) | ||
| { | ||
| ex.printStackTrace(); | ||
| } | ||
| return encoded.toByteArray(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,18 +27,20 @@ public boolean validate( | |
| int length) | ||
| { | ||
| final int limit = index + length; | ||
| validate: | ||
| while (index < limit) | ||
| { | ||
| final int charByte0 = data.getByte(index); | ||
| final int charByteCount = (charByte0 & 0b1000_0000) != 0 | ||
| ? Integer.numberOfLeadingZeros((~charByte0 & 0xff) << 24) | ||
| : 1; | ||
|
|
||
| for (int j = 1; j < charByteCount; j++) | ||
| final int charByteLimit = index + charByteCount; | ||
| for (int charByteIndex = index + 1; charByteIndex < charByteLimit; charByteIndex++) | ||
| { | ||
| if (index + j >= limit || (data.getByte(index + j) & 0b11000000) != 0b10000000) | ||
| if (charByteIndex >= limit || (data.getByte(charByteIndex) & 0b11000000) != 0b10000000) | ||
| { | ||
| break; | ||
| break validate; | ||
| } | ||
| } | ||
| index += charByteCount; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are calculating I think the |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,8 +20,6 @@ | |
| public interface CatalogHandler | ||
| { | ||
| int NO_SCHEMA_ID = 0; | ||
| int NO_ENRICHMENT = 0; | ||
| int ZERO_PADDING = 0; | ||
|
|
||
| int register( | ||
| String subject, | ||
|
|
@@ -39,11 +37,11 @@ default int enrich( | |
| int schemaId, | ||
| ValueConsumer next) | ||
| { | ||
| return NO_ENRICHMENT; | ||
| return 0; | ||
| } | ||
|
|
||
| default int maxPadding() | ||
| { | ||
| return ZERO_PADDING; | ||
| return 0; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's rename to Also let's rename |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,15 +26,14 @@ | |
|
|
||
| public class TestCatalogHandler implements CatalogHandler | ||
| { | ||
| private static final int MAX_PADDING_LEN = 10; | ||
| private static final int MAX_PADDING_LENGTH = 10; | ||
| private static final byte MAGIC_BYTE = 0x0; | ||
| private static final int ENRICHED_LENGTH = 5; | ||
| private static final int PREFIX_LENGTH = 5; | ||
|
|
||
| private final String schema; | ||
| private final MutableDirectBuffer prefixRO; | ||
| private final int id; | ||
| private final boolean embed; | ||
| private final boolean exclude; | ||
|
|
||
| public TestCatalogHandler( | ||
| TestCatalogOptionsConfig config) | ||
|
|
@@ -43,7 +42,6 @@ public TestCatalogHandler( | |
| this.prefixRO = new UnsafeBuffer(new byte[5]); | ||
| this.id = config.id; | ||
| this.embed = config.embed; | ||
| this.exclude = config.exclude; | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -56,20 +54,16 @@ public int enrich( | |
| { | ||
| prefixRO.putByte(0, MAGIC_BYTE); | ||
| prefixRO.putInt(1, schemaId, ByteOrder.BIG_ENDIAN); | ||
| next.accept(prefixRO, 0, 5); | ||
| length = ENRICHED_LENGTH; | ||
| } | ||
| else if (exclude) | ||
| { | ||
| length = ENRICHED_LENGTH; | ||
| next.accept(prefixRO, 0, PREFIX_LENGTH); | ||
| length = PREFIX_LENGTH; | ||
| } | ||
| return length; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it make sense to have booleans for If it is a property of the validator, then perhaps we need to pass this context from the validator to the catalog handler, either via a parameter or by having 2 methods on catalog handler? |
||
| } | ||
|
|
||
| @Override | ||
| public int maxPadding() | ||
| { | ||
| return MAX_PADDING_LEN; | ||
| return MAX_PADDING_LENGTH; | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.