/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.facebook.presto.execution.buffer; import com.facebook.presto.spi.Page; import com.facebook.presto.spi.block.Block; import com.facebook.presto.spi.block.BlockEncodingSerde; import com.google.common.collect.AbstractIterator; import io.airlift.slice.Slice; import io.airlift.slice.SliceInput; import io.airlift.slice.SliceOutput; import java.util.Iterator; import static com.facebook.presto.block.BlockSerdeUtil.readBlock; import static com.facebook.presto.block.BlockSerdeUtil.writeBlock; import static com.facebook.presto.execution.buffer.PageCompression.lookupCodecFromMarker; import static java.lang.Math.toIntExact; import static java.util.Arrays.asList; import static java.util.Objects.requireNonNull; public class PagesSerdeUtil { private PagesSerdeUtil() { } static void writeRawPage(Page page, SliceOutput output, BlockEncodingSerde serde) { Block[] blocks = page.getBlocks(); output.writeInt(blocks.length); for (Block block : blocks) { writeBlock(serde, output, block); } } static Page readRawPage(int positionCount, SliceInput input, BlockEncodingSerde blockEncodingSerde) { int numberOfBlocks = input.readInt(); Block[] blocks = new Block[numberOfBlocks]; for (int i = 0; i < blocks.length; i++) { blocks[i] = readBlock(blockEncodingSerde, input); } return new Page(positionCount, blocks); } public static void writeSerializedPage(SliceOutput output, SerializedPage page) { output.writeInt(page.getPositionCount()); output.writeByte(page.getCompression().getMarker()); output.writeInt(page.getUncompressedSizeInBytes()); output.writeInt(page.getSizeInBytes()); output.writeBytes(page.getSlice()); } private static SerializedPage readSerializedPage(SliceInput sliceInput) { int positionCount = sliceInput.readInt(); byte codecMarker = sliceInput.readByte(); int uncompressedSizeInBytes = sliceInput.readInt(); int sizeInBytes = sliceInput.readInt(); Slice slice = sliceInput.readSlice(toIntExact((sizeInBytes))); return new SerializedPage(slice, lookupCodecFromMarker(codecMarker), positionCount, uncompressedSizeInBytes); } public static long writeSerializedPages(SliceOutput sliceOutput, Iterable<SerializedPage> pages) { Iterator<SerializedPage> pageIterator = pages.iterator(); long size = 0; while (pageIterator.hasNext()) { SerializedPage page = pageIterator.next(); writeSerializedPage(sliceOutput, page); size += page.getSizeInBytes(); } return size; } public static long writePages(PagesSerde serde, SliceOutput sliceOutput, Page... pages) { return writePages(serde, sliceOutput, asList(pages).iterator()); } public static long writePages(PagesSerde serde, SliceOutput sliceOutput, Iterator<Page> pages) { long size = 0; while (pages.hasNext()) { Page page = pages.next(); writeSerializedPage(sliceOutput, serde.serialize(page)); size += page.getSizeInBytes(); } return size; } public static Iterator<Page> readPages(PagesSerde serde, SliceInput sliceInput) { return new PageReader(serde, sliceInput); } private static class PageReader extends AbstractIterator<Page> { private final PagesSerde serde; private final SliceInput input; PageReader(PagesSerde serde, SliceInput input) { this.serde = requireNonNull(serde, "serde is null"); this.input = requireNonNull(input, "input is null"); } @Override protected Page computeNext() { if (!input.isReadable()) { return endOfData(); } return serde.deserialize(readSerializedPage(input)); } } public static Iterator<SerializedPage> readSerializedPages(SliceInput sliceInput) { return new SerializedPageReader(sliceInput); } private static class SerializedPageReader extends AbstractIterator<SerializedPage> { private final SliceInput input; SerializedPageReader(SliceInput input) { this.input = requireNonNull(input, "input is null"); } @Override protected SerializedPage computeNext() { if (!input.isReadable()) { return endOfData(); } return readSerializedPage(input); } } }