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