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  package org.apache.hadoop.hbase.filter;
21  
22  import java.io.DataInput;
23  import java.io.DataOutput;
24  import java.io.IOException;
25  import java.util.HashSet;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Set;
29  
30  import org.apache.hadoop.hbase.KeyValue;
31  import org.apache.hadoop.hbase.util.Bytes;
32  
33  /**
34   * A filter for adding inter-column timestamp matching
35   * Only cells with a correspondingly timestamped entry in
36   * the target column will be retained
37   * Not compatible with Scan.setBatch as operations need 
38   * full rows for correct filtering 
39   */
40  public class DependentColumnFilter extends CompareFilter {
41  
42    protected byte[] columnFamily;
43    protected byte[] columnQualifier;
44    protected boolean dropDependentColumn;
45  
46    protected Set<Long> stampSet = new HashSet<Long>();
47    
48    /**
49     * Should only be used for writable
50     */
51    public DependentColumnFilter() {
52    }
53    
54    /**
55     * Build a dependent column filter with value checking
56     * dependent column varies will be compared using the supplied
57     * compareOp and comparator, for usage of which
58     * refer to {@link CompareFilter}
59     * 
60     * @param family dependent column family
61     * @param qualifier dependent column qualifier
62     * @param dropDependentColumn whether the column should be discarded after
63     * @param valueCompareOp comparison op 
64     * @param valueComparator comparator
65     */
66    public DependentColumnFilter(final byte [] family, final byte[] qualifier,
67  		  final boolean dropDependentColumn, final CompareOp valueCompareOp,
68  	      final WritableByteArrayComparable valueComparator) {
69      // set up the comparator   
70      super(valueCompareOp, valueComparator);
71      this.columnFamily = family;
72      this.columnQualifier = qualifier;
73      this.dropDependentColumn = dropDependentColumn;
74    }
75    
76    /**
77     * Constructor for DependentColumn filter.
78     * Keyvalues where a keyvalue from target column 
79     * with the same timestamp do not exist will be dropped. 
80     * 
81     * @param family name of target column family
82     * @param qualifier name of column qualifier
83     */
84    public DependentColumnFilter(final byte [] family, final byte [] qualifier) {
85      this(family, qualifier, false);
86    }
87    
88    /**
89     * Constructor for DependentColumn filter.
90     * Keyvalues where a keyvalue from target column 
91     * with the same timestamp do not exist will be dropped. 
92     * 
93     * @param family name of dependent column family
94     * @param qualifier name of dependent qualifier
95     * @param dropDependentColumn whether the dependent columns keyvalues should be discarded
96     */
97    public DependentColumnFilter(final byte [] family, final byte [] qualifier,
98        final boolean dropDependentColumn) {
99      this(family, qualifier, dropDependentColumn, CompareOp.NO_OP, null);
100   }
101   
102   
103   @Override
104   public boolean filterAllRemaining() {
105     return false;
106   }
107 
108   @Override
109   public ReturnCode filterKeyValue(KeyValue v) {
110     // Check if the column and qualifier match
111   	if (!v.matchingColumn(this.columnFamily, this.columnQualifier)) {
112         // include non-matches for the time being, they'll be discarded afterwards
113         return ReturnCode.INCLUDE;
114   	}
115   	// If it doesn't pass the op, skip it
116   	if(comparator != null && doCompare(compareOp, comparator, v.getValue(), 0, v.getValueLength()))
117   	  return ReturnCode.SKIP;  	  
118 	
119     stampSet.add(v.getTimestamp());
120     if(dropDependentColumn) {
121     	return ReturnCode.SKIP;
122     }
123     return ReturnCode.INCLUDE;
124   }
125 
126   @Override
127   public void filterRow(List<KeyValue> kvs) {
128     Iterator<KeyValue> it = kvs.iterator();
129     KeyValue kv;
130     while(it.hasNext()) {
131       kv = it.next();
132       if(!stampSet.contains(kv.getTimestamp())) {
133         it.remove();
134       }
135     }
136   }
137 
138   @Override
139   public boolean hasFilterRow() {
140     return true;
141   }
142   
143   @Override
144   public boolean filterRow() {
145     return false;
146   }
147 
148   @Override
149   public boolean filterRowKey(byte[] buffer, int offset, int length) {
150     return false;
151   }
152 
153   @Override
154   public void reset() {
155     stampSet.clear();    
156   }
157 
158   @Override
159   public void readFields(DataInput in) throws IOException {
160 	super.readFields(in);
161     this.columnFamily = Bytes.readByteArray(in);
162 	if(this.columnFamily.length == 0) {
163 	  this.columnFamily = null;
164 	}
165     
166     this.columnQualifier = Bytes.readByteArray(in);
167     if(this.columnQualifier.length == 0) {
168       this.columnQualifier = null;
169     }	
170     
171     this.dropDependentColumn = in.readBoolean();
172   }
173 
174   @Override
175   public void write(DataOutput out) throws IOException {
176     super.write(out);
177     Bytes.writeByteArray(out, this.columnFamily);
178     Bytes.writeByteArray(out, this.columnQualifier);
179     out.writeBoolean(this.dropDependentColumn);    
180   }
181 
182 }