View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.coprocessor;
19  
20  import java.io.IOException;
21  import java.lang.reflect.InvocationTargetException;
22  import java.lang.reflect.Method;
23  
24  import org.apache.hadoop.classification.InterfaceAudience;
25  import org.apache.hadoop.classification.InterfaceStability;
26  import org.apache.hadoop.hbase.Coprocessor;
27  import org.apache.hadoop.hbase.CoprocessorEnvironment;
28  import org.apache.hadoop.hbase.protobuf.ResponseConverter;
29  import org.apache.hadoop.hbase.protobuf.generated.RowProcessorProtos.RowProcessorRequest;
30  import org.apache.hadoop.hbase.protobuf.generated.RowProcessorProtos.RowProcessorResult;
31  import org.apache.hadoop.hbase.protobuf.generated.RowProcessorProtos.RowProcessorService;
32  import org.apache.hadoop.hbase.regionserver.HRegion;
33  import org.apache.hadoop.hbase.regionserver.RowProcessor;
34  
35  import com.google.protobuf.ByteString;
36  import com.google.protobuf.Message;
37  import com.google.protobuf.RpcCallback;
38  import com.google.protobuf.RpcController;
39  import com.google.protobuf.Service;
40  
41  /**
42   * This class demonstrates how to implement atomic read-modify-writes
43   * using {@link HRegion#processRowsWithLocks} and Coprocessor endpoints.
44   */
45  @InterfaceAudience.Public
46  @InterfaceStability.Evolving
47  public abstract class BaseRowProcessorEndpoint<S extends Message, T extends Message> 
48  extends RowProcessorService implements CoprocessorService, Coprocessor {
49    private RegionCoprocessorEnvironment env;
50    /**
51     * Pass a processor to HRegion to process multiple rows atomically.
52     * 
53     * The RowProcessor implementations should be the inner classes of your
54     * RowProcessorEndpoint. This way the RowProcessor can be class-loaded with
55     * the Coprocessor endpoint together.
56     *
57     * See {@code TestRowProcessorEndpoint} for example.
58     *
59     * The request contains information for constructing processor 
60     * (see {@link #constructRowProcessorFromRequest}. The processor object defines
61     * the read-modify-write procedure.
62     */
63    @Override
64    public void process(RpcController controller, RowProcessorRequest request,
65        RpcCallback<RowProcessorResult> done) {
66      RowProcessorResult resultProto = null;
67      try {
68        RowProcessor<S,T> processor = constructRowProcessorFromRequest(request);
69        HRegion region = env.getRegion();
70        region.processRowsWithLocks(processor);
71        T result = processor.getResult();
72        RowProcessorResult.Builder b = RowProcessorResult.newBuilder();
73        b.setRowProcessorResult(result.toByteString()); 
74        resultProto = b.build();
75      } catch (Exception e) {
76        ResponseConverter.setControllerException(controller, new IOException(e));
77      }
78      done.run(resultProto);
79    }
80  
81    @Override
82    public Service getService() {
83      return this;
84    }
85  
86    /**
87     * Stores a reference to the coprocessor environment provided by the
88     * {@link org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost} from the region where this
89     * coprocessor is loaded.  Since this is a coprocessor endpoint, it always expects to be loaded
90     * on a table region, so always expects this to be an instance of
91     * {@link RegionCoprocessorEnvironment}.
92     * @param env the environment provided by the coprocessor host
93     * @throws IOException if the provided environment is not an instance of
94     * {@code RegionCoprocessorEnvironment}
95     */
96    @Override
97    public void start(CoprocessorEnvironment env) throws IOException {
98      if (env instanceof RegionCoprocessorEnvironment) {
99        this.env = (RegionCoprocessorEnvironment)env;
100     } else {
101       throw new CoprocessorException("Must be loaded on a table region!");
102     }
103   }
104 
105   @Override
106   public void stop(CoprocessorEnvironment env) throws IOException {
107     // nothing to do
108   }
109 
110   @SuppressWarnings("unchecked")
111   RowProcessor<S,T> constructRowProcessorFromRequest(RowProcessorRequest request)
112       throws IOException {
113     String className = request.getRowProcessorClassName();
114     Class<?> cls;
115     try {
116       cls = Class.forName(className);
117       RowProcessor<S,T> ci = (RowProcessor<S,T>) cls.newInstance();
118       if (request.hasRowProcessorInitializerMessageName()) {
119         Class<?> imn = Class.forName(request.getRowProcessorInitializerMessageName())
120             .asSubclass(Message.class);
121         Method m;
122         try {
123           m = imn.getMethod("parseFrom", ByteString.class);
124         } catch (SecurityException e) {
125           throw new IOException(e);
126         } catch (NoSuchMethodException e) {
127           throw new IOException(e);
128         }
129         S s;
130         try {
131           s = (S)m.invoke(null,request.getRowProcessorInitializerMessage());
132         } catch (IllegalArgumentException e) {
133           throw new IOException(e);
134         } catch (InvocationTargetException e) {
135           throw new IOException(e);
136         }
137         ci.initialize(s);
138       }
139       return ci;
140     } catch (ClassNotFoundException e) {
141       throw new IOException(e);
142     } catch (InstantiationException e) {
143       throw new IOException(e);
144     } catch (IllegalAccessException e) {
145       throw new IOException(e);
146     }
147   }
148 }