/* * 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.spi.block; import com.facebook.presto.spi.type.TypeManager; import com.google.common.collect.ImmutableSet; import io.airlift.slice.SliceInput; import io.airlift.slice.SliceOutput; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import static com.google.common.base.Preconditions.checkArgument; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Objects.requireNonNull; public final class TestingBlockEncodingSerde implements BlockEncodingSerde { private final TypeManager typeManager; private final ConcurrentMap<String, BlockEncodingFactory<?>> blockEncodings = new ConcurrentHashMap<>(); public TestingBlockEncodingSerde(TypeManager typeManager, BlockEncodingFactory<?>... blockEncodingFactories) { this(typeManager, ImmutableSet.copyOf(blockEncodingFactories)); } public TestingBlockEncodingSerde(TypeManager typeManager, Set<BlockEncodingFactory<?>> blockEncodingFactories) { // This function should be called from Guice and tests only this.typeManager = requireNonNull(typeManager, "typeManager is null"); // always add the built-in BlockEncodingFactories addBlockEncodingFactory(VariableWidthBlockEncoding.FACTORY); addBlockEncodingFactory(FixedWidthBlockEncoding.FACTORY); addBlockEncodingFactory(ByteArrayBlockEncoding.FACTORY); addBlockEncodingFactory(ShortArrayBlockEncoding.FACTORY); addBlockEncodingFactory(IntArrayBlockEncoding.FACTORY); addBlockEncodingFactory(LongArrayBlockEncoding.FACTORY); addBlockEncodingFactory(SliceArrayBlockEncoding.FACTORY); addBlockEncodingFactory(DictionaryBlockEncoding.FACTORY); addBlockEncodingFactory(ArrayBlockEncoding.FACTORY); addBlockEncodingFactory(InterleavedBlockEncoding.FACTORY); addBlockEncodingFactory(MapBlockEncoding.FACTORY); addBlockEncodingFactory(SingleMapBlockEncoding.FACTORY); for (BlockEncodingFactory<?> factory : requireNonNull(blockEncodingFactories, "blockEncodingFactories is null")) { addBlockEncodingFactory(factory); } } public void addBlockEncodingFactory(BlockEncodingFactory<?> blockEncoding) { requireNonNull(blockEncoding, "blockEncoding is null"); BlockEncodingFactory<?> existingEntry = blockEncodings.putIfAbsent(blockEncoding.getName(), blockEncoding); checkArgument(existingEntry == null, "Encoding %s is already registered", blockEncoding.getName()); } @Override public BlockEncoding readBlockEncoding(SliceInput input) { // read the encoding name String encodingName = readLengthPrefixedString(input); // look up the encoding factory BlockEncodingFactory<?> blockEncoding = blockEncodings.get(encodingName); checkArgument(blockEncoding != null, "Unknown block encoding %s", encodingName); // load read the encoding factory from the output stream return blockEncoding.readEncoding(typeManager, this, input); } @Override public void writeBlockEncoding(SliceOutput output, BlockEncoding encoding) { // get the encoding name String encodingName = encoding.getName(); // look up the encoding factory BlockEncodingFactory<BlockEncoding> blockEncoding = encoding.getFactory(); // write the name to the output writeLengthPrefixedString(output, encodingName); // write the encoding to the output blockEncoding.writeEncoding(this, output, encoding); } private static String readLengthPrefixedString(SliceInput input) { int length = input.readInt(); byte[] bytes = new byte[length]; input.readBytes(bytes); return new String(bytes, UTF_8); } private static void writeLengthPrefixedString(SliceOutput output, String value) { byte[] bytes = value.getBytes(UTF_8); output.writeInt(bytes.length); output.writeBytes(bytes); } }