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.rest.client;
21  
22  import java.io.IOException;
23  import java.io.InterruptedIOException;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  import java.util.TreeMap;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.apache.hadoop.conf.Configuration;
35  import org.apache.hadoop.hbase.Cell;
36  import org.apache.hadoop.hbase.CellUtil;
37  import org.apache.hadoop.hbase.HBaseConfiguration;
38  import org.apache.hadoop.hbase.HConstants;
39  import org.apache.hadoop.hbase.HTableDescriptor;
40  import org.apache.hadoop.hbase.KeyValue;
41  import org.apache.hadoop.hbase.TableName;
42  import org.apache.hadoop.hbase.classification.InterfaceAudience;
43  import org.apache.hadoop.hbase.classification.InterfaceStability;
44  import org.apache.hadoop.hbase.client.Append;
45  import org.apache.hadoop.hbase.client.Delete;
46  import org.apache.hadoop.hbase.client.Durability;
47  import org.apache.hadoop.hbase.client.Get;
48  import org.apache.hadoop.hbase.client.Increment;
49  import org.apache.hadoop.hbase.client.Put;
50  import org.apache.hadoop.hbase.client.Result;
51  import org.apache.hadoop.hbase.client.ResultScanner;
52  import org.apache.hadoop.hbase.client.Row;
53  import org.apache.hadoop.hbase.client.RowMutations;
54  import org.apache.hadoop.hbase.client.Scan;
55  import org.apache.hadoop.hbase.client.Table;
56  import org.apache.hadoop.hbase.client.coprocessor.Batch;
57  import org.apache.hadoop.hbase.client.coprocessor.Batch.Callback;
58  import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
59  import org.apache.hadoop.hbase.io.TimeRange;
60  import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
61  import org.apache.hadoop.hbase.rest.Constants;
62  import org.apache.hadoop.hbase.rest.model.CellModel;
63  import org.apache.hadoop.hbase.rest.model.CellSetModel;
64  import org.apache.hadoop.hbase.rest.model.RowModel;
65  import org.apache.hadoop.hbase.rest.model.ScannerModel;
66  import org.apache.hadoop.hbase.rest.model.TableSchemaModel;
67  import org.apache.hadoop.hbase.util.Bytes;
68  import org.apache.hadoop.util.StringUtils;
69  
70  import com.google.protobuf.Descriptors;
71  import com.google.protobuf.Message;
72  import com.google.protobuf.Service;
73  import com.google.protobuf.ServiceException;
74  
75  /**
76   * HTable interface to remote tables accessed via REST gateway
77   */
78  @InterfaceAudience.Public
79  @InterfaceStability.Stable
80  public class RemoteHTable implements Table {
81  
82    private static final Log LOG = LogFactory.getLog(RemoteHTable.class);
83  
84    final Client client;
85    final Configuration conf;
86    final byte[] name;
87    final int maxRetries;
88    final long sleepTime;
89  
90    @SuppressWarnings("rawtypes")
91    protected String buildRowSpec(final byte[] row, final Map familyMap,
92        final long startTime, final long endTime, final int maxVersions) {
93      StringBuffer sb = new StringBuffer();
94      sb.append('/');
95      sb.append(Bytes.toStringBinary(name));
96      sb.append('/');
97      sb.append(Bytes.toStringBinary(row));
98      Set families = familyMap.entrySet();
99      if (families != null) {
100       Iterator i = familyMap.entrySet().iterator();
101       sb.append('/');
102       while (i.hasNext()) {
103         Map.Entry e = (Map.Entry)i.next();
104         Collection quals = (Collection)e.getValue();
105         if (quals == null || quals.isEmpty()) {
106           // this is an unqualified family. append the family name and NO ':'
107           sb.append(Bytes.toStringBinary((byte[])e.getKey()));
108         } else {
109           Iterator ii = quals.iterator();
110           while (ii.hasNext()) {
111             sb.append(Bytes.toStringBinary((byte[])e.getKey()));
112             sb.append(':');
113             Object o = ii.next();
114             // Puts use byte[] but Deletes use KeyValue
115             if (o instanceof byte[]) {
116               sb.append(Bytes.toStringBinary((byte[])o));
117             } else if (o instanceof KeyValue) {
118               sb.append(Bytes.toStringBinary(((KeyValue)o).getQualifier()));
119             } else {
120               throw new RuntimeException("object type not handled");
121             }
122             if (ii.hasNext()) {
123               sb.append(',');
124             }
125           }
126         }
127         if (i.hasNext()) {
128           sb.append(',');
129         }
130       }
131     }
132     if (startTime >= 0 && endTime != Long.MAX_VALUE) {
133       sb.append('/');
134       sb.append(startTime);
135       if (startTime != endTime) {
136         sb.append(',');
137         sb.append(endTime);
138       }
139     } else if (endTime != Long.MAX_VALUE) {
140       sb.append('/');
141       sb.append(endTime);
142     }
143     if (maxVersions > 1) {
144       sb.append("?v=");
145       sb.append(maxVersions);
146     }
147     return sb.toString();
148   }
149 
150   protected String buildMultiRowSpec(final byte[][] rows, int maxVersions) {
151     StringBuilder sb = new StringBuilder();
152     sb.append('/');
153     sb.append(Bytes.toStringBinary(name));
154     sb.append("/multiget/");
155     if (rows == null || rows.length == 0) {
156       return sb.toString();
157     }
158     sb.append("?");
159     for(int i=0; i<rows.length; i++) {
160       byte[] rk = rows[i];
161       if (i != 0) {
162         sb.append('&');
163       }
164       sb.append("row=");
165       sb.append(Bytes.toStringBinary(rk));
166     }
167     sb.append("&v=");
168     sb.append(maxVersions);
169 
170     return sb.toString();
171   }
172 
173   protected Result[] buildResultFromModel(final CellSetModel model) {
174     List<Result> results = new ArrayList<Result>();
175     for (RowModel row: model.getRows()) {
176       List<Cell> kvs = new ArrayList<Cell>();
177       for (CellModel cell: row.getCells()) {
178         byte[][] split = KeyValue.parseColumn(cell.getColumn());
179         byte[] column = split[0];
180         byte[] qualifier = null;
181         if (split.length == 1) {
182           qualifier = HConstants.EMPTY_BYTE_ARRAY;
183         } else if (split.length == 2) {
184           qualifier = split[1];
185         } else {
186           throw new IllegalArgumentException("Invalid familyAndQualifier provided.");
187         }
188         kvs.add(new KeyValue(row.getKey(), column, qualifier,
189           cell.getTimestamp(), cell.getValue()));
190       }
191       results.add(Result.create(kvs));
192     }
193     return results.toArray(new Result[results.size()]);
194   }
195 
196   protected CellSetModel buildModelFromPut(Put put) {
197     RowModel row = new RowModel(put.getRow());
198     long ts = put.getTimeStamp();
199     for (List<Cell> cells: put.getFamilyCellMap().values()) {
200       for (Cell cell: cells) {
201         row.addCell(new CellModel(CellUtil.cloneFamily(cell), CellUtil.cloneQualifier(cell),
202           ts != HConstants.LATEST_TIMESTAMP ? ts : cell.getTimestamp(),
203           CellUtil.cloneValue(cell)));
204       }
205     }
206     CellSetModel model = new CellSetModel();
207     model.addRow(row);
208     return model;
209   }
210 
211   /**
212    * Constructor
213    * @param client
214    * @param name
215    */
216   public RemoteHTable(Client client, String name) {
217     this(client, HBaseConfiguration.create(), Bytes.toBytes(name));
218   }
219 
220   /**
221    * Constructor
222    * @param client
223    * @param conf
224    * @param name
225    */
226   public RemoteHTable(Client client, Configuration conf, String name) {
227     this(client, conf, Bytes.toBytes(name));
228   }
229 
230   /**
231    * Constructor
232    * @param client
233    * @param conf
234    * @param name
235    */
236   public RemoteHTable(Client client, Configuration conf, byte[] name) {
237     this.client = client;
238     this.conf = conf;
239     this.name = name;
240     this.maxRetries = conf.getInt("hbase.rest.client.max.retries", 10);
241     this.sleepTime = conf.getLong("hbase.rest.client.sleep", 1000);
242   }
243 
244   public byte[] getTableName() {
245     return name.clone();
246   }
247 
248   @Override
249   public TableName getName() {
250     return TableName.valueOf(name);
251   }
252 
253   public Configuration getConfiguration() {
254     return conf;
255   }
256 
257   public HTableDescriptor getTableDescriptor() throws IOException {
258     StringBuilder sb = new StringBuilder();
259     sb.append('/');
260     sb.append(Bytes.toStringBinary(name));
261     sb.append('/');
262     sb.append("schema");
263     for (int i = 0; i < maxRetries; i++) {
264       Response response = client.get(sb.toString(), Constants.MIMETYPE_PROTOBUF);
265       int code = response.getCode();
266       switch (code) {
267       case 200:
268         TableSchemaModel schema = new TableSchemaModel();
269         schema.getObjectFromMessage(response.getBody());
270         return schema.getTableDescriptor();
271       case 509:
272         try {
273           Thread.sleep(sleepTime);
274         } catch (InterruptedException e) {
275           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
276         }
277         break;
278       default:
279         throw new IOException("schema request returned " + code);
280       }
281     }
282     throw new IOException("schema request timed out");
283   }
284 
285   public void close() throws IOException {
286     client.shutdown();
287   }
288 
289   public Result get(Get get) throws IOException {
290     TimeRange range = get.getTimeRange();
291     String spec = buildRowSpec(get.getRow(), get.getFamilyMap(),
292       range.getMin(), range.getMax(), get.getMaxVersions());
293     if (get.getFilter() != null) {
294       LOG.warn("filters not supported on gets");
295     }
296     Result[] results = getResults(spec);
297     if (results.length > 0) {
298       if (results.length > 1) {
299         LOG.warn("too many results for get (" + results.length + ")");
300       }
301       return results[0];
302     } else {
303       return new Result();
304     }
305   }
306 
307   public Result[] get(List<Get> gets) throws IOException {
308     byte[][] rows = new byte[gets.size()][];
309     int maxVersions = 1;
310     int count = 0;
311 
312     for(Get g:gets) {
313 
314       if ( count == 0 ) {
315         maxVersions = g.getMaxVersions();
316       } else if (g.getMaxVersions() != maxVersions) {
317         LOG.warn("MaxVersions on Gets do not match, using the first in the list ("+maxVersions+")");
318       }
319 
320       if (g.getFilter() != null) {
321         LOG.warn("filters not supported on gets");
322       }
323 
324       rows[count] = g.getRow();
325       count ++;
326     }
327 
328     String spec = buildMultiRowSpec(rows, maxVersions);
329 
330     return getResults(spec);
331   }
332 
333   private Result[] getResults(String spec) throws IOException {
334     for (int i = 0; i < maxRetries; i++) {
335       Response response = client.get(spec, Constants.MIMETYPE_PROTOBUF);
336       int code = response.getCode();
337       switch (code) {
338         case 200:
339           CellSetModel model = new CellSetModel();
340           model.getObjectFromMessage(response.getBody());
341           Result[] results = buildResultFromModel(model);
342           if ( results.length > 0) {
343             return results;
344           }
345           // fall through
346         case 404:
347           return new Result[0];
348 
349         case 509:
350           try {
351             Thread.sleep(sleepTime);
352           } catch (InterruptedException e) {
353             throw (InterruptedIOException)new InterruptedIOException().initCause(e);
354           }
355           break;
356         default:
357           throw new IOException("get request returned " + code);
358       }
359     }
360     throw new IOException("get request timed out");
361   }
362 
363   public boolean exists(Get get) throws IOException {
364     LOG.warn("exists() is really get(), just use get()");
365     Result result = get(get);
366     return (result != null && !(result.isEmpty()));
367   }
368 
369   /**
370    * exists(List) is really a list of get() calls. Just use get().
371    * @param gets list of Get to test for the existence
372    */
373   public boolean[] existsAll(List<Get> gets) throws IOException {
374     LOG.warn("exists(List<Get>) is really list of get() calls, just use get()");
375     boolean[] results = new boolean[gets.size()];
376     for (int i = 0; i < results.length; i++) {
377       results[i] = exists(gets.get(i));
378     }
379     return results;
380   }
381 
382   @Deprecated
383   public Boolean[] exists(List<Get> gets) throws IOException {
384     boolean[] results = existsAll(gets);
385     Boolean[] objectResults = new Boolean[results.length];
386     for (int i = 0; i < results.length; ++i) {
387       objectResults[i] = results[i];
388     }
389     return objectResults;
390   }
391 
392   public void put(Put put) throws IOException {
393     CellSetModel model = buildModelFromPut(put);
394     StringBuilder sb = new StringBuilder();
395     sb.append('/');
396     sb.append(Bytes.toStringBinary(name));
397     sb.append('/');
398     sb.append(Bytes.toStringBinary(put.getRow()));
399     for (int i = 0; i < maxRetries; i++) {
400       Response response = client.put(sb.toString(), Constants.MIMETYPE_PROTOBUF,
401         model.createProtobufOutput());
402       int code = response.getCode();
403       switch (code) {
404       case 200:
405         return;
406       case 509:
407         try {
408           Thread.sleep(sleepTime);
409         } catch (InterruptedException e) {
410           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
411         }
412         break;
413       default:
414         throw new IOException("put request failed with " + code);
415       }
416     }
417     throw new IOException("put request timed out");
418   }
419 
420   public void put(List<Put> puts) throws IOException {
421     // this is a trick: The gateway accepts multiple rows in a cell set and
422     // ignores the row specification in the URI
423 
424     // separate puts by row
425     TreeMap<byte[],List<Cell>> map =
426       new TreeMap<byte[],List<Cell>>(Bytes.BYTES_COMPARATOR);
427     for (Put put: puts) {
428       byte[] row = put.getRow();
429       List<Cell> cells = map.get(row);
430       if (cells == null) {
431         cells = new ArrayList<Cell>();
432         map.put(row, cells);
433       }
434       for (List<Cell> l: put.getFamilyCellMap().values()) {
435         cells.addAll(l);
436       }
437     }
438 
439     // build the cell set
440     CellSetModel model = new CellSetModel();
441     for (Map.Entry<byte[], List<Cell>> e: map.entrySet()) {
442       RowModel row = new RowModel(e.getKey());
443       for (Cell cell: e.getValue()) {
444         row.addCell(new CellModel(cell));
445       }
446       model.addRow(row);
447     }
448 
449     // build path for multiput
450     StringBuilder sb = new StringBuilder();
451     sb.append('/');
452     sb.append(Bytes.toStringBinary(name));
453     sb.append("/$multiput"); // can be any nonexistent row
454     for (int i = 0; i < maxRetries; i++) {
455       Response response = client.put(sb.toString(), Constants.MIMETYPE_PROTOBUF,
456         model.createProtobufOutput());
457       int code = response.getCode();
458       switch (code) {
459       case 200:
460         return;
461       case 509:
462         try {
463           Thread.sleep(sleepTime);
464         } catch (InterruptedException e) {
465           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
466         }
467         break;
468       default:
469         throw new IOException("multiput request failed with " + code);
470       }
471     }
472     throw new IOException("multiput request timed out");
473   }
474 
475   public void delete(Delete delete) throws IOException {
476     String spec = buildRowSpec(delete.getRow(), delete.getFamilyCellMap(),
477       delete.getTimeStamp(), delete.getTimeStamp(), 1);
478     for (int i = 0; i < maxRetries; i++) {
479       Response response = client.delete(spec);
480       int code = response.getCode();
481       switch (code) {
482       case 200:
483         return;
484       case 509:
485         try {
486           Thread.sleep(sleepTime);
487         } catch (InterruptedException e) {
488           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
489         }
490         break;
491       default:
492         throw new IOException("delete request failed with " + code);
493       }
494     }
495     throw new IOException("delete request timed out");
496   }
497 
498   public void delete(List<Delete> deletes) throws IOException {
499     for (Delete delete: deletes) {
500       delete(delete);
501     }
502   }
503 
504   public void flushCommits() throws IOException {
505     // no-op
506   }
507 
508   class Scanner implements ResultScanner {
509 
510     String uri;
511 
512     public Scanner(Scan scan) throws IOException {
513       ScannerModel model;
514       try {
515         model = ScannerModel.fromScan(scan);
516       } catch (Exception e) {
517         throw new IOException(e);
518       }
519       StringBuffer sb = new StringBuffer();
520       sb.append('/');
521       sb.append(Bytes.toStringBinary(name));
522       sb.append('/');
523       sb.append("scanner");
524       for (int i = 0; i < maxRetries; i++) {
525         Response response = client.post(sb.toString(),
526           Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
527         int code = response.getCode();
528         switch (code) {
529         case 201:
530           uri = response.getLocation();
531           return;
532         case 509:
533           try {
534             Thread.sleep(sleepTime);
535           } catch (InterruptedException e) {
536             throw (InterruptedIOException)new InterruptedIOException().initCause(e);
537           }
538           break;
539         default:
540           throw new IOException("scan request failed with " + code);
541         }
542       }
543       throw new IOException("scan request timed out");
544     }
545 
546     @Override
547     public Result[] next(int nbRows) throws IOException {
548       StringBuilder sb = new StringBuilder(uri);
549       sb.append("?n=");
550       sb.append(nbRows);
551       for (int i = 0; i < maxRetries; i++) {
552         Response response = client.get(sb.toString(),
553           Constants.MIMETYPE_PROTOBUF);
554         int code = response.getCode();
555         switch (code) {
556         case 200:
557           CellSetModel model = new CellSetModel();
558           model.getObjectFromMessage(response.getBody());
559           return buildResultFromModel(model);
560         case 204:
561         case 206:
562           return null;
563         case 509:
564           try {
565             Thread.sleep(sleepTime);
566           } catch (InterruptedException e) {
567             throw (InterruptedIOException)new InterruptedIOException().initCause(e);
568           }
569           break;
570         default:
571           throw new IOException("scanner.next request failed with " + code);
572         }
573       }
574       throw new IOException("scanner.next request timed out");
575     }
576 
577     @Override
578     public Result next() throws IOException {
579       Result[] results = next(1);
580       if (results == null || results.length < 1) {
581         return null;
582       }
583       return results[0];
584     }
585 
586     class Iter implements Iterator<Result> {
587 
588       Result cache;
589 
590       public Iter() {
591         try {
592           cache = Scanner.this.next();
593         } catch (IOException e) {
594           LOG.warn(StringUtils.stringifyException(e));
595         }
596       }
597 
598       @Override
599       public boolean hasNext() {
600         return cache != null;
601       }
602 
603       @Override
604       public Result next() {
605         Result result = cache;
606         try {
607           cache = Scanner.this.next();
608         } catch (IOException e) {
609           LOG.warn(StringUtils.stringifyException(e));
610           cache = null;
611         }
612         return result;
613       }
614 
615       @Override
616       public void remove() {
617         throw new RuntimeException("remove() not supported");
618       }
619 
620     }
621 
622     @Override
623     public Iterator<Result> iterator() {
624       return new Iter();
625     }
626 
627     @Override
628     public void close() {
629       try {
630         client.delete(uri);
631       } catch (IOException e) {
632         LOG.warn(StringUtils.stringifyException(e));
633       }
634     }
635 
636   }
637 
638   public ResultScanner getScanner(Scan scan) throws IOException {
639     return new Scanner(scan);
640   }
641 
642   public ResultScanner getScanner(byte[] family) throws IOException {
643     Scan scan = new Scan();
644     scan.addFamily(family);
645     return new Scanner(scan);
646   }
647 
648   public ResultScanner getScanner(byte[] family, byte[] qualifier)
649       throws IOException {
650     Scan scan = new Scan();
651     scan.addColumn(family, qualifier);
652     return new Scanner(scan);
653   }
654 
655   public boolean isAutoFlush() {
656     return true;
657   }
658 
659   public Result getRowOrBefore(byte[] row, byte[] family) throws IOException {
660     throw new IOException("getRowOrBefore not supported");
661   }
662 
663   public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,
664       byte[] value, Put put) throws IOException {
665     // column to check-the-value
666     put.add(new KeyValue(row, family, qualifier, value));
667 
668     CellSetModel model = buildModelFromPut(put);
669     StringBuilder sb = new StringBuilder();
670     sb.append('/');
671     sb.append(Bytes.toStringBinary(name));
672     sb.append('/');
673     sb.append(Bytes.toStringBinary(put.getRow()));
674     sb.append("?check=put");
675 
676     for (int i = 0; i < maxRetries; i++) {
677       Response response = client.put(sb.toString(),
678         Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
679       int code = response.getCode();
680       switch (code) {
681       case 200:
682         return true;
683       case 304: // NOT-MODIFIED
684         return false;
685       case 509:
686         try {
687           Thread.sleep(sleepTime);
688         } catch (final InterruptedException e) {
689           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
690         }
691         break;
692       default:
693         throw new IOException("checkAndPut request failed with " + code);
694       }
695     }
696     throw new IOException("checkAndPut request timed out");
697   }
698 
699   public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,
700       CompareOp compareOp, byte[] value, Put put) throws IOException {
701     throw new IOException("checkAndPut for non-equal comparison not implemented");
702   }
703 
704   public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier,
705       byte[] value, Delete delete) throws IOException {
706     Put put = new Put(row);
707     // column to check-the-value
708     put.add(new KeyValue(row, family, qualifier, value));
709     CellSetModel model = buildModelFromPut(put);
710     StringBuilder sb = new StringBuilder();
711     sb.append('/');
712     sb.append(Bytes.toStringBinary(name));
713     sb.append('/');
714     sb.append(Bytes.toStringBinary(row));
715     sb.append("?check=delete");
716 
717     for (int i = 0; i < maxRetries; i++) {
718       Response response = client.put(sb.toString(),
719         Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
720       int code = response.getCode();
721       switch (code) {
722       case 200:
723         return true;
724       case 304: // NOT-MODIFIED
725         return false;
726       case 509:
727         try {
728           Thread.sleep(sleepTime);
729         } catch (final InterruptedException e) {
730           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
731         }
732         break;
733       default:
734         throw new IOException("checkAndDelete request failed with " + code);
735       }
736     }
737     throw new IOException("checkAndDelete request timed out");
738   }
739 
740   public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier,
741       CompareOp compareOp, byte[] value, Delete delete) throws IOException {
742     throw new IOException("checkAndDelete for non-equal comparison not implemented");
743   }
744 
745   public Result increment(Increment increment) throws IOException {
746     throw new IOException("Increment not supported");
747   }
748 
749   public Result append(Append append) throws IOException {
750     throw new IOException("Append not supported");
751   }
752 
753   public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
754       long amount) throws IOException {
755     throw new IOException("incrementColumnValue not supported");
756   }
757 
758   public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
759       long amount, Durability durability) throws IOException {
760     throw new IOException("incrementColumnValue not supported");
761   }
762 
763   @Override
764   public void batch(List<? extends Row> actions, Object[] results) throws IOException {
765     throw new IOException("batch not supported");
766   }
767 
768   @Override
769   public Object[] batch(List<? extends Row> actions) throws IOException {
770     throw new IOException("batch not supported");
771   }
772 
773   @Override
774   public <R> void batchCallback(List<? extends Row> actions, Object[] results,
775       Batch.Callback<R> callback) throws IOException, InterruptedException {
776     throw new IOException("batchCallback not supported");
777   }
778 
779   @Override
780   public <R> Object[] batchCallback(List<? extends Row> actions, Batch.Callback<R> callback)
781    throws IOException, InterruptedException {
782     throw new IOException("batchCallback not supported");
783   }
784 
785   @Override
786   public CoprocessorRpcChannel coprocessorService(byte[] row) {
787     throw new UnsupportedOperationException("coprocessorService not implemented");
788   }
789 
790   @Override
791   public <T extends Service, R> Map<byte[], R> coprocessorService(Class<T> service,
792       byte[] startKey, byte[] endKey, Batch.Call<T, R> callable)
793       throws ServiceException, Throwable {
794     throw new UnsupportedOperationException("coprocessorService not implemented");
795   }
796 
797   @Override
798   public <T extends Service, R> void coprocessorService(Class<T> service,
799       byte[] startKey, byte[] endKey, Batch.Call<T, R> callable, Batch.Callback<R> callback)
800       throws ServiceException, Throwable {
801     throw new UnsupportedOperationException("coprocessorService not implemented");
802   }
803 
804   @Override
805   public void mutateRow(RowMutations rm) throws IOException {
806     throw new IOException("atomicMutation not supported");
807   }
808 
809   @Override
810   public long getWriteBufferSize() {
811     throw new UnsupportedOperationException("getWriteBufferSize not implemented");
812   }
813 
814   @Override
815   public void setWriteBufferSize(long writeBufferSize) throws IOException {
816     throw new IOException("setWriteBufferSize not supported");
817   }
818 
819   @Override
820   public <R extends Message> Map<byte[], R> batchCoprocessorService(
821       Descriptors.MethodDescriptor method, Message request,
822       byte[] startKey, byte[] endKey, R responsePrototype) throws ServiceException, Throwable {
823     throw new UnsupportedOperationException("batchCoprocessorService not implemented");
824   }
825 
826   @Override
827   public <R extends Message> void batchCoprocessorService(
828       Descriptors.MethodDescriptor method, Message request,
829       byte[] startKey, byte[] endKey, R responsePrototype, Callback<R> callback)
830       throws ServiceException, Throwable {
831     throw new UnsupportedOperationException("batchCoprocessorService not implemented");
832   }
833 
834   @Override public boolean checkAndMutate(byte[] row, byte[] family, byte[] qualifier,
835       CompareOp compareOp, byte[] value, RowMutations rm) throws IOException {
836     throw new UnsupportedOperationException("checkAndMutate not implemented");
837   }
838 }