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.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.hadoop.hbase.HConstants;
26  import org.apache.hadoop.hbase.regionserver.ScanQueryMatcher.MatchCode;
27  import org.apache.hadoop.hbase.util.Bytes;
28  
29  /**
30   * Keeps track of the columns for a scan if they are not explicitly specified
31   */
32  public class ScanWildcardColumnTracker implements ColumnTracker {
33    private static final Log LOG =
34      LogFactory.getLog(ScanWildcardColumnTracker.class);
35    private byte [] columnBuffer = null;
36    private int columnOffset = 0;
37    private int columnLength = 0;
38    private int currentCount = 0;
39    private int maxVersions;
40    /* Keeps track of the latest timestamp included for current column.
41     * Used to eliminate duplicates. */
42    private long latestTSOfCurrentColumn;
43  
44    /**
45     * Return maxVersions of every row.
46     * @param maxVersion
47     */
48    public ScanWildcardColumnTracker(int maxVersion) {
49      this.maxVersions = maxVersion;
50    }
51  
52    /**
53     * Can only return INCLUDE or SKIP, since returning "NEXT" or
54     * "DONE" would imply we have finished with this row, when
55     * this class can't figure that out.
56     *
57     * @param bytes
58     * @param offset
59     * @param length
60     * @param timestamp
61     * @return The match code instance.
62     */
63    @Override
64    public MatchCode checkColumn(byte[] bytes, int offset, int length,
65        long timestamp) {
66      if (columnBuffer == null) {
67        // first iteration.
68        columnBuffer = bytes;
69        columnOffset = offset;
70        columnLength = length;
71        currentCount = 0;
72  
73        if (++currentCount > maxVersions) {
74          return ScanQueryMatcher.MatchCode.SEEK_NEXT_COL;
75        }
76        setTS(timestamp);
77        return ScanQueryMatcher.MatchCode.INCLUDE;
78      }
79      int cmp = Bytes.compareTo(bytes, offset, length,
80          columnBuffer, columnOffset, columnLength);
81      if (cmp == 0) {
82        //If column matches, check if it is a duplicate timestamp
83        if (sameAsPreviousTS(timestamp)) {
84          return ScanQueryMatcher.MatchCode.SKIP;
85        }
86        if (++currentCount > maxVersions) {
87          return ScanQueryMatcher.MatchCode.SEEK_NEXT_COL; // skip to next col
88        }
89        setTS(timestamp);
90        return ScanQueryMatcher.MatchCode.INCLUDE;
91      }
92  
93      resetTS();
94  
95      // new col > old col
96      if (cmp > 0) {
97        // switched columns, lets do something.x
98        columnBuffer = bytes;
99        columnOffset = offset;
100       columnLength = length;
101       currentCount = 0;
102       if (++currentCount > maxVersions)
103         return ScanQueryMatcher.MatchCode.SEEK_NEXT_COL;
104       setTS(timestamp);
105       return ScanQueryMatcher.MatchCode.INCLUDE;
106     }
107 
108     // new col < oldcol
109     // if (cmp < 0) {
110     // WARNING: This means that very likely an edit for some other family
111     // was incorrectly stored into the store for this one. Continue, but
112     // complain.
113     LOG.error("ScanWildcardColumnTracker.checkColumn ran " +
114   		"into a column actually smaller than the previous column: " +
115       Bytes.toStringBinary(bytes, offset, length));
116     // switched columns
117     columnBuffer = bytes;
118     columnOffset = offset;
119     columnLength = length;
120     currentCount = 0;
121     if (++currentCount > maxVersions) {
122       return ScanQueryMatcher.MatchCode.SEEK_NEXT_COL;
123     }
124     setTS(timestamp);
125     return ScanQueryMatcher.MatchCode.INCLUDE;
126   }
127 
128   @Override
129   public void update() {
130     // no-op, shouldn't even be called
131     throw new UnsupportedOperationException(
132         "ScanWildcardColumnTracker.update should never be called!");
133   }
134 
135   @Override
136   public void reset() {
137     columnBuffer = null;
138     resetTS();
139   }
140 
141   private void resetTS() {
142     latestTSOfCurrentColumn = HConstants.LATEST_TIMESTAMP;
143   }
144 
145   private void setTS(long timestamp) {
146     latestTSOfCurrentColumn = timestamp;
147   }
148 
149   private boolean sameAsPreviousTS(long timestamp) {
150     return timestamp == latestTSOfCurrentColumn;
151   }
152 
153   /**
154    * Used by matcher and scan/get to get a hint of the next column
155    * to seek to after checkColumn() returns SKIP.  Returns the next interesting
156    * column we want, or NULL there is none (wildcard scanner).
157    *
158    * @return The column count.
159    */
160   public ColumnCount getColumnHint() {
161     return null;
162   }
163 
164 
165   /**
166    * We can never know a-priori if we are done, so always return false.
167    * @return false
168    */
169   @Override
170   public boolean done() {
171     return false;
172   }
173 }