/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.hadoop.hive.ql.exec.persistence; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.AbstractList; import java.util.ArrayList; import java.util.ConcurrentModificationException; import java.util.List; import org.apache.hadoop.hive.serde2.AbstractSerDe; import org.apache.hadoop.hive.serde2.SerDeException; import org.apache.hadoop.hive.serde2.io.ShortWritable; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorUtils; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorUtils.ObjectInspectorCopyOption; import org.apache.hadoop.io.Writable; @SuppressWarnings("deprecation") public class MapJoinEagerRowContainer implements MapJoinRowContainer, AbstractRowContainer.RowIterator<List<Object>> { private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; private final List<List<Object>> list; private byte aliasFilter = (byte) 0xff; private int index = 0; public MapJoinEagerRowContainer() { index = 0; list = new ArrayList<List<Object>>(1); } @Override public void addRow(List<Object> t) { list.add(t); } @Override public void addRow(Object[] t) { addRow(toList(t)); } @Override public AbstractRowContainer.RowIterator<List<Object>> rowIter() { return this; } @Override public List<Object> first() { index = 0; if (index < list.size()) { return list.get(index); } return null; } @Override public List<Object> next() { index++; if (index < list.size()) { return list.get(index); } return null; } @Override public boolean hasRows() { return list.size() > 0; } @Override public boolean isSingleRow() { return list.size() == 1; } /** * Get the number of elements in the RowContainer. * * @return number of elements in the RowContainer */ @Override public int rowCount() { return list.size(); } /** * Remove all elements in the RowContainer. */ @Override public void clearRows() { list.clear(); } @Override public byte getAliasFilter() { return aliasFilter; } @Override public MapJoinRowContainer copy() { MapJoinEagerRowContainer result = new MapJoinEagerRowContainer(); for(List<Object> item : list) { result.addRow(item); } return result; } public void read(MapJoinObjectSerDeContext context, ObjectInputStream in, Writable container) throws IOException, SerDeException { long numRows = in.readLong(); for (long rowIndex = 0L; rowIndex < numRows; rowIndex++) { container.readFields(in); read(context, container); } } @SuppressWarnings("unchecked") public void read(MapJoinObjectSerDeContext context, Writable currentValue) throws SerDeException { AbstractSerDe serde = context.getSerDe(); List<Object> value = (List<Object>)ObjectInspectorUtils.copyToStandardObject(serde.deserialize(currentValue), serde.getObjectInspector(), ObjectInspectorCopyOption.WRITABLE); if(value == null) { addRow(toList(EMPTY_OBJECT_ARRAY)); } else { Object[] valuesArray = value.toArray(); if (context.hasFilterTag()) { aliasFilter &= ((ShortWritable)valuesArray[valuesArray.length - 1]).get(); } addRow(toList(valuesArray)); } } @Override public void write(MapJoinObjectSerDeContext context, ObjectOutputStream out) throws IOException, SerDeException { AbstractSerDe serde = context.getSerDe(); ObjectInspector valueObjectInspector = context.getStandardOI(); long numRows = rowCount(); long numRowsWritten = 0L; out.writeLong(numRows); for (List<Object> row = first(); row != null; row = next()) { serde.serialize(row.toArray(), valueObjectInspector).write(out); ++numRowsWritten; } if(numRows != rowCount()) { throw new ConcurrentModificationException("Values was modified while persisting"); } if(numRowsWritten != numRows) { throw new IllegalStateException("Expected to write " + numRows + " but wrote " + numRowsWritten); } } private List<Object> toList(Object[] array) { return new NoCopyingArrayList(array); } /** * In this use case our objects will not be modified * so we don't care about copying in and out. */ private static class NoCopyingArrayList extends AbstractList<Object> { private Object[] array; public NoCopyingArrayList(Object[] array) { this.array = array; } @Override public Object get(int index) { return array[index]; } @Override public int size() { return array.length; } public Object[] toArray() { return array; } } }