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