View Javadoc

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