Java tutorial
/** * * 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.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.Tag; import org.apache.hadoop.hbase.regionserver.querymatcher.NewVersionBehaviorTracker; /** * Similar to MvccSensitiveTracker but tracks the visibility expression also before * deciding if a Cell can be considered deleted */ public class VisibilityNewVersionBehaivorTracker extends NewVersionBehaviorTracker { private static final Log LOG = LogFactory.getLog(VisibilityNewVersionBehaivorTracker.class); public VisibilityNewVersionBehaivorTracker(NavigableSet<byte[]> columns, int minVersion, int maxVersion, int resultMaxVersions, long oldestUnexpiredTS) { super(columns, minVersion, maxVersion, resultMaxVersions, oldestUnexpiredTS); } private static class TagInfo { List<Tag> 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; // <timestamp, set<mvcc>> // Key is ts of version deletes, value is its mvccs. // We may delete more than one time for a version. private Map<Long, SortedMap<Long, TagInfo>> deletesMap = new HashMap<>(); // <mvcc, set<mvcc>> // Key is mvcc of version deletes, value is mvcc of visible puts before the delete effect. private NavigableMap<Long, SortedSet<Long>> 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<Long>()); } protected VisibilityDeleteVersionsNode getDeepCopy() { VisibilityDeleteVersionsNode node = new VisibilityDeleteVersionsNode(ts, mvcc, tagInfo); for (Map.Entry<Long, SortedMap<Long, TagInfo>> e : deletesMap.entrySet()) { node.deletesMap.put(e.getKey(), new TreeMap<>(e.getValue())); } for (Map.Entry<Long, SortedSet<Long>> e : mvccCountingMap.entrySet()) { node.mvccCountingMap.put(e.getKey(), new TreeSet<>(e.getValue())); } return node; } public void addVersionDelete(Cell cell) { SortedMap<Long, TagInfo> 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<Long> nextValue = mvccCountingMap.ceilingEntry(cell.getSequenceId()).getValue(); SortedSet<Long> 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<Tag> 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<Long, DeleteVersionsNode> e : delColMap.tailMap(cell.getSequenceId()).entrySet()) { VisibilityDeleteVersionsNode node = (VisibilityDeleteVersionsNode) e.getValue(); long deleteMvcc = Long.MAX_VALUE; SortedMap<Long, TagInfo> deleteVersionMvccs = node.deletesMap.get(cell.getTimestamp()); if (deleteVersionMvccs != null) { SortedMap<Long, TagInfo> tail = deleteVersionMvccs.tailMap(cell.getSequenceId()); for (Map.Entry<Long, TagInfo> entry : tail.entrySet()) { if (tagMatched(cell, entry.getValue())) { deleteMvcc = tail.firstKey(); break; } } } SortedMap<Long, SortedSet<Long>> subMap = node.mvccCountingMap.subMap(cell.getSequenceId(), true, Math.min(duplicateMvcc, deleteMvcc), true); for (Map.Entry<Long, SortedSet<Long>> 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; } protected void resetInternal() { delFamMap.put(Long.MAX_VALUE, new VisibilityDeleteVersionsNode(Long.MIN_VALUE, Long.MAX_VALUE, new TagInfo())); } }