/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.accumulo.core.file.rfile; import org.apache.accumulo.core.data.Key; import org.junit.Assert; import org.junit.Test; import com.google.common.primitives.Bytes; public class KeyShortenerTest { private static final byte[] E = new byte[0]; private static final byte[] FF = new byte[] {(byte) 0xff}; private void assertBetween(Key p, Key s, Key c) { Assert.assertTrue(p.compareTo(s) < 0); Assert.assertTrue(s.compareTo(c) < 0); } private void testKeys(Key prev, Key current, Key expected) { Key sk = KeyShortener.shorten(prev, current); assertBetween(prev, sk, current); } /** * append 0xff to end of string */ private byte[] apendFF(String s) { return Bytes.concat(s.getBytes(), FF); } /** * append 0x00 to end of string */ private byte[] append00(String s) { return Bytes.concat(s.getBytes(), new byte[] {(byte) 0x00}); } private byte[] toBytes(Object o) { if (o instanceof String) { return ((String) o).getBytes(); } else if (o instanceof byte[]) { return (byte[]) o; } throw new IllegalArgumentException(); } private Key newKey(Object row, Object fam, Object qual, long ts) { return new Key(toBytes(row), toBytes(fam), toBytes(qual), E, ts); } @Test public void testOneCharacterDifference() { // row has char that differs by one byte testKeys(new Key("r321hahahaha", "f89222", "q90232e"), new Key("r321hbhahaha", "f89222", "q90232e"), newKey(apendFF("r321ha"), E, E, 0)); // family has char that differs by one byte testKeys(new Key("r321hahahaha", "f89222", "q90232e"), new Key("r321hahahaha", "f89322", "q90232e"), newKey("r321hahahaha", apendFF("f892"), E, 0)); // qualifier has char that differs by one byte testKeys(new Key("r321hahahaha", "f89222", "q90232e"), new Key("r321hahahaha", "f89222", "q91232e"), newKey("r321hahahaha", "f89222", apendFF("q90"), 0)); } @Test public void testMultiCharacterDifference() { // row has char that differs by two bytes testKeys(new Key("r321hahahaha", "f89222", "q90232e"), new Key("r321hchahaha", "f89222", "q90232e"), newKey("r321hb", E, E, 0)); // family has char that differs by two bytes testKeys(new Key("r321hahahaha", "f89222", "q90232e"), new Key("r321hahahaha", "f89422", "q90232e"), newKey("r321hahahaha", "f893", E, 0)); // qualifier has char that differs by two bytes testKeys(new Key("r321hahahaha", "f89222", "q90232e"), new Key("r321hahahaha", "f89222", "q92232e"), newKey("r321hahahaha", "f89222", "q91", 0)); } @Test public void testOneCharacterDifferenceAndFF() { byte[] ff1 = Bytes.concat(apendFF("mop"), "b".getBytes()); byte[] ff2 = Bytes.concat(apendFF("mop"), FF, "b".getBytes()); byte[] eff1 = Bytes.concat(apendFF("mop"), FF, FF); byte[] eff2 = Bytes.concat(apendFF("mop"), FF, FF, FF); testKeys(newKey(ff1, "f89222", "q90232e", 34), new Key("mor56", "f89222", "q90232e"), newKey(eff1, E, E, 0)); testKeys(newKey("r1", ff1, "q90232e", 34), new Key("r1", "mor56", "q90232e"), newKey("r1", eff1, E, 0)); testKeys(newKey("r1", "f1", ff1, 34), new Key("r1", "f1", "mor56"), newKey("r1", "f1", eff1, 0)); testKeys(newKey(ff2, "f89222", "q90232e", 34), new Key("mor56", "f89222", "q90232e"), newKey(eff2, E, E, 0)); testKeys(newKey("r1", ff2, "q90232e", 34), new Key("r1", "mor56", "q90232e"), newKey("r1", eff2, E, 0)); testKeys(newKey("r1", "f1", ff2, 34), new Key("r1", "f1", "mor56"), newKey("r1", "f1", eff2, 0)); } @Test public void testOneCharacterDifferenceAtEnd() { testKeys(new Key("r321hahahaha", "f89222", "q90232e"), new Key("r321hahahahb", "f89222", "q90232e"), newKey(append00("r321hahahaha"), E, E, 0)); testKeys(new Key("r321hahahaha", "f89222", "q90232e"), new Key("r321hahahaha", "f89223", "q90232e"), newKey("r321hahahaha", append00("f89222"), E, 0)); testKeys(new Key("r321hahahaha", "f89222", "q90232e"), new Key("r321hahahaha", "f89222", "q90232f"), newKey("r321hahahaha", "f89222", append00("q90232e"), 0)); } @Test public void testSamePrefix() { testKeys(new Key("r3boot4", "f89222", "q90232e"), new Key("r3boot452", "f89222", "q90232e"), newKey(append00("r3boot4"), E, E, 0)); testKeys(new Key("r3boot4", "f892", "q90232e"), new Key("r3boot4", "f89222", "q90232e"), newKey("r3boot4", append00("f892"), E, 0)); testKeys(new Key("r3boot4", "f89222", "q902"), new Key("r3boot4", "f89222", "q90232e"), newKey("r3boot4", "f89222", append00("q902"), 0)); } @Test public void testSamePrefixAnd00() { Key prev = new Key("r3boot4", "f89222", "q90232e"); Assert.assertEquals(prev, KeyShortener.shorten(prev, newKey(append00("r3boot4"), "f89222", "q90232e", 8))); prev = new Key("r3boot4", "f892", "q90232e"); Assert.assertEquals(prev, KeyShortener.shorten(prev, newKey("r3boot4", append00("f892"), "q90232e", 8))); prev = new Key("r3boot4", "f89222", "q902"); Assert.assertEquals(prev, KeyShortener.shorten(prev, newKey("r3boot4", "f89222", append00("q902"), 8))); } @Test public void testSanityCheck1() { // prev and shortened equal Key prev = new Key("r001", "f002", "q006"); Assert.assertEquals(prev, KeyShortener.sanityCheck(prev, new Key("r002", "f002", "q006"), new Key("r001", "f002", "q006"))); // prev > shortened equal Assert.assertEquals(prev, KeyShortener.sanityCheck(prev, new Key("r003", "f002", "q006"), new Key("r001", "f002", "q006"))); // current and shortened equal Assert.assertEquals(prev, KeyShortener.sanityCheck(prev, new Key("r003", "f002", "q006"), new Key("r003", "f002", "q006"))); // shortened > current Assert.assertEquals(prev, KeyShortener.sanityCheck(prev, new Key("r003", "f002", "q006"), new Key("r004", "f002", "q006"))); } }