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.exceptions.CoprocessorException;
29  import org.apache.hadoop.hbase.protobuf.ResponseConverter;
30  import org.apache.hadoop.hbase.protobuf.generated.RowProcessorProtos.RowProcessorRequest;
31  import org.apache.hadoop.hbase.protobuf.generated.RowProcessorProtos.RowProcessorResult;
32  import org.apache.hadoop.hbase.protobuf.generated.RowProcessorProtos.RowProcessorService;
33  import org.apache.hadoop.hbase.regionserver.HRegion;
34  import org.apache.hadoop.hbase.regionserver.RowProcessor;
35  
36  import com.google.protobuf.ByteString;
37  import com.google.protobuf.Message;
38  import com.google.protobuf.RpcCallback;
39  import com.google.protobuf.RpcController;
40  import com.google.protobuf.Service;
41  
42  /**
43   * This class demonstrates how to implement atomic read-modify-writes
44   * using {@link HRegion#processRowsWithLocks} and Coprocessor endpoints.
45   */
46  @InterfaceAudience.Public
47  @InterfaceStability.Evolving
48  public abstract class BaseRowProcessorEndpoint<S extends Message, T extends Message> 
49  extends RowProcessorService implements CoprocessorService, Coprocessor {
50    private RegionCoprocessorEnvironment env;
51    /**
52     * Pass a processor to HRegion to process multiple rows atomically.
53     * 
54     * The RowProcessor implementations should be the inner classes of your
55     * RowProcessorEndpoint. This way the RowProcessor can be class-loaded with
56     * the Coprocessor endpoint together.
57     *
58     * See {@code TestRowProcessorEndpoint} for example.
59     *
60     * The request contains information for constructing processor 
61     * (see {@link #constructRowProcessorFromRequest}. The processor object defines
62     * the read-modify-write procedure.
63     */
64    @Override
65    public void process(RpcController controller, RowProcessorRequest request,
66        RpcCallback<RowProcessorResult> done) {
67      RowProcessorResult resultProto = null;
68      try {
69        RowProcessor<S,T> processor = constructRowProcessorFromRequest(request);
70        HRegion region = env.getRegion();
71        region.processRowsWithLocks(processor);
72        T result = processor.getResult();
73        RowProcessorResult.Builder b = RowProcessorResult.newBuilder();
74        b.setRowProcessorResult(result.toByteString()); 
75        resultProto = b.build();
76      } catch (Exception e) {
77        ResponseConverter.setControllerException(controller, new IOException(e));
78      }
79      done.run(resultProto);
80    }
81  
82    @Override
83    public Service getService() {
84      return this;
85    }
86  
87    /**
88     * Stores a reference to the coprocessor environment provided by the
89     * {@link org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost} from the region where this
90     * coprocessor is loaded.  Since this is a coprocessor endpoint, it always expects to be loaded
91     * on a table region, so always expects this to be an instance of
92     * {@link RegionCoprocessorEnvironment}.
93     * @param env the environment provided by the coprocessor host
94     * @throws IOException if the provided environment is not an instance of
95     * {@code RegionCoprocessorEnvironment}
96     */
97    @Override
98    public void start(CoprocessorEnvironment env) throws IOException {
99      if (env instanceof RegionCoprocessorEnvironment) {
100       this.env = (RegionCoprocessorEnvironment)env;
101     } else {
102       throw new CoprocessorException("Must be loaded on a table region!");
103     }
104   }
105 
106   @Override
107   public void stop(CoprocessorEnvironment env) throws IOException {
108     // nothing to do
109   }
110 
111   @SuppressWarnings("unchecked")
112   RowProcessor<S,T> constructRowProcessorFromRequest(RowProcessorRequest request)
113       throws IOException {
114     String className = request.getRowProcessorClassName();
115     Class<?> cls;
116     try {
117       cls = Class.forName(className);
118       RowProcessor<S,T> ci = (RowProcessor<S,T>) cls.newInstance();
119       if (request.hasRowProcessorInitializerMessageName()) {
120         Class<?> imn = Class.forName(request.getRowProcessorInitializerMessageName())
121             .asSubclass(Message.class);
122         Method m;
123         try {
124           m = imn.getMethod("parseFrom", ByteString.class);
125         } catch (SecurityException e) {
126           throw new IOException(e);
127         } catch (NoSuchMethodException e) {
128           throw new IOException(e);
129         }
130         S s;
131         try {
132           s = (S)m.invoke(null,request.getRowProcessorInitializerMessage());
133         } catch (IllegalArgumentException e) {
134           throw new IOException(e);
135         } catch (InvocationTargetException e) {
136           throw new IOException(e);
137         }
138         ci.initialize(s);
139       }
140       return ci;
141     } catch (ClassNotFoundException e) {
142       throw new IOException(e);
143     } catch (InstantiationException e) {
144       throw new IOException(e);
145     } catch (IllegalAccessException e) {
146       throw new IOException(e);
147     }
148   }
149 }