/**
* 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.metastore.hbase;
import com.google.protobuf.InvalidProtocolBufferException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.FilterBase;
import org.apache.hive.common.util.BloomFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* Filter for scanning aggregates stats table
*/
public class AggrStatsInvalidatorFilter extends FilterBase {
private static final Logger LOG =
LoggerFactory.getLogger(AggrStatsInvalidatorFilter.class.getName());
private final List<HbaseMetastoreProto.AggrStatsInvalidatorFilter.Entry> entries;
private final long runEvery;
private final long maxCacheEntryLife;
// This class is not serializable, so I realize transient doesn't mean anything. It's just to
// comunicate that we don't serialize this and ship it across to the filter on the other end.
// We use the time the filter is actually instantiated in HBase.
private transient long now;
public static Filter parseFrom(byte[] serialized) throws DeserializationException {
try {
return new AggrStatsInvalidatorFilter(
HbaseMetastoreProto.AggrStatsInvalidatorFilter.parseFrom(serialized));
} catch (InvalidProtocolBufferException e) {
throw new DeserializationException(e);
}
}
/**
* @param proto Protocol buffer representation of this filter.
*/
AggrStatsInvalidatorFilter(HbaseMetastoreProto.AggrStatsInvalidatorFilter proto) {
this.entries = proto.getToInvalidateList();
this.runEvery = proto.getRunEvery();
this.maxCacheEntryLife = proto.getMaxCacheEntryLife();
now = System.currentTimeMillis();
}
@Override
public byte[] toByteArray() throws IOException {
return HbaseMetastoreProto.AggrStatsInvalidatorFilter.newBuilder()
.addAllToInvalidate(entries)
.setRunEvery(runEvery)
.setMaxCacheEntryLife(maxCacheEntryLife)
.build()
.toByteArray();
}
@Override
public boolean filterAllRemaining() throws IOException {
return false;
}
@Override
public ReturnCode filterKeyValue(Cell cell) throws IOException {
// Is this the partition we want?
if (Arrays.equals(CellUtil.cloneQualifier(cell), HBaseReadWrite.AGGR_STATS_BLOOM_COL)) {
HbaseMetastoreProto.AggrStatsBloomFilter fromCol =
HbaseMetastoreProto.AggrStatsBloomFilter.parseFrom(CellUtil.cloneValue(cell));
BloomFilter bloom = null;
if (now - maxCacheEntryLife > fromCol.getAggregatedAt()) {
// It's too old, kill it regardless of whether we were asked to or not.
return ReturnCode.INCLUDE;
} else if (now - runEvery * 2 <= fromCol.getAggregatedAt()) {
// It's too new. We might be stomping on something that was just created. Skip it.
return ReturnCode.NEXT_ROW;
} else {
// Look through each of our entries and see if any of them match.
for (HbaseMetastoreProto.AggrStatsInvalidatorFilter.Entry entry : entries) {
// First check if we match on db and table match
if (entry.getDbName().equals(fromCol.getDbName()) &&
entry.getTableName().equals(fromCol.getTableName())) {
if (bloom == null) {
// Now, reconstitute the bloom filter and probe it with each of our partition names
bloom = new BloomFilter(
fromCol.getBloomFilter().getBitsList(),
fromCol.getBloomFilter().getNumBits(),
fromCol.getBloomFilter().getNumFuncs());
}
if (bloom.test(entry.getPartName().toByteArray())) {
// This is most likely a match, so mark it and quit looking.
return ReturnCode.INCLUDE;
}
}
}
}
return ReturnCode.NEXT_ROW;
} else {
return ReturnCode.NEXT_COL;
}
}
}