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;
20 
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26 
27 import java.io.ByteArrayInputStream;
28 import java.io.ByteArrayOutputStream;
29 import java.io.DataInputStream;
30 import java.io.DataOutputStream;
31 import java.io.IOException;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.NavigableSet;
35 import java.util.Set;
36 
37 import org.apache.hadoop.hbase.client.Get;
38 import org.apache.hadoop.hbase.client.Scan;
39 import org.apache.hadoop.hbase.exceptions.DeserializationException;
40 import org.apache.hadoop.hbase.filter.BinaryComparator;
41 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
42 import org.apache.hadoop.hbase.filter.Filter;
43 import org.apache.hadoop.hbase.filter.PrefixFilter;
44 import org.apache.hadoop.hbase.filter.RowFilter;
45 import org.apache.hadoop.hbase.io.TimeRange;
46 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
47 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
48 import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.SplitLogTask.RecoveryMode;
49 import org.apache.hadoop.hbase.testclassification.SmallTests;
50 import org.apache.hadoop.hbase.util.Bytes;
51 import org.apache.hadoop.hbase.util.Writables;
52 import org.apache.hadoop.io.DataInputBuffer;
53 import org.junit.Test;
54 import org.junit.experimental.categories.Category;
55 
56 /**
57  * Test HBase Writables serializations
58  */
59 @Category(SmallTests.class)
60 public class TestSerialization {
testKeyValue()61   @Test public void testKeyValue() throws Exception {
62     final String name = "testKeyValue2";
63     byte[] row = name.getBytes();
64     byte[] fam = "fam".getBytes();
65     byte[] qf = "qf".getBytes();
66     long ts = System.currentTimeMillis();
67     byte[] val = "val".getBytes();
68     KeyValue kv = new KeyValue(row, fam, qf, ts, val);
69     ByteArrayOutputStream baos = new ByteArrayOutputStream();
70     DataOutputStream dos = new DataOutputStream(baos);
71     long l = KeyValue.write(kv, dos);
72     dos.close();
73     byte [] mb = baos.toByteArray();
74     ByteArrayInputStream bais = new ByteArrayInputStream(mb);
75     DataInputStream dis = new DataInputStream(bais);
76     KeyValue deserializedKv = KeyValue.create(dis);
77     assertTrue(Bytes.equals(kv.getBuffer(), deserializedKv.getBuffer()));
78     assertEquals(kv.getOffset(), deserializedKv.getOffset());
79     assertEquals(kv.getLength(), deserializedKv.getLength());
80   }
81 
testCreateKeyValueInvalidNegativeLength()82   @Test public void testCreateKeyValueInvalidNegativeLength() {
83 
84     KeyValue kv_0 = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"),       // 51 bytes
85                                  Bytes.toBytes("myQualifier"), 12345L, Bytes.toBytes("my12345"));
86 
87     KeyValue kv_1 = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"),       // 49 bytes
88                                  Bytes.toBytes("myQualifier"), 12345L, Bytes.toBytes("my123"));
89 
90     ByteArrayOutputStream baos = new ByteArrayOutputStream();
91     DataOutputStream dos = new DataOutputStream(baos);
92 
93     long l = 0;
94     try {
95       l  = KeyValue.oswrite(kv_0, dos, false);
96       l += KeyValue.oswrite(kv_1, dos, false);
97       assertEquals(100L, l);
98     } catch (IOException e) {
99       fail("Unexpected IOException" + e.getMessage());
100     }
101 
102     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
103     DataInputStream dis = new DataInputStream(bais);
104 
105     try {
106       KeyValue.create(dis);
107       assertTrue(kv_0.equals(kv_1));
108     } catch (Exception e) {
109       fail("Unexpected Exception" + e.getMessage());
110     }
111 
112     // length -1
113     try {
114       // even if we have a good kv now in dis we will just pass length with -1 for simplicity
115       KeyValue.create(-1, dis);
116       fail("Expected corrupt stream");
117     } catch (Exception e) {
118       assertEquals("Failed read -1 bytes, stream corrupt?", e.getMessage());
119     }
120 
121   }
122 
123   @Test
testSplitLogTask()124   public void testSplitLogTask() throws DeserializationException {
125     SplitLogTask slt = new SplitLogTask.Unassigned(ServerName.valueOf("mgr,1,1"),
126       RecoveryMode.LOG_REPLAY);
127     byte [] bytes = slt.toByteArray();
128     SplitLogTask sltDeserialized = SplitLogTask.parseFrom(bytes);
129     assertTrue(slt.equals(sltDeserialized));
130   }
131 
testCompareFilter()132   @Test public void testCompareFilter() throws Exception {
133     Filter f = new RowFilter(CompareOp.EQUAL,
134       new BinaryComparator(Bytes.toBytes("testRowOne-2")));
135     byte [] bytes = f.toByteArray();
136     Filter ff = RowFilter.parseFrom(bytes);
137     assertNotNull(ff);
138   }
139 
testTableDescriptor()140   @Test public void testTableDescriptor() throws Exception {
141     final String name = "testTableDescriptor";
142     HTableDescriptor htd = createTableDescriptor(name);
143     byte [] mb = Writables.getBytes(htd);
144     HTableDescriptor deserializedHtd =
145       (HTableDescriptor)Writables.getWritable(mb, new HTableDescriptor());
146     assertEquals(htd.getTableName(), deserializedHtd.getTableName());
147   }
148 
149   /**
150    * Test RegionInfo serialization
151    * @throws Exception
152    */
testRegionInfo()153   @Test public void testRegionInfo() throws Exception {
154     HRegionInfo hri = createRandomRegion("testRegionInfo");
155 
156     //test toByteArray()
157     byte [] hrib = hri.toByteArray();
158     HRegionInfo deserializedHri = HRegionInfo.parseFrom(hrib);
159     assertEquals(hri.getEncodedName(), deserializedHri.getEncodedName());
160     assertEquals(hri, deserializedHri);
161 
162     //test toDelimitedByteArray()
163     hrib = hri.toDelimitedByteArray();
164     DataInputBuffer buf = new DataInputBuffer();
165     try {
166       buf.reset(hrib, hrib.length);
167       deserializedHri = HRegionInfo.parseFrom(buf);
168       assertEquals(hri.getEncodedName(), deserializedHri.getEncodedName());
169       assertEquals(hri, deserializedHri);
170     } finally {
171       buf.close();
172     }
173   }
174 
testRegionInfos()175   @Test public void testRegionInfos() throws Exception {
176     HRegionInfo hri = createRandomRegion("testRegionInfos");
177     byte[] triple = HRegionInfo.toDelimitedByteArray(hri, hri, hri);
178     List<HRegionInfo> regions = HRegionInfo.parseDelimitedFrom(triple, 0, triple.length);
179     assertTrue(regions.size() == 3);
180     assertTrue(regions.get(0).equals(regions.get(1)));
181     assertTrue(regions.get(0).equals(regions.get(2)));
182   }
183 
createRandomRegion(final String name)184   private HRegionInfo createRandomRegion(final String name) {
185     HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name));
186     String [] families = new String [] {"info", "anchor"};
187     for (int i = 0; i < families.length; i++) {
188       htd.addFamily(new HColumnDescriptor(families[i]));
189     }
190     return new HRegionInfo(htd.getTableName(), HConstants.EMPTY_START_ROW,
191       HConstants.EMPTY_END_ROW);
192   }
193 
194   /*
195    * TODO
196   @Test public void testPut() throws Exception{
197     byte[] row = "row".getBytes();
198     byte[] fam = "fam".getBytes();
199     byte[] qf1 = "qf1".getBytes();
200     byte[] qf2 = "qf2".getBytes();
201     byte[] qf3 = "qf3".getBytes();
202     byte[] qf4 = "qf4".getBytes();
203     byte[] qf5 = "qf5".getBytes();
204     byte[] qf6 = "qf6".getBytes();
205     byte[] qf7 = "qf7".getBytes();
206     byte[] qf8 = "qf8".getBytes();
207 
208     long ts = System.currentTimeMillis();
209     byte[] val = "val".getBytes();
210 
211     Put put = new Put(row);
212     put.setWriteToWAL(false);
213     put.add(fam, qf1, ts, val);
214     put.add(fam, qf2, ts, val);
215     put.add(fam, qf3, ts, val);
216     put.add(fam, qf4, ts, val);
217     put.add(fam, qf5, ts, val);
218     put.add(fam, qf6, ts, val);
219     put.add(fam, qf7, ts, val);
220     put.add(fam, qf8, ts, val);
221 
222     byte[] sb = Writables.getBytes(put);
223     Put desPut = (Put)Writables.getWritable(sb, new Put());
224 
225     //Timing test
226 //    long start = System.nanoTime();
227 //    desPut = (Put)Writables.getWritable(sb, new Put());
228 //    long stop = System.nanoTime();
229 //    System.out.println("timer " +(stop-start));
230 
231     assertTrue(Bytes.equals(put.getRow(), desPut.getRow()));
232     List<KeyValue> list = null;
233     List<KeyValue> desList = null;
234     for(Map.Entry<byte[], List<KeyValue>> entry : put.getFamilyMap().entrySet()){
235       assertTrue(desPut.getFamilyMap().containsKey(entry.getKey()));
236       list = entry.getValue();
237       desList = desPut.getFamilyMap().get(entry.getKey());
238       for(int i=0; i<list.size(); i++){
239         assertTrue(list.get(i).equals(desList.get(i)));
240       }
241     }
242   }
243 
244 
245   @Test public void testPut2() throws Exception{
246     byte[] row = "testAbort,,1243116656250".getBytes();
247     byte[] fam = "historian".getBytes();
248     byte[] qf1 = "creation".getBytes();
249 
250     long ts = 9223372036854775807L;
251     byte[] val = "dont-care".getBytes();
252 
253     Put put = new Put(row);
254     put.add(fam, qf1, ts, val);
255 
256     byte[] sb = Writables.getBytes(put);
257     Put desPut = (Put)Writables.getWritable(sb, new Put());
258 
259     assertTrue(Bytes.equals(put.getRow(), desPut.getRow()));
260     List<KeyValue> list = null;
261     List<KeyValue> desList = null;
262     for(Map.Entry<byte[], List<KeyValue>> entry : put.getFamilyMap().entrySet()){
263       assertTrue(desPut.getFamilyMap().containsKey(entry.getKey()));
264       list = entry.getValue();
265       desList = desPut.getFamilyMap().get(entry.getKey());
266       for(int i=0; i<list.size(); i++){
267         assertTrue(list.get(i).equals(desList.get(i)));
268       }
269     }
270   }
271 
272 
273   @Test public void testDelete() throws Exception{
274     byte[] row = "row".getBytes();
275     byte[] fam = "fam".getBytes();
276     byte[] qf1 = "qf1".getBytes();
277 
278     long ts = System.currentTimeMillis();
279 
280     Delete delete = new Delete(row);
281     delete.deleteColumn(fam, qf1, ts);
282 
283     byte[] sb = Writables.getBytes(delete);
284     Delete desDelete = (Delete)Writables.getWritable(sb, new Delete());
285 
286     assertTrue(Bytes.equals(delete.getRow(), desDelete.getRow()));
287     List<KeyValue> list = null;
288     List<KeyValue> desList = null;
289     for(Map.Entry<byte[], List<KeyValue>> entry :
290         delete.getFamilyMap().entrySet()){
291       assertTrue(desDelete.getFamilyMap().containsKey(entry.getKey()));
292       list = entry.getValue();
293       desList = desDelete.getFamilyMap().get(entry.getKey());
294       for(int i=0; i<list.size(); i++){
295         assertTrue(list.get(i).equals(desList.get(i)));
296       }
297     }
298   }
299   */
300 
testGet()301   @Test public void testGet() throws Exception{
302     byte[] row = "row".getBytes();
303     byte[] fam = "fam".getBytes();
304     byte[] qf1 = "qf1".getBytes();
305 
306     long ts = System.currentTimeMillis();
307     int maxVersions = 2;
308 
309     Get get = new Get(row);
310     get.addColumn(fam, qf1);
311     get.setTimeRange(ts, ts+1);
312     get.setMaxVersions(maxVersions);
313 
314     ClientProtos.Get getProto = ProtobufUtil.toGet(get);
315     Get desGet = ProtobufUtil.toGet(getProto);
316 
317     assertTrue(Bytes.equals(get.getRow(), desGet.getRow()));
318     Set<byte[]> set = null;
319     Set<byte[]> desSet = null;
320 
321     for(Map.Entry<byte[], NavigableSet<byte[]>> entry :
322         get.getFamilyMap().entrySet()){
323       assertTrue(desGet.getFamilyMap().containsKey(entry.getKey()));
324       set = entry.getValue();
325       desSet = desGet.getFamilyMap().get(entry.getKey());
326       for(byte [] qualifier : set){
327         assertTrue(desSet.contains(qualifier));
328       }
329     }
330 
331     assertEquals(get.getMaxVersions(), desGet.getMaxVersions());
332     TimeRange tr = get.getTimeRange();
333     TimeRange desTr = desGet.getTimeRange();
334     assertEquals(tr.getMax(), desTr.getMax());
335     assertEquals(tr.getMin(), desTr.getMin());
336   }
337 
338 
testScan()339   @Test public void testScan() throws Exception {
340 
341     byte[] startRow = "startRow".getBytes();
342     byte[] stopRow  = "stopRow".getBytes();
343     byte[] fam = "fam".getBytes();
344     byte[] qf1 = "qf1".getBytes();
345 
346     long ts = System.currentTimeMillis();
347     int maxVersions = 2;
348 
349     Scan scan = new Scan(startRow, stopRow);
350     scan.addColumn(fam, qf1);
351     scan.setTimeRange(ts, ts+1);
352     scan.setMaxVersions(maxVersions);
353 
354     ClientProtos.Scan scanProto = ProtobufUtil.toScan(scan);
355     Scan desScan = ProtobufUtil.toScan(scanProto);
356 
357     assertTrue(Bytes.equals(scan.getStartRow(), desScan.getStartRow()));
358     assertTrue(Bytes.equals(scan.getStopRow(), desScan.getStopRow()));
359     assertEquals(scan.getCacheBlocks(), desScan.getCacheBlocks());
360     Set<byte[]> set = null;
361     Set<byte[]> desSet = null;
362 
363     for(Map.Entry<byte[], NavigableSet<byte[]>> entry :
364         scan.getFamilyMap().entrySet()){
365       assertTrue(desScan.getFamilyMap().containsKey(entry.getKey()));
366       set = entry.getValue();
367       desSet = desScan.getFamilyMap().get(entry.getKey());
368       for(byte[] column : set){
369         assertTrue(desSet.contains(column));
370       }
371 
372       // Test filters are serialized properly.
373       scan = new Scan(startRow);
374       final String name = "testScan";
375       byte [] prefix = Bytes.toBytes(name);
376       scan.setFilter(new PrefixFilter(prefix));
377       scanProto = ProtobufUtil.toScan(scan);
378       desScan = ProtobufUtil.toScan(scanProto);
379       Filter f = desScan.getFilter();
380       assertTrue(f instanceof PrefixFilter);
381     }
382 
383     assertEquals(scan.getMaxVersions(), desScan.getMaxVersions());
384     TimeRange tr = scan.getTimeRange();
385     TimeRange desTr = desScan.getTimeRange();
386     assertEquals(tr.getMax(), desTr.getMax());
387     assertEquals(tr.getMin(), desTr.getMin());
388   }
389 
390   /*
391    * TODO
392   @Test public void testResultEmpty() throws Exception {
393     List<KeyValue> keys = new ArrayList<KeyValue>();
394     Result r = Result.newResult(keys);
395     assertTrue(r.isEmpty());
396     byte [] rb = Writables.getBytes(r);
397     Result deserializedR = (Result)Writables.getWritable(rb, new Result());
398     assertTrue(deserializedR.isEmpty());
399   }
400 
401 
402   @Test public void testResult() throws Exception {
403     byte [] rowA = Bytes.toBytes("rowA");
404     byte [] famA = Bytes.toBytes("famA");
405     byte [] qfA = Bytes.toBytes("qfA");
406     byte [] valueA = Bytes.toBytes("valueA");
407 
408     byte [] rowB = Bytes.toBytes("rowB");
409     byte [] famB = Bytes.toBytes("famB");
410     byte [] qfB = Bytes.toBytes("qfB");
411     byte [] valueB = Bytes.toBytes("valueB");
412 
413     KeyValue kvA = new KeyValue(rowA, famA, qfA, valueA);
414     KeyValue kvB = new KeyValue(rowB, famB, qfB, valueB);
415 
416     Result result = Result.newResult(new KeyValue[]{kvA, kvB});
417 
418     byte [] rb = Writables.getBytes(result);
419     Result deResult = (Result)Writables.getWritable(rb, new Result());
420 
421     assertTrue("results are not equivalent, first key mismatch",
422         result.raw()[0].equals(deResult.raw()[0]));
423 
424     assertTrue("results are not equivalent, second key mismatch",
425         result.raw()[1].equals(deResult.raw()[1]));
426 
427     // Test empty Result
428     Result r = new Result();
429     byte [] b = Writables.getBytes(r);
430     Result deserialized = (Result)Writables.getWritable(b, new Result());
431     assertEquals(r.size(), deserialized.size());
432   }
433 
434   @Test public void testResultDynamicBuild() throws Exception {
435     byte [] rowA = Bytes.toBytes("rowA");
436     byte [] famA = Bytes.toBytes("famA");
437     byte [] qfA = Bytes.toBytes("qfA");
438     byte [] valueA = Bytes.toBytes("valueA");
439 
440     byte [] rowB = Bytes.toBytes("rowB");
441     byte [] famB = Bytes.toBytes("famB");
442     byte [] qfB = Bytes.toBytes("qfB");
443     byte [] valueB = Bytes.toBytes("valueB");
444 
445     KeyValue kvA = new KeyValue(rowA, famA, qfA, valueA);
446     KeyValue kvB = new KeyValue(rowB, famB, qfB, valueB);
447 
448     Result result = Result.newResult(new KeyValue[]{kvA, kvB});
449 
450     byte [] rb = Writables.getBytes(result);
451 
452 
453     // Call getRow() first
454     Result deResult = (Result)Writables.getWritable(rb, new Result());
455     byte [] row = deResult.getRow();
456     assertTrue(Bytes.equals(row, rowA));
457 
458     // Call sorted() first
459     deResult = (Result)Writables.getWritable(rb, new Result());
460     assertTrue("results are not equivalent, first key mismatch",
461         result.raw()[0].equals(deResult.raw()[0]));
462     assertTrue("results are not equivalent, second key mismatch",
463         result.raw()[1].equals(deResult.raw()[1]));
464 
465     // Call raw() first
466     deResult = (Result)Writables.getWritable(rb, new Result());
467     assertTrue("results are not equivalent, first key mismatch",
468         result.raw()[0].equals(deResult.raw()[0]));
469     assertTrue("results are not equivalent, second key mismatch",
470         result.raw()[1].equals(deResult.raw()[1]));
471 
472 
473   }
474 
475   @Test public void testResultArray() throws Exception {
476     byte [] rowA = Bytes.toBytes("rowA");
477     byte [] famA = Bytes.toBytes("famA");
478     byte [] qfA = Bytes.toBytes("qfA");
479     byte [] valueA = Bytes.toBytes("valueA");
480 
481     byte [] rowB = Bytes.toBytes("rowB");
482     byte [] famB = Bytes.toBytes("famB");
483     byte [] qfB = Bytes.toBytes("qfB");
484     byte [] valueB = Bytes.toBytes("valueB");
485 
486     KeyValue kvA = new KeyValue(rowA, famA, qfA, valueA);
487     KeyValue kvB = new KeyValue(rowB, famB, qfB, valueB);
488 
489 
490     Result result1 = Result.newResult(new KeyValue[]{kvA, kvB});
491     Result result2 = Result.newResult(new KeyValue[]{kvB});
492     Result result3 = Result.newResult(new KeyValue[]{kvB});
493 
494     Result [] results = new Result [] {result1, result2, result3};
495 
496     ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
497     DataOutputStream out = new DataOutputStream(byteStream);
498     Result.writeArray(out, results);
499 
500     byte [] rb = byteStream.toByteArray();
501 
502     DataInputBuffer in = new DataInputBuffer();
503     in.reset(rb, 0, rb.length);
504 
505     Result [] deResults = Result.readArray(in);
506 
507     assertTrue(results.length == deResults.length);
508 
509     for(int i=0;i<results.length;i++) {
510       KeyValue [] keysA = results[i].raw();
511       KeyValue [] keysB = deResults[i].raw();
512       assertTrue(keysA.length == keysB.length);
513       for(int j=0;j<keysA.length;j++) {
514         assertTrue("Expected equivalent keys but found:\n" +
515             "KeyA : " + keysA[j].toString() + "\n" +
516             "KeyB : " + keysB[j].toString() + "\n" +
517             keysA.length + " total keys, " + i + "th so far"
518             ,keysA[j].equals(keysB[j]));
519       }
520     }
521 
522   }
523 
524   @Test public void testResultArrayEmpty() throws Exception {
525     List<KeyValue> keys = new ArrayList<KeyValue>();
526     Result r = Result.newResult(keys);
527     Result [] results = new Result [] {r};
528 
529     ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
530     DataOutputStream out = new DataOutputStream(byteStream);
531 
532     Result.writeArray(out, results);
533 
534     results = null;
535 
536     byteStream = new ByteArrayOutputStream();
537     out = new DataOutputStream(byteStream);
538     Result.writeArray(out, results);
539 
540     byte [] rb = byteStream.toByteArray();
541 
542     DataInputBuffer in = new DataInputBuffer();
543     in.reset(rb, 0, rb.length);
544 
545     Result [] deResults = Result.readArray(in);
546 
547     assertTrue(deResults.length == 0);
548 
549     results = new Result[0];
550 
551     byteStream = new ByteArrayOutputStream();
552     out = new DataOutputStream(byteStream);
553     Result.writeArray(out, results);
554 
555     rb = byteStream.toByteArray();
556 
557     in = new DataInputBuffer();
558     in.reset(rb, 0, rb.length);
559 
560     deResults = Result.readArray(in);
561 
562     assertTrue(deResults.length == 0);
563 
564   }
565   */
566 
567   protected static final int MAXVERSIONS = 3;
568   protected final static byte [] fam1 = Bytes.toBytes("colfamily1");
569   protected final static byte [] fam2 = Bytes.toBytes("colfamily2");
570   protected final static byte [] fam3 = Bytes.toBytes("colfamily3");
571   protected static final byte [][] COLUMNS = {fam1, fam2, fam3};
572 
573   /**
574    * Create a table of name <code>name</code> with {@link COLUMNS} for
575    * families.
576    * @param name Name to give table.
577    * @return Column descriptor.
578    */
createTableDescriptor(final String name)579   protected HTableDescriptor createTableDescriptor(final String name) {
580     return createTableDescriptor(name, MAXVERSIONS);
581   }
582 
583   /**
584    * Create a table of name <code>name</code> with {@link COLUMNS} for
585    * families.
586    * @param name Name to give table.
587    * @param versions How many versions to allow per column.
588    * @return Column descriptor.
589    */
createTableDescriptor(final String name, final int versions)590   protected HTableDescriptor createTableDescriptor(final String name,
591       final int versions) {
592     HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name));
593     htd.addFamily(new HColumnDescriptor(fam1)
594         .setMaxVersions(versions)
595         .setBlockCacheEnabled(false)
596     );
597     htd.addFamily(new HColumnDescriptor(fam2)
598         .setMaxVersions(versions)
599         .setBlockCacheEnabled(false)
600     );
601     htd.addFamily(new HColumnDescriptor(fam3)
602         .setMaxVersions(versions)
603         .setBlockCacheEnabled(false)
604     );
605     return htd;
606   }
607 }
608