1   /**
2    * Copyright 2009 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase;
21  
22  import java.io.IOException;
23  import java.util.Set;
24  import java.util.TreeSet;
25  
26  import junit.framework.TestCase;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.hadoop.hbase.KeyValue.KVComparator;
31  import org.apache.hadoop.hbase.KeyValue.Type;
32  import org.apache.hadoop.hbase.util.Bytes;
33  
34  public class TestKeyValue extends TestCase {
35    private final Log LOG = LogFactory.getLog(this.getClass().getName());
36  
37    public void testColumnCompare() throws Exception {
38      final byte [] a = Bytes.toBytes("aaa");
39      byte [] family1 = Bytes.toBytes("abc");
40      byte [] qualifier1 = Bytes.toBytes("def");
41      byte [] family2 = Bytes.toBytes("abcd");
42      byte [] qualifier2 = Bytes.toBytes("ef");
43  
44      KeyValue aaa = new KeyValue(a, family1, qualifier1, 0L, Type.Put, a);
45      assertFalse(aaa.matchingColumn(family2, qualifier2));
46      assertTrue(aaa.matchingColumn(family1, qualifier1));
47      aaa = new KeyValue(a, family2, qualifier2, 0L, Type.Put, a);
48      assertFalse(aaa.matchingColumn(family1, qualifier1));
49      assertTrue(aaa.matchingColumn(family2,qualifier2));
50      byte [] nullQualifier = new byte[0];
51      aaa = new KeyValue(a, family1, nullQualifier, 0L, Type.Put, a);
52      assertTrue(aaa.matchingColumn(family1,null));
53      assertFalse(aaa.matchingColumn(family2,qualifier2));
54    }
55  
56    public void testBasics() throws Exception {
57      LOG.info("LOWKEY: " + KeyValue.LOWESTKEY.toString());
58      check(Bytes.toBytes(getName()),
59        Bytes.toBytes(getName()), Bytes.toBytes(getName()), 1,
60        Bytes.toBytes(getName()));
61      // Test empty value and empty column -- both should work. (not empty fam)
62      check(Bytes.toBytes(getName()), Bytes.toBytes(getName()), null, 1, null);
63      check(HConstants.EMPTY_BYTE_ARRAY, Bytes.toBytes(getName()), null, 1, null);
64    }
65  
66    private void check(final byte [] row, final byte [] family, byte [] qualifier,
67      final long timestamp, final byte [] value) {
68      KeyValue kv = new KeyValue(row, family, qualifier, timestamp, value);
69      assertTrue(Bytes.compareTo(kv.getRow(), row) == 0);
70      assertTrue(kv.matchingColumn(family, qualifier));
71      // Call toString to make sure it works.
72      LOG.info(kv.toString());
73    }
74  
75    public void testPlainCompare() throws Exception {
76      final byte [] a = Bytes.toBytes("aaa");
77      final byte [] b = Bytes.toBytes("bbb");
78      final byte [] fam = Bytes.toBytes("col");
79      final byte [] qf = Bytes.toBytes("umn");
80  //    final byte [] column = Bytes.toBytes("col:umn");
81      KeyValue aaa = new KeyValue(a, fam, qf, a);
82      KeyValue bbb = new KeyValue(b, fam, qf, b);
83      byte [] keyabb = aaa.getKey();
84      byte [] keybbb = bbb.getKey();
85      assertTrue(KeyValue.COMPARATOR.compare(aaa, bbb) < 0);
86      assertTrue(KeyValue.KEY_COMPARATOR.compare(keyabb, 0, keyabb.length, keybbb,
87        0, keybbb.length) < 0);
88      assertTrue(KeyValue.COMPARATOR.compare(bbb, aaa) > 0);
89      assertTrue(KeyValue.KEY_COMPARATOR.compare(keybbb, 0, keybbb.length, keyabb,
90        0, keyabb.length) > 0);
91      // Compare breaks if passed same ByteBuffer as both left and right arguments.
92      assertTrue(KeyValue.COMPARATOR.compare(bbb, bbb) == 0);
93      assertTrue(KeyValue.KEY_COMPARATOR.compare(keybbb, 0, keybbb.length, keybbb,
94        0, keybbb.length) == 0);
95      assertTrue(KeyValue.COMPARATOR.compare(aaa, aaa) == 0);
96      assertTrue(KeyValue.KEY_COMPARATOR.compare(keyabb, 0, keyabb.length, keyabb,
97        0, keyabb.length) == 0);
98      // Do compare with different timestamps.
99      aaa = new KeyValue(a, fam, qf, 1, a);
100     bbb = new KeyValue(a, fam, qf, 2, a);
101     assertTrue(KeyValue.COMPARATOR.compare(aaa, bbb) > 0);
102     assertTrue(KeyValue.COMPARATOR.compare(bbb, aaa) < 0);
103     assertTrue(KeyValue.COMPARATOR.compare(aaa, aaa) == 0);
104     // Do compare with different types.  Higher numbered types -- Delete
105     // should sort ahead of lower numbers; i.e. Put
106     aaa = new KeyValue(a, fam, qf, 1, KeyValue.Type.Delete, a);
107     bbb = new KeyValue(a, fam, qf, 1, a);
108     assertTrue(KeyValue.COMPARATOR.compare(aaa, bbb) < 0);
109     assertTrue(KeyValue.COMPARATOR.compare(bbb, aaa) > 0);
110     assertTrue(KeyValue.COMPARATOR.compare(aaa, aaa) == 0);
111   }
112 
113   public void testMoreComparisons() throws Exception {
114     // Root compares
115     long now = System.currentTimeMillis();
116     KeyValue a = new KeyValue(Bytes.toBytes(".META.,,99999999999999"), now);
117     KeyValue b = new KeyValue(Bytes.toBytes(".META.,,1"), now);
118     KVComparator c = new KeyValue.RootComparator();
119     assertTrue(c.compare(b, a) < 0);
120     KeyValue aa = new KeyValue(Bytes.toBytes(".META.,,1"), now);
121     KeyValue bb = new KeyValue(Bytes.toBytes(".META.,,1"),
122         Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1235943454602L,
123         (byte[])null);
124     assertTrue(c.compare(aa, bb) < 0);
125 
126     // Meta compares
127     KeyValue aaa = new KeyValue(
128         Bytes.toBytes("TestScanMultipleVersions,row_0500,1236020145502"), now);
129     KeyValue bbb = new KeyValue(
130         Bytes.toBytes("TestScanMultipleVersions,,99999999999999"), now);
131     c = new KeyValue.MetaComparator();
132     assertTrue(c.compare(bbb, aaa) < 0);
133 
134     KeyValue aaaa = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,,1236023996656"),
135         Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236024396271L,
136         (byte[])null);
137     assertTrue(c.compare(aaaa, bbb) < 0);
138 
139     KeyValue x = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"),
140         Bytes.toBytes("info"), Bytes.toBytes(""), 9223372036854775807L,
141         (byte[])null);
142     KeyValue y = new KeyValue(Bytes.toBytes("TestScanMultipleVersions,row_0500,1236034574162"),
143         Bytes.toBytes("info"), Bytes.toBytes("regioninfo"), 1236034574912L,
144         (byte[])null);
145     assertTrue(c.compare(x, y) < 0);
146     comparisons(new KeyValue.MetaComparator());
147     comparisons(new KeyValue.KVComparator());
148     metacomparisons(new KeyValue.RootComparator());
149     metacomparisons(new KeyValue.MetaComparator());
150   }
151 
152   /**
153    * Tests cases where rows keys have characters below the ','.
154    * See HBASE-832
155    * @throws IOException
156    */
157   public void testKeyValueBorderCases() throws IOException {
158     // % sorts before , so if we don't do special comparator, rowB would
159     // come before rowA.
160     KeyValue rowA = new KeyValue(Bytes.toBytes("testtable,www.hbase.org/,1234"),
161       Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
162     KeyValue rowB = new KeyValue(Bytes.toBytes("testtable,www.hbase.org/%20,99999"),
163         Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
164     assertTrue(KeyValue.META_COMPARATOR.compare(rowA, rowB) < 0);
165 
166     rowA = new KeyValue(Bytes.toBytes("testtable,,1234"), Bytes.toBytes("fam"),
167         Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
168     rowB = new KeyValue(Bytes.toBytes("testtable,$www.hbase.org/,99999"),
169         Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
170     assertTrue(KeyValue.META_COMPARATOR.compare(rowA, rowB) < 0);
171 
172     rowA = new KeyValue(Bytes.toBytes(".META.,testtable,www.hbase.org/,1234,4321"),
173         Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
174     rowB = new KeyValue(Bytes.toBytes(".META.,testtable,www.hbase.org/%20,99999,99999"),
175         Bytes.toBytes("fam"), Bytes.toBytes(""), Long.MAX_VALUE, (byte[])null);
176     assertTrue(KeyValue.ROOT_COMPARATOR.compare(rowA, rowB) < 0);
177   }
178 
179   private void metacomparisons(final KeyValue.MetaComparator c) {
180     long now = System.currentTimeMillis();
181     assertTrue(c.compare(new KeyValue(Bytes.toBytes(".META.,a,,0,1"), now),
182       new KeyValue(Bytes.toBytes(".META.,a,,0,1"), now)) == 0);
183     KeyValue a = new KeyValue(Bytes.toBytes(".META.,a,,0,1"), now);
184     KeyValue b = new KeyValue(Bytes.toBytes(".META.,a,,0,2"), now);
185     assertTrue(c.compare(a, b) < 0);
186     assertTrue(c.compare(new KeyValue(Bytes.toBytes(".META.,a,,0,2"), now),
187       new KeyValue(Bytes.toBytes(".META.,a,,0,1"), now)) > 0);
188   }
189 
190   private void comparisons(final KeyValue.KVComparator c) {
191     long now = System.currentTimeMillis();
192     assertTrue(c.compare(new KeyValue(Bytes.toBytes(".META.,,1"), now),
193       new KeyValue(Bytes.toBytes(".META.,,1"), now)) == 0);
194     assertTrue(c.compare(new KeyValue(Bytes.toBytes(".META.,,1"), now),
195       new KeyValue(Bytes.toBytes(".META.,,2"), now)) < 0);
196     assertTrue(c.compare(new KeyValue(Bytes.toBytes(".META.,,2"), now),
197       new KeyValue(Bytes.toBytes(".META.,,1"), now)) > 0);
198   }
199 
200   public void testBinaryKeys() throws Exception {
201     Set<KeyValue> set = new TreeSet<KeyValue>(KeyValue.COMPARATOR);
202     final byte [] fam = Bytes.toBytes("col");
203     final byte [] qf = Bytes.toBytes("umn");
204     final byte [] nb = new byte[0];
205     KeyValue [] keys = {new KeyValue(Bytes.toBytes("aaaaa,\u0000\u0000,2"), fam, qf, 2, nb),
206       new KeyValue(Bytes.toBytes("aaaaa,\u0001,3"), fam, qf, 3, nb),
207       new KeyValue(Bytes.toBytes("aaaaa,,1"), fam, qf, 1, nb),
208       new KeyValue(Bytes.toBytes("aaaaa,\u1000,5"), fam, qf, 5, nb),
209       new KeyValue(Bytes.toBytes("aaaaa,a,4"), fam, qf, 4, nb),
210       new KeyValue(Bytes.toBytes("a,a,0"), fam, qf, 0, nb),
211     };
212     // Add to set with bad comparator
213     for (int i = 0; i < keys.length; i++) {
214       set.add(keys[i]);
215     }
216     // This will output the keys incorrectly.
217     boolean assertion = false;
218     int count = 0;
219     try {
220       for (KeyValue k: set) {
221         assertTrue(count++ == k.getTimestamp());
222       }
223     } catch (junit.framework.AssertionFailedError e) {
224       // Expected
225       assertion = true;
226     }
227     assertTrue(assertion);
228     // Make set with good comparator
229     set = new TreeSet<KeyValue>(new KeyValue.MetaComparator());
230     for (int i = 0; i < keys.length; i++) {
231       set.add(keys[i]);
232     }
233     count = 0;
234     for (KeyValue k: set) {
235       assertTrue(count++ == k.getTimestamp());
236     }
237     // Make up -ROOT- table keys.
238     KeyValue [] rootKeys = {
239         new KeyValue(Bytes.toBytes(".META.,aaaaa,\u0000\u0000,0,2"), fam, qf, 2, nb),
240         new KeyValue(Bytes.toBytes(".META.,aaaaa,\u0001,0,3"), fam, qf, 3, nb),
241         new KeyValue(Bytes.toBytes(".META.,aaaaa,,0,1"), fam, qf, 1, nb),
242         new KeyValue(Bytes.toBytes(".META.,aaaaa,\u1000,0,5"), fam, qf, 5, nb),
243         new KeyValue(Bytes.toBytes(".META.,aaaaa,a,0,4"), fam, qf, 4, nb),
244         new KeyValue(Bytes.toBytes(".META.,,0"), fam, qf, 0, nb),
245       };
246     // This will output the keys incorrectly.
247     set = new TreeSet<KeyValue>(new KeyValue.MetaComparator());
248     // Add to set with bad comparator
249     for (int i = 0; i < keys.length; i++) {
250       set.add(rootKeys[i]);
251     }
252     assertion = false;
253     count = 0;
254     try {
255       for (KeyValue k: set) {
256         assertTrue(count++ == k.getTimestamp());
257       }
258     } catch (junit.framework.AssertionFailedError e) {
259       // Expected
260       assertion = true;
261     }
262     // Now with right comparator
263     set = new TreeSet<KeyValue>(new KeyValue.RootComparator());
264     // Add to set with bad comparator
265     for (int i = 0; i < keys.length; i++) {
266       set.add(rootKeys[i]);
267     }
268     count = 0;
269     for (KeyValue k: set) {
270       assertTrue(count++ == k.getTimestamp());
271     }
272   }
273 
274   public void testStackedUpKeyValue() {
275     // Test multiple KeyValues in a single blob.
276 
277     // TODO actually write this test!
278 
279   }
280 
281   private final byte[] rowA = Bytes.toBytes("rowA");
282   private final byte[] rowB = Bytes.toBytes("rowB");
283 
284   private final byte[] family = Bytes.toBytes("family");
285   private final byte[] qualA = Bytes.toBytes("qfA");
286 
287   private void assertKVLess(KeyValue.KVComparator c,
288                             KeyValue less,
289                             KeyValue greater) {
290     int cmp = c.compare(less,greater);
291     assertTrue(cmp < 0);
292     cmp = c.compare(greater,less);
293     assertTrue(cmp > 0);
294   }
295 
296   public void testFirstLastOnRow() {
297     final KVComparator c = KeyValue.COMPARATOR;
298     long ts = 1;
299 
300     // These are listed in sort order (ie: every one should be less
301     // than the one on the next line).
302     final KeyValue firstOnRowA = KeyValue.createFirstOnRow(rowA);
303     final KeyValue kvA_1 = new KeyValue(rowA, null, null, ts, Type.Put);
304     final KeyValue kvA_2 = new KeyValue(rowA, family, qualA, ts, Type.Put);
305         
306     final KeyValue lastOnRowA = KeyValue.createLastOnRow(rowA);
307     final KeyValue firstOnRowB = KeyValue.createFirstOnRow(rowB);
308     final KeyValue kvB = new KeyValue(rowB, family, qualA, ts, Type.Put);
309 
310     assertKVLess(c, firstOnRowA, firstOnRowB);
311     assertKVLess(c, firstOnRowA, kvA_1);
312     assertKVLess(c, firstOnRowA, kvA_2);
313     assertKVLess(c, kvA_1, kvA_2);
314     assertKVLess(c, kvA_2, firstOnRowB);
315     assertKVLess(c, kvA_1, firstOnRowB);
316 
317     assertKVLess(c, lastOnRowA, firstOnRowB);
318     assertKVLess(c, firstOnRowB, kvB);
319     assertKVLess(c, lastOnRowA, kvB);
320 
321     assertKVLess(c, kvA_2, lastOnRowA);
322     assertKVLess(c, kvA_1, lastOnRowA);
323     assertKVLess(c, firstOnRowA, lastOnRowA);
324   }
325 
326   public void testConvertToKeyOnly() throws Exception {
327     long ts = 1;
328     byte [] value = Bytes.toBytes("a real value");
329     byte [] evalue = new byte[0]; // empty value
330 
331     for (byte[] val : new byte[][]{value, evalue}) {
332       for (boolean useLen : new boolean[]{false,true}) {
333         KeyValue kv1 = new KeyValue(rowA, family, qualA, ts, val);
334         KeyValue kv1ko = kv1.clone();
335         assertTrue(kv1.equals(kv1ko));
336         kv1ko.convertToKeyOnly(useLen);
337         // keys are still the same
338         assertTrue(kv1.equals(kv1ko));
339         // but values are not
340         assertTrue(kv1ko.getValue().length == (useLen?Bytes.SIZEOF_INT:0));
341         if (useLen) {
342           assertEquals(kv1.getValueLength(), Bytes.toInt(kv1ko.getValue()));
343         }
344       }
345     }
346   }
347 }