View Javadoc

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.equals(deleteBuffer, deleteOffset, deleteLength,
80              buffer, qualifierOffset, qualifierLength)){
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         throw new IllegalStateException("isDelete failed: deleteBuffer="
134             + Bytes.toStringBinary(deleteBuffer, deleteOffset, deleteLength)
135             + ", qualifier="
136             + Bytes.toStringBinary(buffer, qualifierOffset, qualifierLength)
137             + ", timestamp=" + timestamp + ", comparison result: " + ret);
138       }
139     }
140 
141     return false;
142   }
143 
144   @Override
145   public boolean isEmpty() {
146     return deleteBuffer == null && familyStamp == 0;
147   }
148 
149   @Override
150   // called between every row.
151   public void reset() {
152     familyStamp = 0L;
153     deleteBuffer = null;
154   }
155 
156   @Override
157   // should not be called at all even (!)
158   public void update() {
159     this.reset();
160   }
161 }