Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 1.6k
GH-3493: Optimize PlainValuesReader with direct ByteBuffer reads#3494
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -19,120 +19,92 @@ | ||
| package org.apache.parquet.column.values.plain; | ||
| import java.io.IOException; | ||
| import java.nio.ByteBuffer; | ||
| import java.nio.ByteOrder; | ||
| import org.apache.parquet.bytes.ByteBufferInputStream; | ||
| import org.apache.parquet.bytes.LittleEndianDataInputStream; | ||
| import org.apache.parquet.column.values.ValuesReader; | ||
| import org.apache.parquet.io.ParquetDecodingException; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| /** | ||
| * Plain encoding for float, double, int, long | ||
| * Plain encoding for float, double, int, long. | ||
| * | ||
| * <p>Reads directly from a {@link ByteBuffer} with {@link ByteOrder#LITTLE_ENDIAN} byte order, | ||
| * bypassing the {@link LittleEndianDataInputStream} wrapper to avoid per-value virtual dispatch | ||
| * overhead. The underlying page data is obtained as a single contiguous {@link ByteBuffer} via | ||
| * {@link ByteBufferInputStream#slice(int)}. | ||
| */ | ||
| public abstract class PlainValuesReader extends ValuesReader { | ||
| private static final Logger LOG = LoggerFactory.getLogger(PlainValuesReader.class); | ||
| protected LittleEndianDataInputStream in; | ||
| ByteBuffer buffer; | ||
| @Override | ||
| public void initFromPage(int valueCount, ByteBufferInputStream stream) throws IOException { | ||
| LOG.debug("init from page at offset {} for length {}", stream.position(), stream.available()); | ||
| this.in = new LittleEndianDataInputStream(stream.remainingStream()); | ||
| int available = stream.available(); | ||
| if (available > 0) { | ||
| this.buffer = stream.slice(available).order(ByteOrder.LITTLE_ENDIAN); | ||
| } else { | ||
| this.buffer = ByteBuffer.allocate(0).order(ByteOrder.LITTLE_ENDIAN); | ||
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. Should we introduce a constant: | ||
| } | ||
| } | ||
| @Override | ||
| public void skip() { | ||
| skip(1); | ||
| } | ||
| void skipBytesFully(int n) throws IOException { | ||
| int skipped = 0; | ||
| while (skipped < n) { | ||
| skipped += in.skipBytes(n - skipped); | ||
| } | ||
| } | ||
| public static class DoublePlainValuesReader extends PlainValuesReader { | ||
| @Override | ||
| public void skip(int n) { | ||
| try { | ||
| skipBytesFully(n * 8); | ||
| } catch (IOException e) { | ||
| throw new ParquetDecodingException("could not skip " + n + " double values", e); | ||
| } | ||
| buffer.position(buffer.position() + n * 8); | ||
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. When skipping, should we validate bounds? | ||
| } | ||
| @Override | ||
| public double readDouble() { | ||
| try { | ||
| return in.readDouble(); | ||
| } catch (IOException e) { | ||
| throw new ParquetDecodingException("could not read double", e); | ||
| } | ||
| return buffer.getDouble(); | ||
| } | ||
| } | ||
| public static class FloatPlainValuesReader extends PlainValuesReader { | ||
| @Override | ||
| public void skip(int n) { | ||
| try { | ||
| skipBytesFully(n * 4); | ||
| } catch (IOException e) { | ||
| throw new ParquetDecodingException("could not skip " + n + " floats", e); | ||
| } | ||
| buffer.position(buffer.position() + n * 4); | ||
| } | ||
| @Override | ||
| public float readFloat() { | ||
| try { | ||
| return in.readFloat(); | ||
| } catch (IOException e) { | ||
| throw new ParquetDecodingException("could not read float", e); | ||
| } | ||
| return buffer.getFloat(); | ||
| } | ||
| } | ||
| public static class IntegerPlainValuesReader extends PlainValuesReader { | ||
| @Override | ||
| public void skip(int n) { | ||
| try { | ||
| in.skipBytes(n * 4); | ||
| } catch (IOException e) { | ||
| throw new ParquetDecodingException("could not skip " + n + " ints", e); | ||
| } | ||
| buffer.position(buffer.position() + n * 4); | ||
| } | ||
| @Override | ||
| public int readInteger() { | ||
| try { | ||
| return in.readInt(); | ||
| } catch (IOException e) { | ||
| throw new ParquetDecodingException("could not read int", e); | ||
| } | ||
| return buffer.getInt(); | ||
| } | ||
| } | ||
| public static class LongPlainValuesReader extends PlainValuesReader { | ||
| @Override | ||
| public void skip(int n) { | ||
| try { | ||
| in.skipBytes(n * 8); | ||
| } catch (IOException e) { | ||
| throw new ParquetDecodingException("could not skip " + n + " longs", e); | ||
| } | ||
| buffer.position(buffer.position() + n * 8); | ||
| } | ||
| @Override | ||
| public long readLong() { | ||
| try { | ||
| return in.readLong(); | ||
| } catch (IOException e) { | ||
| throw new ParquetDecodingException("could not read long", e); | ||
| } | ||
| return buffer.getLong(); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.