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.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 }