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  
19  package org.apache.hadoop.hbase.coprocessor.example;
20  
21  import com.google.protobuf.RpcCallback;
22  import com.google.protobuf.RpcController;
23  import com.google.protobuf.Service;
24  import org.apache.hadoop.hbase.Coprocessor;
25  import org.apache.hadoop.hbase.CoprocessorEnvironment;
26  import org.apache.hadoop.hbase.KeyValue;
27  import org.apache.hadoop.hbase.client.Scan;
28  import org.apache.hadoop.hbase.coprocessor.CoprocessorException;
29  import org.apache.hadoop.hbase.coprocessor.CoprocessorService;
30  import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
31  import org.apache.hadoop.hbase.coprocessor.example.generated.ExampleProtos;
32  import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
33  import org.apache.hadoop.hbase.protobuf.ResponseConverter;
34  import org.apache.hadoop.hbase.regionserver.InternalScanner;
35  import org.apache.hadoop.hbase.util.Bytes;
36  
37  import java.io.IOException;
38  import java.util.ArrayList;
39  import java.util.List;
40  
41  /**
42   * Sample coprocessor endpoint exposing a Service interface for counting rows and key values.
43   *
44   * <p>
45   * For the protocol buffer definition of the RowCountService, see the source file located under
46   * hbase-server/src/main/protobuf/Examples.proto.
47   * </p>
48   */
49  public class RowCountEndpoint extends ExampleProtos.RowCountService
50      implements Coprocessor, CoprocessorService {
51    private RegionCoprocessorEnvironment env;
52  
53    public RowCountEndpoint() {
54    }
55  
56    /**
57     * Just returns a reference to this object, which implements the RowCounterService interface.
58     */
59    @Override
60    public Service getService() {
61      return this;
62    }
63  
64    /**
65     * Returns a count of the rows in the region where this coprocessor is loaded.
66     */
67    @Override
68    public void getRowCount(RpcController controller, ExampleProtos.CountRequest request,
69                            RpcCallback<ExampleProtos.CountResponse> done) {
70      Scan scan = new Scan();
71      scan.setFilter(new FirstKeyOnlyFilter());
72      ExampleProtos.CountResponse response = null;
73      InternalScanner scanner = null;
74      try {
75        scanner = env.getRegion().getScanner(scan);
76        List<KeyValue> results = new ArrayList<KeyValue>();
77        boolean hasMore = false;
78        byte[] lastRow = null;
79        long count = 0;
80        do {
81          hasMore = scanner.next(results);
82          for (KeyValue kv : results) {
83            byte[] currentRow = kv.getRow();
84            if (lastRow == null || !Bytes.equals(lastRow, currentRow)) {
85              lastRow = currentRow;
86              count++;
87            }
88          }
89          results.clear();
90        } while (hasMore);
91  
92        response = ExampleProtos.CountResponse.newBuilder()
93            .setCount(count).build();
94      } catch (IOException ioe) {
95        ResponseConverter.setControllerException(controller, ioe);
96      } finally {
97        if (scanner != null) {
98          try {
99            scanner.close();
100         } catch (IOException ignored) {}
101       }
102     }
103     done.run(response);
104   }
105 
106   /**
107    * Returns a count of all KeyValues in the region where this coprocessor is loaded.
108    */
109   @Override
110   public void getKeyValueCount(RpcController controller, ExampleProtos.CountRequest request,
111                                RpcCallback<ExampleProtos.CountResponse> done) {
112     ExampleProtos.CountResponse response = null;
113     InternalScanner scanner = null;
114     try {
115       scanner = env.getRegion().getScanner(new Scan());
116       List<KeyValue> results = new ArrayList<KeyValue>();
117       boolean hasMore = false;
118       long count = 0;
119       do {
120         hasMore = scanner.next(results);
121         for (KeyValue kv : results) {
122           count++;
123         }
124         results.clear();
125       } while (hasMore);
126 
127       response = ExampleProtos.CountResponse.newBuilder()
128           .setCount(count).build();
129     } catch (IOException ioe) {
130       ResponseConverter.setControllerException(controller, ioe);
131     } finally {
132       if (scanner != null) {
133         try {
134           scanner.close();
135         } catch (IOException ignored) {}
136       }
137     }
138     done.run(response);
139   }
140 
141   /**
142    * Stores a reference to the coprocessor environment provided by the
143    * {@link org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost} from the region where this
144    * coprocessor is loaded.  Since this is a coprocessor endpoint, it always expects to be loaded
145    * on a table region, so always expects this to be an instance of
146    * {@link RegionCoprocessorEnvironment}.
147    * @param env the environment provided by the coprocessor host
148    * @throws IOException if the provided environment is not an instance of
149    * {@code RegionCoprocessorEnvironment}
150    */
151   @Override
152   public void start(CoprocessorEnvironment env) throws IOException {
153     if (env instanceof RegionCoprocessorEnvironment) {
154       this.env = (RegionCoprocessorEnvironment)env;
155     } else {
156       throw new CoprocessorException("Must be loaded on a table region!");
157     }
158   }
159 
160   @Override
161   public void stop(CoprocessorEnvironment env) throws IOException {
162     // nothing to do
163   }
164 }