1 /** 2 * Copyright 2010 The Apache Software Foundation 3 * 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package org.apache.hadoop.hbase.regionserver; 22 23 import org.apache.hadoop.hbase.KeyValue; 24 import org.apache.hadoop.hbase.util.Bytes; 25 26 /** 27 * This class is responsible for the tracking and enforcement of Deletes 28 * during the course of a Scan operation. 29 * 30 * It only has to enforce Delete and DeleteColumn, since the 31 * DeleteFamily is handled at a higher level. 32 * 33 * <p> 34 * This class is utilized through three methods: 35 * <ul><li>{@link #add} when encountering a Delete or DeleteColumn 36 * <li>{@link #isDeleted} when checking if a Put KeyValue has been deleted 37 * <li>{@link #update} when reaching the end of a StoreFile or row for scans 38 * <p> 39 * This class is NOT thread-safe as queries are never multi-threaded 40 */ 41 public class ScanDeleteTracker implements DeleteTracker { 42 43 private long familyStamp = -1L; 44 private byte [] deleteBuffer = null; 45 private int deleteOffset = 0; 46 private int deleteLength = 0; 47 private byte deleteType = 0; 48 private long deleteTimestamp = 0L; 49 50 /** 51 * Constructor for ScanDeleteTracker 52 */ 53 public ScanDeleteTracker() { 54 super(); 55 } 56 57 /** 58 * Add the specified KeyValue to the list of deletes to check against for 59 * this row operation. 60 * <p> 61 * This is called when a Delete is encountered in a StoreFile. 62 * @param buffer KeyValue buffer 63 * @param qualifierOffset column qualifier offset 64 * @param qualifierLength column qualifier length 65 * @param timestamp timestamp 66 * @param type delete type as byte 67 */ 68 @Override 69 public void add(byte[] buffer, int qualifierOffset, int qualifierLength, 70 long timestamp, byte type) { 71 if (timestamp > familyStamp) { 72 if (type == KeyValue.Type.DeleteFamily.getCode()) { 73 familyStamp = timestamp; 74 return; 75 } 76 77 if (deleteBuffer != null && type < deleteType) { 78 // same column, so ignore less specific delete 79 if (Bytes.compareTo(deleteBuffer, deleteOffset, deleteLength, 80 buffer, qualifierOffset, qualifierLength) == 0){ 81 return; 82 } 83 } 84 // new column, or more general delete type 85 deleteBuffer = buffer; 86 deleteOffset = qualifierOffset; 87 deleteLength = qualifierLength; 88 deleteType = type; 89 deleteTimestamp = timestamp; 90 } 91 // missing else is never called. 92 } 93 94 /** 95 * Check if the specified KeyValue buffer has been deleted by a previously 96 * seen delete. 97 * 98 * @param buffer KeyValue buffer 99 * @param qualifierOffset column qualifier offset 100 * @param qualifierLength column qualifier length 101 * @param timestamp timestamp 102 * @return true is the specified KeyValue is deleted, false if not 103 */ 104 @Override 105 public boolean isDeleted(byte [] buffer, int qualifierOffset, 106 int qualifierLength, long timestamp) { 107 if (timestamp <= familyStamp) { 108 return true; 109 } 110 111 if (deleteBuffer != null) { 112 int ret = Bytes.compareTo(deleteBuffer, deleteOffset, deleteLength, 113 buffer, qualifierOffset, qualifierLength); 114 115 if (ret == 0) { 116 if (deleteType == KeyValue.Type.DeleteColumn.getCode()) { 117 return true; 118 } 119 // Delete (aka DeleteVersion) 120 // If the timestamp is the same, keep this one 121 if (timestamp == deleteTimestamp) { 122 return true; 123 } 124 // use assert or not? 125 assert timestamp < deleteTimestamp; 126 127 // different timestamp, let's clear the buffer. 128 deleteBuffer = null; 129 } else if(ret < 0){ 130 // Next column case. 131 deleteBuffer = null; 132 } else { 133 //Should never happen, throw Exception 134 } 135 } 136 137 return false; 138 } 139 140 @Override 141 public boolean isEmpty() { 142 return deleteBuffer == null && familyStamp == 0; 143 } 144 145 @Override 146 // called between every row. 147 public void reset() { 148 familyStamp = 0L; 149 deleteBuffer = null; 150 } 151 152 @Override 153 // should not be called at all even (!) 154 public void update() { 155 this.reset(); 156 } 157 }