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.classification.InterfaceAudience;
35  import org.apache.hadoop.classification.InterfaceStability;
36  import org.apache.hadoop.conf.Configuration;
37  import org.apache.hadoop.hbase.Cell;
38  import org.apache.hadoop.hbase.HBaseConfiguration;
39  import org.apache.hadoop.hbase.HConstants;
40  import org.apache.hadoop.hbase.HTableDescriptor;
41  import org.apache.hadoop.hbase.KeyValue;
42  import org.apache.hadoop.hbase.KeyValueUtil;
43  import org.apache.hadoop.hbase.TableName;
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.HTableInterface;
49  import org.apache.hadoop.hbase.client.Increment;
50  import org.apache.hadoop.hbase.client.Put;
51  import org.apache.hadoop.hbase.client.Result;
52  import org.apache.hadoop.hbase.client.ResultScanner;
53  import org.apache.hadoop.hbase.client.Row;
54  import org.apache.hadoop.hbase.client.RowMutations;
55  import org.apache.hadoop.hbase.client.Scan;
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 HTableInterface {
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         KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
202         row.addCell(new CellModel(kv.getFamily(), kv.getQualifier(),
203           ts != HConstants.LATEST_TIMESTAMP ? ts : kv.getTimestamp(),
204           kv.getValue()));
205       }
206     }
207     CellSetModel model = new CellSetModel();
208     model.addRow(row);
209     return model;
210   }
211 
212   /**
213    * Constructor
214    * @param client
215    * @param name
216    */
217   public RemoteHTable(Client client, String name) {
218     this(client, HBaseConfiguration.create(), Bytes.toBytes(name));
219   }
220 
221   /**
222    * Constructor
223    * @param client
224    * @param conf
225    * @param name
226    */
227   public RemoteHTable(Client client, Configuration conf, String name) {
228     this(client, conf, Bytes.toBytes(name));
229   }
230 
231   /**
232    * Constructor
233    * @param client
234    * @param conf
235    * @param name
236    */
237   public RemoteHTable(Client client, Configuration conf, byte[] name) {
238     this.client = client;
239     this.conf = conf;
240     this.name = name;
241     this.maxRetries = conf.getInt("hbase.rest.client.max.retries", 10);
242     this.sleepTime = conf.getLong("hbase.rest.client.sleep", 1000);
243   }
244 
245   public byte[] getTableName() {
246     return name.clone();
247   }
248 
249   @Override
250   public TableName getName() {
251     return TableName.valueOf(name);
252   }
253 
254   public Configuration getConfiguration() {
255     return conf;
256   }
257 
258   public HTableDescriptor getTableDescriptor() throws IOException {
259     StringBuilder sb = new StringBuilder();
260     sb.append('/');
261     sb.append(Bytes.toStringBinary(name));
262     sb.append('/');
263     sb.append("schema");
264     for (int i = 0; i < maxRetries; i++) {
265       Response response = client.get(sb.toString(), Constants.MIMETYPE_PROTOBUF);
266       int code = response.getCode();
267       switch (code) {
268       case 200:
269         TableSchemaModel schema = new TableSchemaModel();
270         schema.getObjectFromMessage(response.getBody());
271         return schema.getTableDescriptor();
272       case 509:
273         try {
274           Thread.sleep(sleepTime);
275         } catch (InterruptedException e) {
276           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
277         }
278         break;
279       default:
280         throw new IOException("schema request returned " + code);
281       }
282     }
283     throw new IOException("schema request timed out");
284   }
285 
286   public void close() throws IOException {
287     client.shutdown();
288   }
289 
290   public Result get(Get get) throws IOException {
291     TimeRange range = get.getTimeRange();
292     String spec = buildRowSpec(get.getRow(), get.getFamilyMap(),
293       range.getMin(), range.getMax(), get.getMaxVersions());
294     if (get.getFilter() != null) {
295       LOG.warn("filters not supported on gets");
296     }
297     Result[] results = getResults(spec);
298     if (results.length > 0) {
299       if (results.length > 1) {
300         LOG.warn("too many results for get (" + results.length + ")");
301       }
302       return results[0];
303     } else {
304       return new Result();
305     }
306   }
307 
308   public Result[] get(List<Get> gets) throws IOException {
309     byte[][] rows = new byte[gets.size()][];
310     int maxVersions = 1;
311     int count = 0;
312 
313     for(Get g:gets) {
314 
315       if ( count == 0 ) {
316         maxVersions = g.getMaxVersions();
317       } else if (g.getMaxVersions() != maxVersions) {
318         LOG.warn("MaxVersions on Gets do not match, using the first in the list ("+maxVersions+")");
319       }
320 
321       if (g.getFilter() != null) {
322         LOG.warn("filters not supported on gets");
323       }
324 
325       rows[count] = g.getRow();
326       count ++;
327     }
328 
329     String spec = buildMultiRowSpec(rows, maxVersions);
330 
331     return getResults(spec);
332   }
333 
334   private Result[] getResults(String spec) throws IOException {
335     for (int i = 0; i < maxRetries; i++) {
336       Response response = client.get(spec, Constants.MIMETYPE_PROTOBUF);
337       int code = response.getCode();
338       switch (code) {
339         case 200:
340           CellSetModel model = new CellSetModel();
341           model.getObjectFromMessage(response.getBody());
342           Result[] results = buildResultFromModel(model);
343           if ( results.length > 0) {
344             return results;
345           }
346           // fall through
347         case 404:
348           return new Result[0];
349 
350         case 509:
351           try {
352             Thread.sleep(sleepTime);
353           } catch (InterruptedException e) {
354             throw (InterruptedIOException)new InterruptedIOException().initCause(e);
355           }
356           break;
357         default:
358           throw new IOException("get request returned " + code);
359       }
360     }
361     throw new IOException("get request timed out");
362   }
363 
364   public boolean exists(Get get) throws IOException {
365     LOG.warn("exists() is really get(), just use get()");
366     Result result = get(get);
367     return (result != null && !(result.isEmpty()));
368   }
369 
370   /**
371    * exists(List) is really a list of get() calls. Just use get().
372    * @param gets list of Get to test for the existence
373    */
374   public boolean[] existsAll(List<Get> gets) throws IOException {
375     LOG.warn("exists(List<Get>) is really list of get() calls, just use get()");
376     boolean[] results = new boolean[gets.size()];
377     for (int i = 0; i < results.length; i++) {
378       results[i] = exists(gets.get(i));
379     }
380     return results;
381   }
382 
383   @Deprecated
384   public Boolean[] exists(List<Get> gets) throws IOException {
385     boolean[] results = existsAll(gets);
386     Boolean[] objectResults = new Boolean[results.length];
387     for (int i = 0; i < results.length; ++i) {
388       objectResults[i] = results[i];
389     }
390     return objectResults;
391   }
392 
393   public void put(Put put) throws IOException {
394     CellSetModel model = buildModelFromPut(put);
395     StringBuilder sb = new StringBuilder();
396     sb.append('/');
397     sb.append(Bytes.toStringBinary(name));
398     sb.append('/');
399     sb.append(Bytes.toStringBinary(put.getRow()));
400     for (int i = 0; i < maxRetries; i++) {
401       Response response = client.put(sb.toString(), Constants.MIMETYPE_PROTOBUF,
402         model.createProtobufOutput());
403       int code = response.getCode();
404       switch (code) {
405       case 200:
406         return;
407       case 509:
408         try {
409           Thread.sleep(sleepTime);
410         } catch (InterruptedException e) {
411           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
412         }
413         break;
414       default:
415         throw new IOException("put request failed with " + code);
416       }
417     }
418     throw new IOException("put request timed out");
419   }
420 
421   public void put(List<Put> puts) throws IOException {
422     // this is a trick: The gateway accepts multiple rows in a cell set and
423     // ignores the row specification in the URI
424 
425     // separate puts by row
426     TreeMap<byte[],List<Cell>> map =
427       new TreeMap<byte[],List<Cell>>(Bytes.BYTES_COMPARATOR);
428     for (Put put: puts) {
429       byte[] row = put.getRow();
430       List<Cell> cells = map.get(row);
431       if (cells == null) {
432         cells = new ArrayList<Cell>();
433         map.put(row, cells);
434       }
435       for (List<Cell> l: put.getFamilyCellMap().values()) {
436         cells.addAll(l);
437       }
438     }
439 
440     // build the cell set
441     CellSetModel model = new CellSetModel();
442     for (Map.Entry<byte[], List<Cell>> e: map.entrySet()) {
443       RowModel row = new RowModel(e.getKey());
444       for (Cell cell: e.getValue()) {
445         KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
446         row.addCell(new CellModel(kv));
447       }
448       model.addRow(row);
449     }
450 
451     // build path for multiput
452     StringBuilder sb = new StringBuilder();
453     sb.append('/');
454     sb.append(Bytes.toStringBinary(name));
455     sb.append("/$multiput"); // can be any nonexistent row
456     for (int i = 0; i < maxRetries; i++) {
457       Response response = client.put(sb.toString(), Constants.MIMETYPE_PROTOBUF,
458         model.createProtobufOutput());
459       int code = response.getCode();
460       switch (code) {
461       case 200:
462         return;
463       case 509:
464         try {
465           Thread.sleep(sleepTime);
466         } catch (InterruptedException e) {
467           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
468         }
469         break;
470       default:
471         throw new IOException("multiput request failed with " + code);
472       }
473     }
474     throw new IOException("multiput request timed out");
475   }
476 
477   public void delete(Delete delete) throws IOException {
478     String spec = buildRowSpec(delete.getRow(), delete.getFamilyCellMap(),
479       delete.getTimeStamp(), delete.getTimeStamp(), 1);
480     for (int i = 0; i < maxRetries; i++) {
481       Response response = client.delete(spec);
482       int code = response.getCode();
483       switch (code) {
484       case 200:
485         return;
486       case 509:
487         try {
488           Thread.sleep(sleepTime);
489         } catch (InterruptedException e) {
490           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
491         }
492         break;
493       default:
494         throw new IOException("delete request failed with " + code);
495       }
496     }
497     throw new IOException("delete request timed out");
498   }
499 
500   public void delete(List<Delete> deletes) throws IOException {
501     for (Delete delete: deletes) {
502       delete(delete);
503     }
504   }
505 
506   public void flushCommits() throws IOException {
507     // no-op
508   }
509 
510   class Scanner implements ResultScanner {
511 
512     String uri;
513 
514     public Scanner(Scan scan) throws IOException {
515       ScannerModel model;
516       try {
517         model = ScannerModel.fromScan(scan);
518       } catch (Exception e) {
519         throw new IOException(e);
520       }
521       StringBuffer sb = new StringBuffer();
522       sb.append('/');
523       sb.append(Bytes.toStringBinary(name));
524       sb.append('/');
525       sb.append("scanner");
526       for (int i = 0; i < maxRetries; i++) {
527         Response response = client.post(sb.toString(),
528           Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
529         int code = response.getCode();
530         switch (code) {
531         case 201:
532           uri = response.getLocation();
533           return;
534         case 509:
535           try {
536             Thread.sleep(sleepTime);
537           } catch (InterruptedException e) {
538             throw (InterruptedIOException)new InterruptedIOException().initCause(e);
539           }
540           break;
541         default:
542           throw new IOException("scan request failed with " + code);
543         }
544       }
545       throw new IOException("scan request timed out");
546     }
547 
548     @Override
549     public Result[] next(int nbRows) throws IOException {
550       StringBuilder sb = new StringBuilder(uri);
551       sb.append("?n=");
552       sb.append(nbRows);
553       for (int i = 0; i < maxRetries; i++) {
554         Response response = client.get(sb.toString(),
555           Constants.MIMETYPE_PROTOBUF);
556         int code = response.getCode();
557         switch (code) {
558         case 200:
559           CellSetModel model = new CellSetModel();
560           model.getObjectFromMessage(response.getBody());
561           return buildResultFromModel(model);
562         case 204:
563         case 206:
564           return null;
565         case 509:
566           try {
567             Thread.sleep(sleepTime);
568           } catch (InterruptedException e) {
569             throw (InterruptedIOException)new InterruptedIOException().initCause(e);
570           }
571           break;
572         default:
573           throw new IOException("scanner.next request failed with " + code);
574         }
575       }
576       throw new IOException("scanner.next request timed out");
577     }
578 
579     @Override
580     public Result next() throws IOException {
581       Result[] results = next(1);
582       if (results == null || results.length < 1) {
583         return null;
584       }
585       return results[0];
586     }
587 
588     class Iter implements Iterator<Result> {
589 
590       Result cache;
591 
592       public Iter() {
593         try {
594           cache = Scanner.this.next();
595         } catch (IOException e) {
596           LOG.warn(StringUtils.stringifyException(e));
597         }
598       }
599 
600       @Override
601       public boolean hasNext() {
602         return cache != null;
603       }
604 
605       @Override
606       public Result next() {
607         Result result = cache;
608         try {
609           cache = Scanner.this.next();
610         } catch (IOException e) {
611           LOG.warn(StringUtils.stringifyException(e));
612           cache = null;
613         }
614         return result;
615       }
616 
617       @Override
618       public void remove() {
619         throw new RuntimeException("remove() not supported");
620       }
621 
622     }
623 
624     @Override
625     public Iterator<Result> iterator() {
626       return new Iter();
627     }
628 
629     @Override
630     public void close() {
631       try {
632         client.delete(uri);
633       } catch (IOException e) {
634         LOG.warn(StringUtils.stringifyException(e));
635       }
636     }
637 
638   }
639 
640   public ResultScanner getScanner(Scan scan) throws IOException {
641     return new Scanner(scan);
642   }
643 
644   public ResultScanner getScanner(byte[] family) throws IOException {
645     Scan scan = new Scan();
646     scan.addFamily(family);
647     return new Scanner(scan);
648   }
649 
650   public ResultScanner getScanner(byte[] family, byte[] qualifier)
651       throws IOException {
652     Scan scan = new Scan();
653     scan.addColumn(family, qualifier);
654     return new Scanner(scan);
655   }
656 
657   public boolean isAutoFlush() {
658     return true;
659   }
660 
661   public Result getRowOrBefore(byte[] row, byte[] family) throws IOException {
662     throw new IOException("getRowOrBefore not supported");
663   }
664 
665   public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,
666       byte[] value, Put put) throws IOException {
667     // column to check-the-value
668     put.add(new KeyValue(row, family, qualifier, value));
669 
670     CellSetModel model = buildModelFromPut(put);
671     StringBuilder sb = new StringBuilder();
672     sb.append('/');
673     sb.append(Bytes.toStringBinary(name));
674     sb.append('/');
675     sb.append(Bytes.toStringBinary(put.getRow()));
676     sb.append("?check=put");
677 
678     for (int i = 0; i < maxRetries; i++) {
679       Response response = client.put(sb.toString(),
680         Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
681       int code = response.getCode();
682       switch (code) {
683       case 200:
684         return true;
685       case 304: // NOT-MODIFIED
686         return false;
687       case 509:
688         try {
689           Thread.sleep(sleepTime);
690         } catch (final InterruptedException e) {
691           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
692         }
693         break;
694       default:
695         throw new IOException("checkAndPut request failed with " + code);
696       }
697     }
698     throw new IOException("checkAndPut request timed out");
699   }
700 
701   public boolean checkAndPut(byte[] row, byte[] family, byte[] qualifier,
702       CompareOp compareOp, byte[] value, Put put) throws IOException {
703     throw new IOException("checkAndPut for non-equal comparison not implemented");
704   }
705 
706   public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier,
707       byte[] value, Delete delete) throws IOException {
708     Put put = new Put(row);
709     // column to check-the-value
710     put.add(new KeyValue(row, family, qualifier, value));
711     CellSetModel model = buildModelFromPut(put);
712     StringBuilder sb = new StringBuilder();
713     sb.append('/');
714     sb.append(Bytes.toStringBinary(name));
715     sb.append('/');
716     sb.append(Bytes.toStringBinary(row));
717     sb.append("?check=delete");
718 
719     for (int i = 0; i < maxRetries; i++) {
720       Response response = client.put(sb.toString(),
721         Constants.MIMETYPE_PROTOBUF, model.createProtobufOutput());
722       int code = response.getCode();
723       switch (code) {
724       case 200:
725         return true;
726       case 304: // NOT-MODIFIED
727         return false;
728       case 509:
729         try {
730           Thread.sleep(sleepTime);
731         } catch (final InterruptedException e) {
732           throw (InterruptedIOException)new InterruptedIOException().initCause(e);
733         }
734         break;
735       default:
736         throw new IOException("checkAndDelete request failed with " + code);
737       }
738     }
739     throw new IOException("checkAndDelete request timed out");
740   }
741 
742   public boolean checkAndDelete(byte[] row, byte[] family, byte[] qualifier,
743       CompareOp compareOp, byte[] value, Delete delete) throws IOException {
744     throw new IOException("checkAndDelete for non-equal comparison not implemented");
745   }
746 
747   public Result increment(Increment increment) throws IOException {
748     throw new IOException("Increment not supported");
749   }
750 
751   public Result append(Append append) throws IOException {
752     throw new IOException("Append not supported");
753   }
754 
755   public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
756       long amount) throws IOException {
757     throw new IOException("incrementColumnValue not supported");
758   }
759 
760   public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
761       long amount, Durability durability) throws IOException {
762     throw new IOException("incrementColumnValue not supported");
763   }
764 
765   @Override
766   public void batch(List<? extends Row> actions, Object[] results) throws IOException {
767     throw new IOException("batch not supported");
768   }
769 
770   @Override
771   public Object[] batch(List<? extends Row> actions) throws IOException {
772     throw new IOException("batch not supported");
773   }
774 
775   @Override
776   public <R> void batchCallback(List<? extends Row> actions, Object[] results,
777       Batch.Callback<R> callback) throws IOException, InterruptedException {
778     throw new IOException("batchCallback not supported");
779   }
780 
781   @Override
782   public <R> Object[] batchCallback(List<? extends Row> actions, Batch.Callback<R> callback)
783    throws IOException, InterruptedException {
784     throw new IOException("batchCallback not supported");
785   }
786 
787   @Override
788   public CoprocessorRpcChannel coprocessorService(byte[] row) {
789     throw new UnsupportedOperationException("coprocessorService not implemented");
790   }
791 
792   @Override
793   public <T extends Service, R> Map<byte[], R> coprocessorService(Class<T> service,
794       byte[] startKey, byte[] endKey, Batch.Call<T, R> callable)
795       throws ServiceException, Throwable {
796     throw new UnsupportedOperationException("coprocessorService not implemented");
797   }
798 
799   @Override
800   public <T extends Service, R> void coprocessorService(Class<T> service,
801       byte[] startKey, byte[] endKey, Batch.Call<T, R> callable, Batch.Callback<R> callback)
802       throws ServiceException, Throwable {
803     throw new UnsupportedOperationException("coprocessorService not implemented");
804   }
805 
806   @Override
807   public void mutateRow(RowMutations rm) throws IOException {
808     throw new IOException("atomicMutation not supported");
809   }
810 
811   @Override
812   public void setAutoFlush(boolean autoFlush) {
813     throw new UnsupportedOperationException("setAutoFlush not implemented");
814   }
815 
816   @Override
817   public void setAutoFlush(boolean autoFlush, boolean clearBufferOnFail) {
818     throw new UnsupportedOperationException("setAutoFlush not implemented");
819   }
820 
821   @Override
822   public void setAutoFlushTo(boolean autoFlush) {
823     throw new UnsupportedOperationException("setAutoFlushTo not implemented");
824   }
825 
826   @Override
827   public long getWriteBufferSize() {
828     throw new UnsupportedOperationException("getWriteBufferSize not implemented");
829   }
830 
831   @Override
832   public void setWriteBufferSize(long writeBufferSize) throws IOException {
833     throw new IOException("setWriteBufferSize not supported");
834   }
835 
836   @Override
837   public long incrementColumnValue(byte[] row, byte[] family, byte[] qualifier,
838       long amount, boolean writeToWAL) throws IOException {
839     throw new IOException("incrementColumnValue not supported");
840   }
841 
842   @Override
843   public <R extends Message> Map<byte[], R> batchCoprocessorService(
844       Descriptors.MethodDescriptor method, Message request,
845       byte[] startKey, byte[] endKey, R responsePrototype) throws ServiceException, Throwable {
846     throw new UnsupportedOperationException("batchCoprocessorService not implemented");
847   }
848 
849   @Override
850   public <R extends Message> void batchCoprocessorService(
851       Descriptors.MethodDescriptor method, Message request,
852       byte[] startKey, byte[] endKey, R responsePrototype, Callback<R> callback)
853       throws ServiceException, Throwable {
854     throw new UnsupportedOperationException("batchCoprocessorService not implemented");
855   }
856 }