org.apache.hadoop.hbase.security.visibility.VisibilityNewVersionBehaivorTracker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hbase-server Show documentation
Show all versions of hbase-server Show documentation
Server functionality for HBase
/**
*
* 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.hbase.security.visibility;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellComparator;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.Tag;
import org.apache.hadoop.hbase.regionserver.querymatcher.NewVersionBehaviorTracker;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Similar to MvccSensitiveTracker but tracks the visibility expression also before
* deciding if a Cell can be considered deleted
*/
@InterfaceAudience.Private
public class VisibilityNewVersionBehaivorTracker extends NewVersionBehaviorTracker {
private static final Logger LOG =
LoggerFactory.getLogger(VisibilityNewVersionBehaivorTracker.class);
public VisibilityNewVersionBehaivorTracker(NavigableSet columns,
CellComparator cellComparator, int minVersion, int maxVersion, int resultMaxVersions,
long oldestUnexpiredTS) {
super(columns, cellComparator, minVersion, maxVersion, resultMaxVersions, oldestUnexpiredTS);
}
private static class TagInfo {
List tags;
Byte format;
private TagInfo(Cell c) {
tags = new ArrayList<>();
format = VisibilityUtils.extractVisibilityTags(c, tags);
}
private TagInfo() {
tags = new ArrayList<>();
}
}
private class VisibilityDeleteVersionsNode extends DeleteVersionsNode {
private TagInfo tagInfo;
// >
// Key is ts of version deletes, value is its mvccs.
// We may delete more than one time for a version.
private Map> deletesMap = new HashMap<>();
// >
// Key is mvcc of version deletes, value is mvcc of visible puts before the delete effect.
private NavigableMap> mvccCountingMap = new TreeMap<>();
protected VisibilityDeleteVersionsNode(long ts, long mvcc, TagInfo tagInfo) {
this.tagInfo = tagInfo;
this.ts = ts;
this.mvcc = mvcc;
mvccCountingMap.put(Long.MAX_VALUE, new TreeSet());
}
@Override
protected VisibilityDeleteVersionsNode getDeepCopy() {
VisibilityDeleteVersionsNode node = new VisibilityDeleteVersionsNode(ts, mvcc, tagInfo);
for (Map.Entry> e : deletesMap.entrySet()) {
node.deletesMap.put(e.getKey(), new TreeMap<>(e.getValue()));
}
for (Map.Entry> e : mvccCountingMap.entrySet()) {
node.mvccCountingMap.put(e.getKey(), new TreeSet<>(e.getValue()));
}
return node;
}
@Override
public void addVersionDelete(Cell cell) {
SortedMap set = deletesMap.get(cell.getTimestamp());
if (set == null) {
set = new TreeMap<>();
deletesMap.put(cell.getTimestamp(), set);
}
set.put(cell.getSequenceId(), new TagInfo(cell));
// The init set should be the puts whose mvcc is smaller than this Delete. Because
// there may be some Puts masked by them. The Puts whose mvcc is larger than this Delete can
// not be copied to this node because we may delete one version and the oldest put may not be
// masked.
SortedSet nextValue = mvccCountingMap.ceilingEntry(cell.getSequenceId()).getValue();
SortedSet thisValue = new TreeSet<>(nextValue.headSet(cell.getSequenceId()));
mvccCountingMap.put(cell.getSequenceId(), thisValue);
}
}
@Override
public void add(Cell cell) {
prepare(cell);
byte type = cell.getTypeByte();
switch (KeyValue.Type.codeToType(type)) {
// By the order of seen. We put null cq at first.
case DeleteFamily: // Delete all versions of all columns of the specified family
delFamMap.put(cell.getSequenceId(),
new VisibilityDeleteVersionsNode(cell.getTimestamp(), cell.getSequenceId(),
new TagInfo(cell)));
break;
case DeleteFamilyVersion: // Delete all columns of the specified family and specified version
delFamMap.ceilingEntry(cell.getSequenceId()).getValue().addVersionDelete(cell);
break;
// These two kinds of markers are mix with Puts.
case DeleteColumn: // Delete all versions of the specified column
delColMap.put(cell.getSequenceId(),
new VisibilityDeleteVersionsNode(cell.getTimestamp(), cell.getSequenceId(),
new TagInfo(cell)));
break;
case Delete: // Delete the specified version of the specified column.
delColMap.ceilingEntry(cell.getSequenceId()).getValue().addVersionDelete(cell);
break;
default:
throw new AssertionError("Unknown delete marker type for " + cell);
}
}
private boolean tagMatched(Cell put, TagInfo delInfo) throws IOException {
List putVisTags = new ArrayList<>();
Byte putCellVisTagsFormat = VisibilityUtils.extractVisibilityTags(put, putVisTags);
return putVisTags.isEmpty() == delInfo.tags.isEmpty() && (
(putVisTags.isEmpty() && delInfo.tags.isEmpty()) || VisibilityLabelServiceManager
.getInstance().getVisibilityLabelService()
.matchVisibility(putVisTags, putCellVisTagsFormat, delInfo.tags, delInfo.format));
}
@Override
public DeleteResult isDeleted(Cell cell) {
try {
long duplicateMvcc = prepare(cell);
for (Map.Entry e : delColMap.tailMap(cell.getSequenceId())
.entrySet()) {
VisibilityDeleteVersionsNode node = (VisibilityDeleteVersionsNode) e.getValue();
long deleteMvcc = Long.MAX_VALUE;
SortedMap deleteVersionMvccs = node.deletesMap.get(cell.getTimestamp());
if (deleteVersionMvccs != null) {
SortedMap tail = deleteVersionMvccs.tailMap(cell.getSequenceId());
for (Map.Entry entry : tail.entrySet()) {
if (tagMatched(cell, entry.getValue())) {
deleteMvcc = tail.firstKey();
break;
}
}
}
SortedMap> subMap = node.mvccCountingMap
.subMap(cell.getSequenceId(), true, Math.min(duplicateMvcc, deleteMvcc), true);
for (Map.Entry> seg : subMap.entrySet()) {
if (seg.getValue().size() >= maxVersions) {
return DeleteResult.VERSION_MASKED;
}
seg.getValue().add(cell.getSequenceId());
}
if (deleteMvcc < Long.MAX_VALUE) {
return DeleteResult.VERSION_DELETED;
}
if (cell.getTimestamp() <= node.ts && tagMatched(cell, node.tagInfo)) {
return DeleteResult.COLUMN_DELETED;
}
}
if (duplicateMvcc < Long.MAX_VALUE) {
return DeleteResult.VERSION_MASKED;
}
} catch (IOException e) {
LOG.error("Error in isDeleted() check! Will treat cell as not deleted", e);
}
return DeleteResult.NOT_DELETED;
}
@Override
protected void resetInternal() {
delFamMap.put(Long.MAX_VALUE,
new VisibilityDeleteVersionsNode(Long.MIN_VALUE, Long.MAX_VALUE, new TagInfo()));
}
}