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  package org.apache.hadoop.hbase.thrift2;
20  
21  import static org.apache.hadoop.hbase.util.Bytes.getBytes;
22  
23  import java.io.IOException;
24  import java.nio.ByteBuffer;
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.Map;
28  
29  import org.apache.hadoop.classification.InterfaceAudience;
30  import org.apache.hadoop.hbase.Cell;
31  import org.apache.hadoop.hbase.CellUtil;
32  import org.apache.hadoop.hbase.HConstants;
33  import org.apache.hadoop.hbase.KeyValue;
34  import org.apache.hadoop.hbase.KeyValueUtil;
35  import org.apache.hadoop.hbase.client.Delete;
36  import org.apache.hadoop.hbase.client.Durability;
37  import org.apache.hadoop.hbase.client.Get;
38  import org.apache.hadoop.hbase.client.Increment;
39  import org.apache.hadoop.hbase.client.OperationWithAttributes;
40  import org.apache.hadoop.hbase.client.Put;
41  import org.apache.hadoop.hbase.client.Result;
42  import org.apache.hadoop.hbase.client.RowMutations;
43  import org.apache.hadoop.hbase.client.Scan;
44  import org.apache.hadoop.hbase.filter.ParseFilter;
45  import org.apache.hadoop.hbase.thrift2.generated.TColumn;
46  import org.apache.hadoop.hbase.thrift2.generated.TColumnIncrement;
47  import org.apache.hadoop.hbase.thrift2.generated.TColumnValue;
48  import org.apache.hadoop.hbase.thrift2.generated.TDelete;
49  import org.apache.hadoop.hbase.thrift2.generated.TDeleteType;
50  import org.apache.hadoop.hbase.thrift2.generated.TDurability;
51  import org.apache.hadoop.hbase.thrift2.generated.TGet;
52  import org.apache.hadoop.hbase.thrift2.generated.TIncrement;
53  import org.apache.hadoop.hbase.thrift2.generated.TMutation;
54  import org.apache.hadoop.hbase.thrift2.generated.TPut;
55  import org.apache.hadoop.hbase.thrift2.generated.TResult;
56  import org.apache.hadoop.hbase.thrift2.generated.TRowMutations;
57  import org.apache.hadoop.hbase.thrift2.generated.TScan;
58  import org.apache.hadoop.hbase.thrift2.generated.TTimeRange;
59  import org.apache.hadoop.hbase.util.Bytes;
60  
61  @InterfaceAudience.Private
62  public class ThriftUtilities {
63  
64    private ThriftUtilities() {
65      throw new UnsupportedOperationException("Can't initialize class");
66    }
67  
68    /**
69     * Creates a {@link Get} (HBase) from a {@link TGet} (Thrift).
70     *
71     * This ignores any timestamps set on {@link TColumn} objects.
72     *
73     * @param in the <code>TGet</code> to convert
74     *
75     * @return <code>Get</code> object
76     *
77     * @throws IOException if an invalid time range or max version parameter is given
78     */
79    public static Get getFromThrift(TGet in) throws IOException {
80      Get out = new Get(in.getRow());
81  
82      // Timestamp overwrites time range if both are set
83      if (in.isSetTimestamp()) {
84        out.setTimeStamp(in.getTimestamp());
85      } else if (in.isSetTimeRange()) {
86        out.setTimeRange(in.getTimeRange().getMinStamp(), in.getTimeRange().getMaxStamp());
87      }
88  
89      if (in.isSetMaxVersions()) {
90        out.setMaxVersions(in.getMaxVersions());
91      }
92  
93      if (in.isSetFilterString()) {
94        ParseFilter parseFilter = new ParseFilter();
95        out.setFilter(parseFilter.parseFilterString(in.getFilterString()));
96      }
97  
98      if (in.isSetAttributes()) {
99        addAttributes(out,in.getAttributes());
100     }
101 
102     if (!in.isSetColumns()) {
103       return out;
104     }
105 
106     for (TColumn column : in.getColumns()) {
107       if (column.isSetQualifier()) {
108         out.addColumn(column.getFamily(), column.getQualifier());
109       } else {
110         out.addFamily(column.getFamily());
111       }
112     }
113 
114     return out;
115   }
116 
117   /**
118    * Converts multiple {@link TGet}s (Thrift) into a list of {@link Get}s (HBase).
119    *
120    * @param in list of <code>TGet</code>s to convert
121    *
122    * @return list of <code>Get</code> objects
123    *
124    * @throws IOException if an invalid time range or max version parameter is given
125    * @see #getFromThrift(TGet)
126    */
127   public static List<Get> getsFromThrift(List<TGet> in) throws IOException {
128     List<Get> out = new ArrayList<Get>(in.size());
129     for (TGet get : in) {
130       out.add(getFromThrift(get));
131     }
132     return out;
133   }
134 
135   /**
136    * Creates a {@link TResult} (Thrift) from a {@link Result} (HBase).
137    *
138    * @param in the <code>Result</code> to convert
139    *
140    * @return converted result, returns an empty result if the input is <code>null</code>
141    */
142   public static TResult resultFromHBase(Result in) {
143     Cell[] raw = in.rawCells();
144     TResult out = new TResult();
145     byte[] row = in.getRow();
146     if (row != null) {
147       out.setRow(in.getRow());
148     }
149     List<TColumnValue> columnValues = new ArrayList<TColumnValue>();
150     for (Cell kv : raw) {
151       TColumnValue col = new TColumnValue();
152       col.setFamily(CellUtil.cloneFamily(kv));
153       col.setQualifier(CellUtil.cloneQualifier(kv));
154       col.setTimestamp(kv.getTimestamp());
155       col.setValue(CellUtil.cloneValue(kv));
156       columnValues.add(col);
157     }
158     out.setColumnValues(columnValues);
159     return out;
160   }
161 
162   /**
163    * Converts multiple {@link Result}s (HBase) into a list of {@link TResult}s (Thrift).
164    *
165    * @param in array of <code>Result</code>s to convert
166    *
167    * @return list of converted <code>TResult</code>s
168    *
169    * @see #resultFromHBase(Result)
170    */
171   public static List<TResult> resultsFromHBase(Result[] in) {
172     List<TResult> out = new ArrayList<TResult>(in.length);
173     for (Result result : in) {
174       out.add(resultFromHBase(result));
175     }
176     return out;
177   }
178 
179   /**
180    * Creates a {@link Put} (HBase) from a {@link TPut} (Thrift)
181    *
182    * @param in the <code>TPut</code> to convert
183    *
184    * @return converted <code>Put</code>
185    */
186   public static Put putFromThrift(TPut in) {
187     Put out;
188 
189     if (in.isSetTimestamp()) {
190       out = new Put(in.getRow(), in.getTimestamp());
191     } else {
192       out = new Put(in.getRow());
193     }
194 
195     if (in.isSetDurability()) {
196       out.setDurability(durabilityFromThrift(in.getDurability()));
197     }
198 
199     for (TColumnValue columnValue : in.getColumnValues()) {
200       if (columnValue.isSetTimestamp()) {
201         out.addImmutable(
202             columnValue.getFamily(), columnValue.getQualifier(), columnValue.getTimestamp(),
203             columnValue.getValue());
204       } else {
205         out.addImmutable(
206             columnValue.getFamily(), columnValue.getQualifier(), columnValue.getValue());
207       }
208     }
209 
210     if (in.isSetAttributes()) {
211       addAttributes(out,in.getAttributes());
212     }
213 
214     return out;
215   }
216 
217   /**
218    * Converts multiple {@link TPut}s (Thrift) into a list of {@link Put}s (HBase).
219    *
220    * @param in list of <code>TPut</code>s to convert
221    *
222    * @return list of converted <code>Put</code>s
223    *
224    * @see #putFromThrift(TPut)
225    */
226   public static List<Put> putsFromThrift(List<TPut> in) {
227     List<Put> out = new ArrayList<Put>(in.size());
228     for (TPut put : in) {
229       out.add(putFromThrift(put));
230     }
231     return out;
232   }
233 
234   /**
235    * Creates a {@link Delete} (HBase) from a {@link TDelete} (Thrift).
236    *
237    * @param in the <code>TDelete</code> to convert
238    *
239    * @return converted <code>Delete</code>
240    */
241   public static Delete deleteFromThrift(TDelete in) {
242     Delete out;
243 
244     if (in.isSetColumns()) {
245       out = new Delete(in.getRow());
246       for (TColumn column : in.getColumns()) {
247         if (column.isSetQualifier()) {
248           if (column.isSetTimestamp()) {
249             if (in.isSetDeleteType() &&
250                 in.getDeleteType().equals(TDeleteType.DELETE_COLUMNS))
251               out.deleteColumns(column.getFamily(), column.getQualifier(), column.getTimestamp());
252             else
253               out.deleteColumn(column.getFamily(), column.getQualifier(), column.getTimestamp());
254           } else {
255             if (in.isSetDeleteType() &&
256                 in.getDeleteType().equals(TDeleteType.DELETE_COLUMNS))
257               out.deleteColumns(column.getFamily(), column.getQualifier());
258             else
259               out.deleteColumn(column.getFamily(), column.getQualifier());
260           }
261 
262         } else {
263           if (column.isSetTimestamp()) {
264             out.deleteFamily(column.getFamily(), column.getTimestamp());
265           } else {
266             out.deleteFamily(column.getFamily());
267           }
268         }
269       }
270     } else {
271       if (in.isSetTimestamp()) {
272         out = new Delete(in.getRow(), in.getTimestamp());
273       } else {
274         out = new Delete(in.getRow());
275       }
276     }
277 
278     if (in.isSetAttributes()) {
279       addAttributes(out,in.getAttributes());
280     }
281 
282     if (in.isSetDurability()) {
283       out.setDurability(durabilityFromThrift(in.getDurability()));
284     }
285 
286     return out;
287   }
288 
289   /**
290    * Converts multiple {@link TDelete}s (Thrift) into a list of {@link Delete}s (HBase).
291    *
292    * @param in list of <code>TDelete</code>s to convert
293    *
294    * @return list of converted <code>Delete</code>s
295    *
296    * @see #deleteFromThrift(TDelete)
297    */
298 
299   public static List<Delete> deletesFromThrift(List<TDelete> in) {
300     List<Delete> out = new ArrayList<Delete>(in.size());
301     for (TDelete delete : in) {
302       out.add(deleteFromThrift(delete));
303     }
304     return out;
305   }
306 
307   public static TDelete deleteFromHBase(Delete in) {
308     TDelete out = new TDelete(ByteBuffer.wrap(in.getRow()));
309 
310     List<TColumn> columns = new ArrayList<TColumn>();
311     long rowTimestamp = in.getTimeStamp();
312     if (rowTimestamp != HConstants.LATEST_TIMESTAMP) {
313       out.setTimestamp(rowTimestamp);
314     }
315 
316     // Map<family, List<KeyValue>>
317     for (Map.Entry<byte[], List<org.apache.hadoop.hbase.Cell>> familyEntry:
318         in.getFamilyCellMap().entrySet()) {
319       TColumn column = new TColumn(ByteBuffer.wrap(familyEntry.getKey()));
320       for (org.apache.hadoop.hbase.Cell cell: familyEntry.getValue()) {
321         KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
322         byte[] family = kv.getFamily();
323         byte[] qualifier = kv.getQualifier();
324         long timestamp = kv.getTimestamp();
325         if (family != null) {
326           column.setFamily(family);
327         }
328         if (qualifier != null) {
329           column.setQualifier(qualifier);
330         }
331         if (timestamp != HConstants.LATEST_TIMESTAMP) {
332           column.setTimestamp(kv.getTimestamp());
333         }
334       }
335       columns.add(column);
336     }
337     out.setColumns(columns);
338 
339     return out;
340   }
341 
342   /**
343    * Creates a {@link RowMutations} (HBase) from a {@link TRowMutations} (Thrift)
344    *
345    * @param in the <code>TRowMutations</code> to convert
346    *
347    * @return converted <code>RowMutations</code>
348    */
349   public static RowMutations rowMutationsFromThrift(TRowMutations in) throws IOException {
350     RowMutations out = new RowMutations(in.getRow());
351     List<TMutation> mutations = in.getMutations();
352     for (TMutation mutation : mutations) {
353       if (mutation.isSetPut()) {
354         out.add(putFromThrift(mutation.getPut()));
355       }
356       if (mutation.isSetDeleteSingle()) {
357         out.add(deleteFromThrift(mutation.getDeleteSingle()));
358       }
359     }
360     return out;
361   }
362 
363   public static Scan scanFromThrift(TScan in) throws IOException {
364     Scan out = new Scan();
365 
366     if (in.isSetStartRow())
367       out.setStartRow(in.getStartRow());
368     if (in.isSetStopRow())
369       out.setStopRow(in.getStopRow());
370     if (in.isSetCaching())
371       out.setCaching(in.getCaching());
372     if (in.isSetMaxVersions()) {
373       out.setMaxVersions(in.getMaxVersions());
374     }
375 
376     if (in.isSetColumns()) {
377       for (TColumn column : in.getColumns()) {
378         if (column.isSetQualifier()) {
379           out.addColumn(column.getFamily(), column.getQualifier());
380         } else {
381           out.addFamily(column.getFamily());
382         }
383       }
384     }
385 
386     TTimeRange timeRange = in.getTimeRange();
387     if (timeRange != null &&
388         timeRange.isSetMinStamp() && timeRange.isSetMaxStamp()) {
389       out.setTimeRange(timeRange.getMinStamp(), timeRange.getMaxStamp());
390     }
391 
392     if (in.isSetBatchSize()) {
393       out.setBatch(in.getBatchSize());
394     }
395 
396     if (in.isSetFilterString()) {
397       ParseFilter parseFilter = new ParseFilter();
398       out.setFilter(parseFilter.parseFilterString(in.getFilterString()));
399     }
400 
401     if (in.isSetAttributes()) {
402       addAttributes(out,in.getAttributes());
403     }
404 
405     return out;
406   }
407 
408   public static Increment incrementFromThrift(TIncrement in) throws IOException {
409     Increment out = new Increment(in.getRow());
410     for (TColumnIncrement column : in.getColumns()) {
411       out.addColumn(column.getFamily(), column.getQualifier(), column.getAmount());
412     }
413 
414     if (in.isSetAttributes()) {
415       addAttributes(out,in.getAttributes());
416     }
417 
418     if (in.isSetDurability()) {
419       out.setDurability(durabilityFromThrift(in.getDurability()));
420     }
421 
422     return out;
423   }
424 
425   /**
426    * Adds all the attributes into the Operation object
427    */
428   private static void addAttributes(OperationWithAttributes op,
429                                     Map<ByteBuffer, ByteBuffer> attributes) {
430     if (attributes == null || attributes.size() == 0) {
431       return;
432     }
433     for (Map.Entry<ByteBuffer, ByteBuffer> entry : attributes.entrySet()) {
434       String name = Bytes.toStringBinary(getBytes(entry.getKey()));
435       byte[] value =  getBytes(entry.getValue());
436       op.setAttribute(name, value);
437     }
438   }
439 
440   private static Durability durabilityFromThrift(TDurability tDurability) {
441     switch (tDurability.getValue()) {
442       case 1: return Durability.SKIP_WAL;
443       case 2: return Durability.ASYNC_WAL;
444       case 3: return Durability.SYNC_WAL;
445       case 4: return Durability.FSYNC_WAL;
446       default: return null;
447     }
448   }
449 }