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.coprocessor;
21  
22  import java.io.IOException;
23  import java.util.List;
24  import java.util.Arrays;
25  
26  import org.apache.hadoop.fs.Path;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  
30  import org.apache.hadoop.hbase.Cell;
31  import org.apache.hadoop.hbase.HRegionInfo;
32  import org.apache.hadoop.hbase.KeyValue;
33  import org.apache.hadoop.hbase.regionserver.wal.HLogKey;
34  import org.apache.hadoop.hbase.wal.WALKey;
35  import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
36  import org.apache.hadoop.hbase.util.Bytes;
37  
38  /**
39   * Class for testing WALObserver coprocessor.
40   *
41   * It will monitor WAL writing and restoring, and modify passed-in WALEdit, i.e,
42   * ignore specified columns when writing, or add a KeyValue. On the other
43   * side, it checks whether the ignored column is still in WAL when Restoreed
44   * at region reconstruct.
45   */
46  public class SampleRegionWALObserver extends BaseRegionObserver
47  implements WALObserver {
48  
49    private static final Log LOG = LogFactory.getLog(SampleRegionWALObserver.class);
50  
51    private byte[] tableName;
52    private byte[] row;
53    private byte[] ignoredFamily;
54    private byte[] ignoredQualifier;
55    private byte[] addedFamily;
56    private byte[] addedQualifier;
57    private byte[] changedFamily;
58    private byte[] changedQualifier;
59  
60    private boolean preWALWriteCalled = false;
61    private boolean postWALWriteCalled = false;
62    private boolean preWALRestoreCalled = false;
63    private boolean postWALRestoreCalled = false;
64    private boolean preWALRollCalled = false;
65    private boolean postWALRollCalled = false;
66  
67    // Deprecated versions
68    private boolean preWALWriteDeprecatedCalled = false;
69    private boolean postWALWriteDeprecatedCalled = false;
70    private boolean preWALRestoreDeprecatedCalled = false;
71    private boolean postWALRestoreDeprecatedCalled = false;
72  
73    /**
74     * Set values: with a table name, a column name which will be ignored, and
75     * a column name which will be added to WAL.
76     */
77    public void setTestValues(byte[] tableName, byte[] row, byte[] igf, byte[] igq,
78        byte[] chf, byte[] chq, byte[] addf, byte[] addq) {
79      this.row = row;
80      this.tableName = tableName;
81      this.ignoredFamily = igf;
82      this.ignoredQualifier = igq;
83      this.addedFamily = addf;
84      this.addedQualifier = addq;
85      this.changedFamily = chf;
86      this.changedQualifier = chq;
87      preWALWriteCalled = false;
88      postWALWriteCalled = false;
89      preWALRestoreCalled = false;
90      postWALRestoreCalled = false;
91      preWALWriteDeprecatedCalled = false;
92      postWALWriteDeprecatedCalled = false;
93      preWALRestoreDeprecatedCalled = false;
94      postWALRestoreDeprecatedCalled = false;
95      preWALRollCalled = false;
96      postWALRollCalled = false;
97    }
98  
99    @Override
100   public void postWALWrite(ObserverContext<? extends WALCoprocessorEnvironment> env,
101       HRegionInfo info, WALKey logKey, WALEdit logEdit) throws IOException {
102     postWALWriteCalled = true;
103   }
104 
105   @Override
106   public void postWALWrite(ObserverContext<WALCoprocessorEnvironment> env,
107       HRegionInfo info, HLogKey logKey, WALEdit logEdit) throws IOException {
108     postWALWriteDeprecatedCalled = true;
109     postWALWrite(env, info, (WALKey)logKey, logEdit);
110   }
111 
112   @Override
113   public boolean preWALWrite(ObserverContext<? extends WALCoprocessorEnvironment> env,
114       HRegionInfo info, WALKey logKey, WALEdit logEdit) throws IOException {
115     boolean bypass = false;
116     // check table name matches or not.
117     if (!Bytes.equals(info.getTableName(), this.tableName)) {
118       return bypass;
119     }
120     preWALWriteCalled = true;
121     // here we're going to remove one keyvalue from the WALEdit, and add
122     // another one to it.
123     List<Cell> cells = logEdit.getCells();
124     Cell deletedCell = null;
125     for (Cell cell : cells) {
126       // assume only one kv from the WALEdit matches.
127       byte[] family = cell.getFamily();
128       byte[] qulifier = cell.getQualifier();
129 
130       if (Arrays.equals(family, ignoredFamily) &&
131           Arrays.equals(qulifier, ignoredQualifier)) {
132         LOG.debug("Found the KeyValue from WALEdit which should be ignored.");
133         deletedCell = cell;
134       }
135       if (Arrays.equals(family, changedFamily) &&
136           Arrays.equals(qulifier, changedQualifier)) {
137         LOG.debug("Found the KeyValue from WALEdit which should be changed.");
138         cell.getValueArray()[cell.getValueOffset()] += 1;
139       }
140     }
141     if (null != row) {
142       cells.add(new KeyValue(row, addedFamily, addedQualifier));
143     }
144     if (deletedCell != null) {
145       LOG.debug("About to delete a KeyValue from WALEdit.");
146       cells.remove(deletedCell);
147     }
148     return bypass;
149   }
150 
151   @Override
152   public boolean preWALWrite(ObserverContext<WALCoprocessorEnvironment> env,
153       HRegionInfo info, HLogKey logKey, WALEdit logEdit) throws IOException {
154     preWALWriteDeprecatedCalled = true;
155     return preWALWrite(env, info, (WALKey)logKey, logEdit);
156   }
157 
158   /**
159    * Triggered before  {@link org.apache.hadoop.hbase.regionserver.HRegion} when WAL is
160    * Restoreed.
161    */
162   @Override
163   public void preWALRestore(ObserverContext<? extends RegionCoprocessorEnvironment> env,
164       HRegionInfo info, WALKey logKey, WALEdit logEdit) throws IOException {
165     preWALRestoreCalled = true;
166   }
167 
168   @Override
169   public void preWALRestore(ObserverContext<RegionCoprocessorEnvironment> env,
170       HRegionInfo info, HLogKey logKey, WALEdit logEdit) throws IOException {
171     preWALRestoreDeprecatedCalled = true;
172     preWALRestore(env, info, (WALKey)logKey, logEdit);
173   }
174 
175   @Override
176   public void preWALRoll(ObserverContext<? extends WALCoprocessorEnvironment> ctx,
177       Path oldPath, Path newPath) throws IOException {
178     preWALRollCalled = true;
179   }
180 
181   @Override
182   public void postWALRoll(ObserverContext<? extends WALCoprocessorEnvironment> ctx,
183       Path oldPath, Path newPath) throws IOException {
184     postWALRollCalled = true;
185   }
186 
187   /**
188    * Triggered after {@link org.apache.hadoop.hbase.regionserver.HRegion} when WAL is
189    * Restoreed.
190    */
191   @Override
192   public void postWALRestore(ObserverContext<? extends RegionCoprocessorEnvironment> env,
193       HRegionInfo info, WALKey logKey, WALEdit logEdit) throws IOException {
194     postWALRestoreCalled = true;
195   }
196 
197   @Override
198   public void postWALRestore(ObserverContext<RegionCoprocessorEnvironment> env,
199       HRegionInfo info, HLogKey logKey, WALEdit logEdit) throws IOException {
200     postWALRestoreDeprecatedCalled = true;
201     postWALRestore(env, info, (WALKey)logKey, logEdit);
202   }
203 
204   public boolean isPreWALWriteCalled() {
205     return preWALWriteCalled;
206   }
207 
208   public boolean isPostWALWriteCalled() {
209     return postWALWriteCalled;
210   }
211 
212   public boolean isPreWALRestoreCalled() {
213     LOG.debug(SampleRegionWALObserver.class.getName() +
214       ".isPreWALRestoreCalled is called.");
215     return preWALRestoreCalled;
216   }
217 
218   public boolean isPostWALRestoreCalled() {
219     LOG.debug(SampleRegionWALObserver.class.getName() +
220       ".isPostWALRestoreCalled is called.");
221     return postWALRestoreCalled;
222   }
223 
224   public boolean isPreWALWriteDeprecatedCalled() {
225     return preWALWriteDeprecatedCalled;
226   }
227 
228   public boolean isPostWALWriteDeprecatedCalled() {
229     return postWALWriteDeprecatedCalled;
230   }
231 
232   public boolean isPreWALRestoreDeprecatedCalled() {
233     return preWALRestoreDeprecatedCalled;
234   }
235 
236   public boolean isPostWALRestoreDeprecatedCalled() {
237     return postWALRestoreDeprecatedCalled;
238   }
239 
240   public boolean isPreWALRollCalled() {
241     return preWALRollCalled;
242   }
243 
244   public boolean isPostWALRollCalled() {
245     return postWALRollCalled;
246   }
247 
248   /**
249    * This class should trigger our legacy support since it does not directly implement the
250    * newer API methods.
251    */
252   static class Legacy extends SampleRegionWALObserver {
253   }
254 }