/** * 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.llap.io.metadata; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hive.common.io.DiskRangeList; import org.apache.hadoop.hive.common.io.DataCache.BooleanRef; import org.apache.hadoop.hive.common.io.DataCache.DiskRangeListFactory; import org.apache.hadoop.hive.common.io.DiskRangeList.MutateHelper; import org.apache.hadoop.hive.llap.IncrementalObjectSizeEstimator; import org.apache.hadoop.hive.llap.IncrementalObjectSizeEstimator.ObjectEstimator; import org.apache.hadoop.hive.llap.cache.EvictionDispatcher; import org.apache.hadoop.hive.llap.cache.LlapCacheableBuffer; import org.apache.hadoop.hive.ql.io.SyntheticFileId; import org.apache.hadoop.hive.ql.io.orc.encoded.IncompleteCb; public class OrcFileEstimateErrors extends LlapCacheableBuffer { private final Object fileKey; private int estimatedMemUsage; private final ConcurrentHashMap<Long, Integer> cache = new ConcurrentHashMap<>(); private final static HashMap<Class<?>, ObjectEstimator> SIZE_ESTIMATORS; private final static ObjectEstimator SIZE_ESTIMATOR; static { SIZE_ESTIMATORS = IncrementalObjectSizeEstimator.createEstimators(createDummy( new SyntheticFileId(new Path("/"), 0, 0))); SIZE_ESTIMATOR = SIZE_ESTIMATORS.get(OrcFileEstimateErrors.class); } public OrcFileEstimateErrors(Object fileKey) { this.fileKey = fileKey; } public void addError(long offset, int length, long baseOffset) { Long key = Long.valueOf(offset + baseOffset); Integer existingLength = cache.get(key); if (existingLength != null && existingLength >= length) return; Integer value = Integer.valueOf(length); while (true) { existingLength = cache.putIfAbsent(key, value); if (existingLength == null || existingLength >= length) return; cache.remove(key, existingLength); } } public DiskRangeList getIncompleteCbs(DiskRangeList ranges, long baseOffset, DiskRangeListFactory factory, BooleanRef gotAllData) { DiskRangeList prev = ranges.prev; if (prev == null) { prev = new MutateHelper(ranges); } DiskRangeList current = ranges; gotAllData.value = true; // Assume by default that we would find everything. while (current != null) { // We assume ranges in "ranges" are non-overlapping; thus, we will save next in advance. DiskRangeList check = current; current = current.next; if (check.hasData()) continue; Integer badLength = cache.get(Long.valueOf(check.getOffset() + baseOffset)); if (badLength == null || badLength < check.getLength()) { gotAllData.value = false; continue; } // We could just remove here and handle the missing tail during read, but that can be // dangerous; let's explicitly add an incomplete CB. check.replaceSelfWith(new IncompleteCb(check.getOffset(), check.getEnd())); } return prev.next; } public Object getFileKey() { return fileKey; } public long estimateMemoryUsage() { // Since we won't be able to update this as we add, for now, estimate 10x usage. // This shouldn't be much and this cache should be remove later anyway. estimatedMemUsage = 10 * SIZE_ESTIMATOR.estimate(this, SIZE_ESTIMATORS); return estimatedMemUsage; } private static OrcFileEstimateErrors createDummy(Object fileKey) { OrcFileEstimateErrors dummy = new OrcFileEstimateErrors(fileKey); dummy.addError(0L, 0, 0L); return dummy; } @Override protected boolean invalidate() { return true; } @Override public long getMemoryUsage() { return estimatedMemUsage; } @Override public void notifyEvicted(EvictionDispatcher evictionDispatcher) { evictionDispatcher.notifyEvicted(this); } @Override protected boolean isLocked() { return false; } }