From 219a6ceb67b42b5f8de2707bf3151f53d39ecc74 Mon Sep 17 00:00:00 2001 From: Mario Pastorelli Date: Thu, 1 Sep 2016 01:32:40 +0200 Subject: [PATCH 1/8] ACCUMULO-4376 add KeyBuilder --- .../org/apache/accumulo/core/data/Key.java | 38 +++ .../apache/accumulo/core/data/KeyBuilder.java | 278 ++++++++++++++++++ .../accumulo/core/data/KeyBuilderTest.java | 239 +++++++++++++++ 3 files changed, 555 insertions(+) create mode 100644 core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java create mode 100644 core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java diff --git a/core/src/main/java/org/apache/accumulo/core/data/Key.java b/core/src/main/java/org/apache/accumulo/core/data/Key.java index 66ad5ca6e33..4ff35384365 100644 --- a/core/src/main/java/org/apache/accumulo/core/data/Key.java +++ b/core/src/main/java/org/apache/accumulo/core/data/Key.java @@ -184,6 +184,44 @@ public Key(byte row[], int rOff, int rLen, byte cf[], int cfOff, int cfLen, byte init(row, rOff, rLen, cf, cfOff, cfLen, cq, cqOff, cqLen, cv, cvOff, cvLen, ts, false, true); } + /** + * Creates a key. + * + * @param row + * bytes containing row ID + * @param rOff + * offset into row where key's row ID begins (inclusive) + * @param rLen + * length of row ID in row + * @param cf + * bytes containing column family + * @param cfOff + * offset into cf where key's column family begins (inclusive) + * @param cfLen + * length of column family in cf + * @param cq + * bytes containing column qualifier + * @param cqOff + * offset into cq where key's column qualifier begins (inclusive) + * @param cqLen + * length of column qualifier in cq + * @param cv + * bytes containing column visibility + * @param cvOff + * offset into cv where key's column visibility begins (inclusive) + * @param cvLen + * length of column visibility in cv + * @param ts + * timestamp + * @param deleted + * delete marker + * @param copy + * if true, forces copy of byte array values into key + */ + public Key(byte row[], int rOff, int rLen, byte cf[], int cfOff, int cfLen, byte cq[], int cqOff, int cqLen, byte cv[], int cvOff, int cvLen, long ts, boolean deleted, boolean copy) { + init(row, rOff, rLen, cf, cfOff, cfLen, cq, cqOff, cqLen, cv, cvOff, cvLen, ts, deleted, copy); + } + /** * Creates a key. The delete marker defaults to false. This constructor creates a copy of each specified array. If you don't want to create a copy of the * arrays, you should call {@link Key#Key(byte[] row, byte[] cf, byte[] cq, byte[] cv, long ts, boolean deleted, boolean copy)} instead. diff --git a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java new file mode 100644 index 00000000000..f5aa8747c66 --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java @@ -0,0 +1,278 @@ +/* + * 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.data; + + +import org.apache.hadoop.io.Text; + +/** + * A builder used to build Keys by defining their components. + * + * The rules are: + * + * + * The builder supports three types of components: byte[], Text and CharSequence. + * + * The builder is mutable and not thread safe. + * + * @see org.apache.accumulo.core.data.Key + * @since 1.8 + */ +public class KeyBuilder { + + public interface Build { + + /** + * Build a Key from this builder. + * + * @param copyBytes + * if the byte arrays should be copied or not. If not, byte arrays will be reused in the resultant Key + * @return + * the Key built from this builder + */ + Key build(boolean copyBytes); + + /** + * Build a Key from this builder. copyBytes defaults to true. + * + * @return + * the Key built from this builder + */ + Key build(); + + /** + * Change the timestamp of the Key created. + * + * @param timestamp + * the timestamp to use for the Key + * @return this builder + */ + Build timestamp(long timestamp); + + /** + * Set the deleted marker of the Key to the parameter. + * + * @param deleted + * if the Key should be marked as deleted or not + * @return this builder + */ + Build deleted(boolean deleted); + } + + public interface ColumnFamilyStep extends ColumnVisibilityStep { + + /** + * Set the column family of the Key that this builder will build to the parameter. + * + * @param columnFamily + * the column family to use for the Key + * @return this builder + */ + ColumnQualifierStep columnFamily(final T columnFamily); + + /** + * Set the column family, qualifier and visibility of the Key that this builder will build to the parameter. + * + * @param columnFamily + * the column family to use for the Key + * @param columnQualifier + * the column qualifier to use for the Key + * @param columnVisibility + * the column visibility to use for the Key + * @return this builder + */ + Build column(final T columnFamily, final T columnQualifier, final T columnVisibility); + + /** + * Set the column family and the qualifier of the Key that this builder will build to the parameter. + * + * @param columnFamily + * the column family to use for the Key + * @param columnQualifier + * the column qualifier to use for the Key + * @return this builder + */ + ColumnVisibilityStep column(final T columnFamily, final T columnQualifier); + } + + public interface ColumnQualifierStep extends ColumnVisibilityStep { + + /** + * Set the column qualifier of the Key that this builder will build to the parameter. + * + * @param columnQualifier + * the column qualifier to use for the Key + * @return this builder + */ + ColumnVisibilityStep columnQualifier(final T columnQualifier); + } + + public interface ColumnVisibilityStep extends Build { + /** + * Set the column qualifier of the Key that this builder will build to the parameter. + * + * @param columnVisibility + * the column visibility to use for the Key + * @return this builder + */ + Build columnVisibility(final T columnVisibility); + } + + private static abstract class AbstractKeyBuilder implements ColumnFamilyStep, ColumnQualifierStep, + ColumnVisibilityStep { + + protected static final byte EMPTY_BYTES[] = new byte[0]; + + protected T row = null; + protected T columnFamily = null; + protected T columnQualifier = null; + protected T columnVisibility = null; + protected long timestamp = Long.MAX_VALUE; + protected boolean deleted = false; + + final public ColumnFamilyStep row(final T row) { + this.row = row; + return this; + } + + @Override + final public ColumnQualifierStep columnFamily(final T columnFamily) { + this.columnFamily = columnFamily; + return this; + } + + @Override + final public ColumnVisibilityStep columnQualifier(final T columnQualifier) { + this.columnQualifier = columnQualifier; + return this; + } + + @Override + final public Build columnVisibility(final T columnVisibility) { + this.columnVisibility = columnVisibility; + return this; + } + + @Override + final public Build timestamp(long timestamp) { + this.timestamp = timestamp; + return this; + } + + @Override + public Build deleted(boolean deleted) { + this.deleted = deleted; + return this; + } + + @Override + public Key build() { + return this.build(true); + } + + @Override + public Build column(final T columnFamily, final T columnQualifier, final T columnVisibility) { + return this.columnFamily(columnFamily).columnQualifier(columnQualifier).columnVisibility(columnVisibility); + } + + @Override + public ColumnVisibilityStep column(final T columnFamily, final T columnQualifier) { + return this.columnFamily(columnFamily).columnQualifier(columnQualifier); + } + } + + private static class TextKeyBuilder extends AbstractKeyBuilder { + + private final Text EMPTY_TEXT = new Text(); + + @Override + public Key build(boolean copyBytes) { + Text columnFamily = (this.columnFamily == null) ? EMPTY_TEXT : this.columnFamily; + Text columnQualifier = (this.columnQualifier == null) ? EMPTY_TEXT : this.columnQualifier; + Text columnVisibility = (this.columnVisibility == null) ? EMPTY_TEXT : this.columnVisibility; + return new Key(row.getBytes(), 0, row.getLength(), columnFamily.getBytes(), 0, columnFamily.getLength(), + columnQualifier.getBytes(), 0, columnQualifier.getLength(), columnVisibility.getBytes(), 0, + columnVisibility.getLength(), timestamp, deleted, copyBytes); + } + } + + private static class ByteArrayKeyBuilder extends AbstractKeyBuilder { + + @Override + public Key build(boolean copyBytes) { + byte[] columnFamily = (this.columnFamily == null) ? EMPTY_BYTES : this.columnFamily; + byte[] columnQualifier = (this.columnQualifier == null) ? EMPTY_BYTES : this.columnQualifier; + byte[] columnVisibility = (this.columnVisibility == null) ? EMPTY_BYTES : this.columnVisibility; + return new Key(row, columnFamily, columnQualifier, columnVisibility, timestamp, deleted, copyBytes); + } + } + + private static class CharSequenceKeyBuilder extends AbstractKeyBuilder { + + private final Text EMPTY_TEXT = new Text(); + + @Override + public Key build(boolean copyBytes) { + Text rowText = new Text(row.toString()); + Text columnFamilyText = (this.columnFamily == null) ? EMPTY_TEXT : new Text(this.columnFamily.toString()); + Text columnQualifierText = (this.columnQualifier == null) ? EMPTY_TEXT : new Text(this.columnQualifier.toString()); + Text columnVisibilityText = (this.columnVisibility == null) ? EMPTY_TEXT : new Text(this.columnVisibility.toString()); + return new Key(rowText.getBytes(), 0, rowText.getLength(), columnFamilyText.getBytes(), 0, + columnFamilyText.getLength(), columnQualifierText.getBytes(), 0, columnQualifierText.getLength(), + columnVisibilityText.getBytes(), 0, columnVisibilityText.getLength(), timestamp, deleted, copyBytes); + } + } + + /** + * Set the row of the Key that this builder will build to the parameter. + * + * @param row + * the row to use for the key + * @return this builder + */ + public static ColumnFamilyStep row(final Text row) { + return new TextKeyBuilder().row(row); + } + + /** + * Set the row of the Key that this builder will build to the parameter. + * + * @param row + * the row to use for the key + * @return this builder + */ + public static ColumnFamilyStep row(final byte[] row) { + return new ByteArrayKeyBuilder().row(row); + } + + /** + * Set the row of the Key that this builder will build to the parameter. + * + * @param row + * the row to use for the key + * @return this builder + */ + public static ColumnFamilyStep row( final CharSequence row) { + return new CharSequenceKeyBuilder().row(row); + } +} diff --git a/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java b/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java new file mode 100644 index 00000000000..cc706957e8e --- /dev/null +++ b/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java @@ -0,0 +1,239 @@ +package org.apache.accumulo.core.data; + +import org.apache.hadoop.io.Text; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class KeyBuilderTest { + + private static final byte EMPTY_BYTES[] = new byte[0]; + byte[] rowBytes = "row".getBytes(); + byte[] familyBytes = "family".getBytes(); + byte[] qualifierBytes = "qualifier".getBytes(); + byte[] visibilityBytes = "visibility".getBytes(); + Text rowText = new Text(rowBytes); + Text familyText = new Text(familyBytes); + Text qualifierText = new Text(qualifierBytes); + Text visibilityText = new Text(visibilityBytes); + + @Test + public void testKeyBuildingFromRow() { + Key keyBuilt = KeyBuilder.row("foo").build(); + Key keyExpected = new Key("foo"); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamily() { + Key keyBuilt = KeyBuilder.row("foo").columnFamily("bar").build(); + Key keyExpected = new Key("foo", "bar"); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifier() { + Key keyBuilt = KeyBuilder.row("foo").columnFamily("bar").columnQualifier("baz").build(); + Key keyExpected = new Key("foo", "bar", "baz"); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierVisibility() { + Key keyBuilt = KeyBuilder.row("foo").columnFamily("bar").columnQualifier("baz").columnVisibility("v").build(); + Key keyExpected = new Key("foo", "bar", "baz", "v"); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestamp() { + Key keyBuilt = KeyBuilder.row("foo").columnFamily("bar").columnQualifier("baz").columnVisibility("v").timestamp(1L).build(); + Key keyExpected = new Key("foo", "bar", "baz", "v", 1L); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestampDeleted() { + Key keyBuilt = + KeyBuilder + .row("foo") + .columnFamily("bar") + .columnQualifier("baz") + .columnVisibility("v") + .timestamp(10L) + .deleted(true) + .build(); + Key keyExpected = new Key("foo", "bar", "baz", "v", 10L); + keyExpected.setDeleted(true); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowVisibility() { + Key keyBuilt = KeyBuilder.row("foo").columnVisibility("v").build(); + Key keyExpected = new Key("foo", "", "", "v"); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyVisibility() { + Key keyBuilt = KeyBuilder.row("foo").columnFamily("bar").columnVisibility("v").build(); + Key keyExpected = new Key("foo", "bar", "", "v"); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void textKeyBuildingFromRowTimestamp() { + Key keyBuilt = KeyBuilder.row("foo").timestamp(3L).build(); + Key keyExpected = new Key("foo"); + keyExpected.setTimestamp(3L); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowBytes() { + Key keyBuilt = KeyBuilder.row(rowBytes).build(); + Key keyExpected = new Key(rowBytes, EMPTY_BYTES, EMPTY_BYTES, EMPTY_BYTES, Long.MAX_VALUE); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyBytes() { + Key keyBuilt = KeyBuilder.row(rowBytes).columnFamily(familyBytes).build(); + Key keyExpected = new Key(rowBytes, familyBytes, EMPTY_BYTES, EMPTY_BYTES, Long.MAX_VALUE); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierBytes() { + Key keyBuilt = KeyBuilder.row(rowBytes).columnFamily(familyBytes).columnQualifier(qualifierBytes).build(); + Key keyExpected = new Key(rowBytes, familyBytes, qualifierBytes, EMPTY_BYTES, Long.MAX_VALUE); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierVisibilityBytes() { + Key keyBuilt = KeyBuilder.row(rowBytes).columnFamily(familyBytes).columnQualifier(qualifierBytes).columnVisibility(visibilityBytes).build(); + Key keyExpected = new Key(rowBytes, familyBytes, qualifierBytes, visibilityBytes, Long.MAX_VALUE); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestampBytes() { + Key keyBuilt = KeyBuilder.row(rowBytes).columnFamily(familyBytes).columnQualifier(qualifierBytes).columnVisibility(visibilityBytes).timestamp(1L).build(); + Key keyExpected = new Key(rowBytes, familyBytes, qualifierBytes, visibilityBytes, 1L); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestampDeletedBytes() { + Key keyBuilt = + KeyBuilder + .row(rowBytes) + .columnFamily(familyBytes) + .columnQualifier(qualifierBytes) + .columnVisibility(visibilityBytes) + .timestamp(10L) + .deleted(true) + .build(); + Key keyExpected = new Key(rowBytes, familyBytes, qualifierBytes, visibilityBytes, 10L); + keyExpected.setDeleted(true); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowVisibilityBytes() { + Key keyBuilt = KeyBuilder.row(rowBytes).columnVisibility(visibilityBytes).build(); + Key keyExpected = new Key(rowBytes, EMPTY_BYTES, EMPTY_BYTES, visibilityBytes, Long.MAX_VALUE); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyVisibilityBytes() { + Key keyBuilt = KeyBuilder.row(rowBytes).columnFamily(familyBytes).columnVisibility(visibilityBytes).build(); + Key keyExpected = new Key(rowBytes, familyBytes, EMPTY_BYTES, visibilityBytes, Long.MAX_VALUE); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void textKeyBuildingFromRowTimestampBytes() { + Key keyBuilt = KeyBuilder.row(rowBytes).timestamp(3L).build(); + Key keyExpected = new Key(rowBytes, EMPTY_BYTES, EMPTY_BYTES, EMPTY_BYTES, Long.MAX_VALUE); + keyExpected.setTimestamp(3L); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowText() { + Key keyBuilt = KeyBuilder.row(rowText).build(); + Key keyExpected = new Key(rowText); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyText() { + Key keyBuilt = KeyBuilder.row(rowText).columnFamily(familyText).build(); + Key keyExpected = new Key(rowText, familyText); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierText() { + Key keyBuilt = KeyBuilder.row(rowText).columnFamily(familyText).columnQualifier(qualifierText).build(); + Key keyExpected = new Key(rowText, familyText, qualifierText); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierVisibilityText() { + Key keyBuilt = KeyBuilder.row(rowText).columnFamily(familyText).columnQualifier(qualifierText).columnVisibility(visibilityText).build(); + Key keyExpected = new Key(rowText, familyText, qualifierText, visibilityText); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestampText() { + Key keyBuilt = KeyBuilder.row(rowText).columnFamily(familyText).columnQualifier(qualifierText).columnVisibility(visibilityText).timestamp(1L).build(); + Key keyExpected = new Key(rowText, familyText, qualifierText, visibilityText, 1L); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestampDeletedText() { + Key keyBuilt = + KeyBuilder + .row(rowText) + .columnFamily(familyText) + .columnQualifier(qualifierText) + .columnVisibility(visibilityText) + .timestamp(10L) + .deleted(true) + .build(); + Key keyExpected = new Key(rowText, familyText, qualifierText, visibilityText, 10L); + keyExpected.setDeleted(true); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowVisibilityText() { + Key keyBuilt = KeyBuilder.row(rowText).columnVisibility(visibilityText).build(); + Key keyExpected = new Key(rowText, new Text(), new Text(), visibilityText); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void testKeyBuildingFromRowFamilyVisibilityText() { + Key keyBuilt = KeyBuilder.row(rowText).columnFamily(familyText).columnVisibility(visibilityText).build(); + Key keyExpected = new Key(rowText, familyText, new Text(), visibilityText); + assertEquals(keyBuilt, keyExpected); + } + + @Test + public void textKeyBuildingFromRowTimestampText() { + Key keyBuilt = KeyBuilder.row(rowText).timestamp(3L).build(); + Key keyExpected = new Key(rowText); + keyExpected.setTimestamp(3L); + assertEquals(keyBuilt, keyExpected); + } + +} \ No newline at end of file From 7e75219654a78370ddf4774fce7d212f1838dd0a Mon Sep 17 00:00:00 2001 From: Mario Pastorelli Date: Fri, 2 Sep 2016 00:07:57 +0200 Subject: [PATCH 2/8] switch to heterogeneous KeyBuilder --- .../org/apache/accumulo/core/data/Key.java | 60 ++-- .../apache/accumulo/core/data/KeyBuilder.java | 294 ++++++++++-------- .../accumulo/core/data/KeyBuilderTest.java | 171 ++++++---- 3 files changed, 286 insertions(+), 239 deletions(-) diff --git a/core/src/main/java/org/apache/accumulo/core/data/Key.java b/core/src/main/java/org/apache/accumulo/core/data/Key.java index 4ff35384365..a2c3a2658a3 100644 --- a/core/src/main/java/org/apache/accumulo/core/data/Key.java +++ b/core/src/main/java/org/apache/accumulo/core/data/Key.java @@ -51,6 +51,26 @@ public class Key implements WritableComparable, Cloneable { protected long timestamp; protected boolean deleted; + /** + * Create a {@link Key} builder. + * + * @param copyBytes + * if the bytes of the {@link Key} components should be copied + * @return the builder at the {@link KeyBuilder.RowStep} + */ + public static KeyBuilder.RowStep builder(boolean copyBytes) { + return new KeyBuilder.AbstractKeyBuilder(copyBytes); + } + + /** + * Create a {@link Key} builder. Copy bytes defaults to true. + * + * @return the builder at the {@link KeyBuilder.RowStep} + */ + public static KeyBuilder.RowStep builder() { + return new KeyBuilder.AbstractKeyBuilder(true); + } + @Override public boolean equals(Object o) { if (o instanceof Key) @@ -60,7 +80,7 @@ public boolean equals(Object o) { private static final byte EMPTY_BYTES[] = new byte[0]; - private byte[] copyIfNeeded(byte ba[], int off, int len, boolean copyData) { + static byte[] copyIfNeeded(byte ba[], int off, int len, boolean copyData) { if (len == 0) return EMPTY_BYTES; @@ -184,44 +204,6 @@ public Key(byte row[], int rOff, int rLen, byte cf[], int cfOff, int cfLen, byte init(row, rOff, rLen, cf, cfOff, cfLen, cq, cqOff, cqLen, cv, cvOff, cvLen, ts, false, true); } - /** - * Creates a key. - * - * @param row - * bytes containing row ID - * @param rOff - * offset into row where key's row ID begins (inclusive) - * @param rLen - * length of row ID in row - * @param cf - * bytes containing column family - * @param cfOff - * offset into cf where key's column family begins (inclusive) - * @param cfLen - * length of column family in cf - * @param cq - * bytes containing column qualifier - * @param cqOff - * offset into cq where key's column qualifier begins (inclusive) - * @param cqLen - * length of column qualifier in cq - * @param cv - * bytes containing column visibility - * @param cvOff - * offset into cv where key's column visibility begins (inclusive) - * @param cvLen - * length of column visibility in cv - * @param ts - * timestamp - * @param deleted - * delete marker - * @param copy - * if true, forces copy of byte array values into key - */ - public Key(byte row[], int rOff, int rLen, byte cf[], int cfOff, int cfLen, byte cq[], int cqOff, int cqLen, byte cv[], int cvOff, int cvLen, long ts, boolean deleted, boolean copy) { - init(row, rOff, rLen, cf, cfOff, cfLen, cq, cqOff, cqLen, cv, cvOff, cvLen, ts, deleted, copy); - } - /** * Creates a key. The delete marker defaults to false. This constructor creates a copy of each specified array. If you don't want to create a copy of the * arrays, you should call {@link Key#Key(byte[] row, byte[] cf, byte[] cq, byte[] cv, long ts, boolean deleted, boolean copy)} instead. diff --git a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java index f5aa8747c66..cfc7fbbf644 100644 --- a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java +++ b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java @@ -20,11 +20,11 @@ import org.apache.hadoop.io.Text; /** - * A builder used to build Keys by defining their components. + * A builder used to build {@link Key}s by defining their components. * * The rules are: *
    - *
  • All components of the Key are optional except the row
  • + *
  • All components of the {@link Key} are optional except the row
  • *
  • Components not explicitly set default to empty byte array except the timestamp which * defaults to Long.MAX_VALUE
  • *
  • The column qualifier can only be set if the column family has been set first
  • @@ -40,239 +40,261 @@ */ public class KeyBuilder { - public interface Build { + public interface Build { /** - * Build a Key from this builder. + * Build a {@link Key} from this builder. copyBytes defaults to true. * - * @param copyBytes - * if the byte arrays should be copied or not. If not, byte arrays will be reused in the resultant Key * @return - * the Key built from this builder + * the {@link Key} built from this builder */ - Key build(boolean copyBytes); + Key build(); /** - * Build a Key from this builder. copyBytes defaults to true. + * Change the timestamp of the {@link Key} created. * - * @return - * the Key built from this builder + * @param timestamp + * the timestamp to use for the {@link Key} + * @return this builder */ - Key build(); + Build timestamp(long timestamp); /** - * Change the timestamp of the Key created. + * Set the deleted marker of the {@link Key} to the parameter. * - * @param timestamp - * the timestamp to use for the Key + * @param deleted + * if the {@link Key} should be marked as deleted or not * @return this builder */ - Build timestamp(long timestamp); + Build deleted(boolean deleted); + } + + public interface RowStep extends Build { /** - * Set the deleted marker of the Key to the parameter. + * Set the row of the {@link Key} that this builder will build to the parameter. * - * @param deleted - * if the Key should be marked as deleted or not + * @param row + * the row to use for the key + * @return this builder + */ + ColumnFamilyStep row(final Text row); + + /** + * Set the row of the {@link Key} that this builder will build to the parameter. + * + * @param row + * the row to use for the key * @return this builder */ - Build deleted(boolean deleted); + ColumnFamilyStep row(final byte[] row); + + /** + * Set the row of the {@link Key} that this builder will build to the parameter. + * + * @param row + * the row to use for the key + * @return this builder + */ + ColumnFamilyStep row(final CharSequence row); } - public interface ColumnFamilyStep extends ColumnVisibilityStep { + public interface ColumnFamilyStep extends ColumnVisibilityStep { /** - * Set the column family of the Key that this builder will build to the parameter. + * Set the column family of the {@link Key} that this builder will build to the parameter. * * @param columnFamily - * the column family to use for the Key + * the column family to use for the {@link Key} * @return this builder */ - ColumnQualifierStep columnFamily(final T columnFamily); + ColumnQualifierStep family(final byte[] columnFamily); /** - * Set the column family, qualifier and visibility of the Key that this builder will build to the parameter. + * Set the column family of the {@link Key} that this builder will build to the parameter. * * @param columnFamily - * the column family to use for the Key - * @param columnQualifier - * the column qualifier to use for the Key - * @param columnVisibility - * the column visibility to use for the Key + * the column family to use for the {@link Key} * @return this builder */ - Build column(final T columnFamily, final T columnQualifier, final T columnVisibility); + ColumnQualifierStep family(final Text columnFamily); /** - * Set the column family and the qualifier of the Key that this builder will build to the parameter. + * Set the column family of the {@link Key} that this builder will build to the parameter. * * @param columnFamily - * the column family to use for the Key - * @param columnQualifier - * the column qualifier to use for the Key + * the column family to use for the {@link Key} * @return this builder */ - ColumnVisibilityStep column(final T columnFamily, final T columnQualifier); + ColumnQualifierStep family(final CharSequence columnFamily); } - public interface ColumnQualifierStep extends ColumnVisibilityStep { + public interface ColumnQualifierStep extends ColumnVisibilityStep { /** - * Set the column qualifier of the Key that this builder will build to the parameter. + * Set the column qualifier of the {@link Key} that this builder will build to the parameter. * * @param columnQualifier - * the column qualifier to use for the Key + * the column qualifier to use for the {@link Key} * @return this builder */ - ColumnVisibilityStep columnQualifier(final T columnQualifier); + ColumnVisibilityStep qualifier(final byte[] columnQualifier); + + /** + * Set the column qualifier of the {@link Key} that this builder will build to the parameter. + * + * @param columnQualifier + * the column qualifier to use for the {@link Key} + * @return this builder + */ + ColumnVisibilityStep qualifier(final Text columnQualifier); + + /** + * Set the column qualifier of the {@link Key} that this builder will build to the parameter. + * + * @param columnQualifier + * the column qualifier to use for the {@link Key} + * @return this builder + */ + ColumnVisibilityStep qualifier(final CharSequence columnQualifier); } - public interface ColumnVisibilityStep extends Build { + public interface ColumnVisibilityStep extends Build { + + /** + * Set the column qualifier of the {@link Key} that this builder will build to the parameter. + * + * @param columnVisibility + * the column visibility to use for the {@link Key} + * @return this builder + */ + Build visibility(final byte[] columnVisibility); + + /** + * Set the column qualifier of the {@link Key} that this builder will build to the parameter. + * + * @param columnVisibility + * the column visibility to use for the {@link Key} + * @return this builder + */ + Build visibility(final Text columnVisibility); + /** - * Set the column qualifier of the Key that this builder will build to the parameter. + * Set the column qualifier of the {@link Key} that this builder will build to the parameter. * * @param columnVisibility - * the column visibility to use for the Key + * the column visibility to use for the {@link Key} * @return this builder */ - Build columnVisibility(final T columnVisibility); + Build visibility(final CharSequence columnVisibility); } - private static abstract class AbstractKeyBuilder implements ColumnFamilyStep, ColumnQualifierStep, - ColumnVisibilityStep { + static class AbstractKeyBuilder implements RowStep, ColumnFamilyStep, ColumnQualifierStep, + ColumnVisibilityStep { protected static final byte EMPTY_BYTES[] = new byte[0]; - protected T row = null; - protected T columnFamily = null; - protected T columnQualifier = null; - protected T columnVisibility = null; - protected long timestamp = Long.MAX_VALUE; - protected boolean deleted = false; + private final boolean copyBytes; + private byte[] row = EMPTY_BYTES; + private byte[] family = EMPTY_BYTES; + private byte[] qualifier = EMPTY_BYTES; + private byte[] visibility = EMPTY_BYTES; + private long timestamp = Long.MAX_VALUE; + private boolean deleted = false; + + AbstractKeyBuilder(boolean copyBytes) { + this.copyBytes = copyBytes; + } + + private byte[] copyBytesIfNeeded(final byte[] bytes) { + return Key.copyIfNeeded(bytes, 0, bytes.length, this.copyBytes); + } + + private byte[] copyBytesIfNeeded(Text text) { + return Key.copyIfNeeded(text.getBytes(), 0, text.getLength(), this.copyBytes); + } - final public ColumnFamilyStep row(final T row) { - this.row = row; + public ColumnFamilyStep row(final byte[] row) { + this.row = copyBytesIfNeeded(row); return this; } - @Override - final public ColumnQualifierStep columnFamily(final T columnFamily) { - this.columnFamily = columnFamily; + public ColumnFamilyStep row(final Text row) { + this.row = copyBytesIfNeeded(row); return this; } + public ColumnFamilyStep row(final CharSequence row) { + return row(new Text(row.toString())); + } + @Override - final public ColumnVisibilityStep columnQualifier(final T columnQualifier) { - this.columnQualifier = columnQualifier; + public ColumnQualifierStep family(final byte[] family) { + this.family = copyBytesIfNeeded(family); return this; } + @Override - final public Build columnVisibility(final T columnVisibility) { - this.columnVisibility = columnVisibility; + public ColumnQualifierStep family(Text family) { + this.family = copyBytesIfNeeded(family); return this; } @Override - final public Build timestamp(long timestamp) { - this.timestamp = timestamp; - return this; + public ColumnQualifierStep family(CharSequence family) { + return family(new Text(family.toString())); } @Override - public Build deleted(boolean deleted) { - this.deleted = deleted; + public ColumnVisibilityStep qualifier(byte[] qualifier) { + this.qualifier = copyBytesIfNeeded(qualifier); return this; } @Override - public Key build() { - return this.build(true); + public ColumnVisibilityStep qualifier(Text qualifier) { + this.qualifier = copyBytesIfNeeded(qualifier); + return this; } @Override - public Build column(final T columnFamily, final T columnQualifier, final T columnVisibility) { - return this.columnFamily(columnFamily).columnQualifier(columnQualifier).columnVisibility(columnVisibility); + public ColumnVisibilityStep qualifier(CharSequence qualifier) { + return qualifier(new Text(qualifier.toString())); } @Override - public ColumnVisibilityStep column(final T columnFamily, final T columnQualifier) { - return this.columnFamily(columnFamily).columnQualifier(columnQualifier); + public Build visibility(byte[] visibility) { + this.visibility = copyBytesIfNeeded(visibility); + return this; } - } - - private static class TextKeyBuilder extends AbstractKeyBuilder { - - private final Text EMPTY_TEXT = new Text(); @Override - public Key build(boolean copyBytes) { - Text columnFamily = (this.columnFamily == null) ? EMPTY_TEXT : this.columnFamily; - Text columnQualifier = (this.columnQualifier == null) ? EMPTY_TEXT : this.columnQualifier; - Text columnVisibility = (this.columnVisibility == null) ? EMPTY_TEXT : this.columnVisibility; - return new Key(row.getBytes(), 0, row.getLength(), columnFamily.getBytes(), 0, columnFamily.getLength(), - columnQualifier.getBytes(), 0, columnQualifier.getLength(), columnVisibility.getBytes(), 0, - columnVisibility.getLength(), timestamp, deleted, copyBytes); + public Build visibility(Text visibility) { + this.visibility = copyBytesIfNeeded(visibility); + return this; } - } - - private static class ByteArrayKeyBuilder extends AbstractKeyBuilder { @Override - public Key build(boolean copyBytes) { - byte[] columnFamily = (this.columnFamily == null) ? EMPTY_BYTES : this.columnFamily; - byte[] columnQualifier = (this.columnQualifier == null) ? EMPTY_BYTES : this.columnQualifier; - byte[] columnVisibility = (this.columnVisibility == null) ? EMPTY_BYTES : this.columnVisibility; - return new Key(row, columnFamily, columnQualifier, columnVisibility, timestamp, deleted, copyBytes); + public Build visibility(CharSequence visibility) { + return visibility(new Text(visibility.toString())); } - } - - private static class CharSequenceKeyBuilder extends AbstractKeyBuilder { - - private final Text EMPTY_TEXT = new Text(); @Override - public Key build(boolean copyBytes) { - Text rowText = new Text(row.toString()); - Text columnFamilyText = (this.columnFamily == null) ? EMPTY_TEXT : new Text(this.columnFamily.toString()); - Text columnQualifierText = (this.columnQualifier == null) ? EMPTY_TEXT : new Text(this.columnQualifier.toString()); - Text columnVisibilityText = (this.columnVisibility == null) ? EMPTY_TEXT : new Text(this.columnVisibility.toString()); - return new Key(rowText.getBytes(), 0, rowText.getLength(), columnFamilyText.getBytes(), 0, - columnFamilyText.getLength(), columnQualifierText.getBytes(), 0, columnQualifierText.getLength(), - columnVisibilityText.getBytes(), 0, columnVisibilityText.getLength(), timestamp, deleted, copyBytes); + final public Build timestamp(long timestamp) { + this.timestamp = timestamp; + return this; } - } - /** - * Set the row of the Key that this builder will build to the parameter. - * - * @param row - * the row to use for the key - * @return this builder - */ - public static ColumnFamilyStep row(final Text row) { - return new TextKeyBuilder().row(row); - } - - /** - * Set the row of the Key that this builder will build to the parameter. - * - * @param row - * the row to use for the key - * @return this builder - */ - public static ColumnFamilyStep row(final byte[] row) { - return new ByteArrayKeyBuilder().row(row); - } + @Override + public Build deleted(boolean deleted) { + this.deleted = deleted; + return this; + } - /** - * Set the row of the Key that this builder will build to the parameter. - * - * @param row - * the row to use for the key - * @return this builder - */ - public static ColumnFamilyStep row( final CharSequence row) { - return new CharSequenceKeyBuilder().row(row); + @Override + public Key build() { + return new Key(this.row, this.family, this.qualifier, this.visibility, this.timestamp, this.deleted, false); + } } } diff --git a/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java b/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java index cc706957e8e..387067fa3f7 100644 --- a/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java @@ -1,3 +1,19 @@ +/* + * 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.data; import org.apache.hadoop.io.Text; @@ -19,221 +35,248 @@ public class KeyBuilderTest { @Test public void testKeyBuildingFromRow() { - Key keyBuilt = KeyBuilder.row("foo").build(); + Key keyBuilt = Key.builder().row("foo").build(); Key keyExpected = new Key("foo"); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamily() { - Key keyBuilt = KeyBuilder.row("foo").columnFamily("bar").build(); + Key keyBuilt = Key.builder().row("foo").family("bar").build(); Key keyExpected = new Key("foo", "bar"); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifier() { - Key keyBuilt = KeyBuilder.row("foo").columnFamily("bar").columnQualifier("baz").build(); + Key keyBuilt = Key.builder().row("foo").family("bar").qualifier("baz").build(); Key keyExpected = new Key("foo", "bar", "baz"); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierVisibility() { - Key keyBuilt = KeyBuilder.row("foo").columnFamily("bar").columnQualifier("baz").columnVisibility("v").build(); + Key keyBuilt = Key.builder().row("foo").family("bar").qualifier("baz").visibility("v").build(); Key keyExpected = new Key("foo", "bar", "baz", "v"); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestamp() { - Key keyBuilt = KeyBuilder.row("foo").columnFamily("bar").columnQualifier("baz").columnVisibility("v").timestamp(1L).build(); + Key keyBuilt = Key.builder().row("foo").family("bar").qualifier("baz").visibility("v").timestamp(1L).build(); Key keyExpected = new Key("foo", "bar", "baz", "v", 1L); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestampDeleted() { Key keyBuilt = - KeyBuilder + Key.builder() .row("foo") - .columnFamily("bar") - .columnQualifier("baz") - .columnVisibility("v") + .family("bar") + .qualifier("baz") + .visibility("v") .timestamp(10L) .deleted(true) .build(); Key keyExpected = new Key("foo", "bar", "baz", "v", 10L); keyExpected.setDeleted(true); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowVisibility() { - Key keyBuilt = KeyBuilder.row("foo").columnVisibility("v").build(); + Key keyBuilt = Key.builder().row("foo").visibility("v").build(); Key keyExpected = new Key("foo", "", "", "v"); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyVisibility() { - Key keyBuilt = KeyBuilder.row("foo").columnFamily("bar").columnVisibility("v").build(); + Key keyBuilt = Key.builder().row("foo").family("bar").visibility("v").build(); Key keyExpected = new Key("foo", "bar", "", "v"); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void textKeyBuildingFromRowTimestamp() { - Key keyBuilt = KeyBuilder.row("foo").timestamp(3L).build(); + Key keyBuilt = Key.builder().row("foo").timestamp(3L).build(); Key keyExpected = new Key("foo"); keyExpected.setTimestamp(3L); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowBytes() { - Key keyBuilt = KeyBuilder.row(rowBytes).build(); + Key keyBuilt = Key.builder().row(rowBytes).build(); Key keyExpected = new Key(rowBytes, EMPTY_BYTES, EMPTY_BYTES, EMPTY_BYTES, Long.MAX_VALUE); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyBytes() { - Key keyBuilt = KeyBuilder.row(rowBytes).columnFamily(familyBytes).build(); + Key keyBuilt = Key.builder().row(rowBytes).family(familyBytes).build(); Key keyExpected = new Key(rowBytes, familyBytes, EMPTY_BYTES, EMPTY_BYTES, Long.MAX_VALUE); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierBytes() { - Key keyBuilt = KeyBuilder.row(rowBytes).columnFamily(familyBytes).columnQualifier(qualifierBytes).build(); + Key keyBuilt = Key.builder().row(rowBytes).family(familyBytes).qualifier(qualifierBytes).build(); Key keyExpected = new Key(rowBytes, familyBytes, qualifierBytes, EMPTY_BYTES, Long.MAX_VALUE); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierVisibilityBytes() { - Key keyBuilt = KeyBuilder.row(rowBytes).columnFamily(familyBytes).columnQualifier(qualifierBytes).columnVisibility(visibilityBytes).build(); + Key keyBuilt = Key.builder().row(rowBytes).family(familyBytes).qualifier(qualifierBytes).visibility(visibilityBytes).build(); Key keyExpected = new Key(rowBytes, familyBytes, qualifierBytes, visibilityBytes, Long.MAX_VALUE); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestampBytes() { - Key keyBuilt = KeyBuilder.row(rowBytes).columnFamily(familyBytes).columnQualifier(qualifierBytes).columnVisibility(visibilityBytes).timestamp(1L).build(); + Key keyBuilt = Key.builder().row(rowBytes).family(familyBytes).qualifier(qualifierBytes).visibility(visibilityBytes).timestamp(1L).build(); Key keyExpected = new Key(rowBytes, familyBytes, qualifierBytes, visibilityBytes, 1L); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestampDeletedBytes() { Key keyBuilt = - KeyBuilder + Key.builder() .row(rowBytes) - .columnFamily(familyBytes) - .columnQualifier(qualifierBytes) - .columnVisibility(visibilityBytes) + .family(familyBytes) + .qualifier(qualifierBytes) + .visibility(visibilityBytes) .timestamp(10L) .deleted(true) .build(); Key keyExpected = new Key(rowBytes, familyBytes, qualifierBytes, visibilityBytes, 10L); keyExpected.setDeleted(true); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowVisibilityBytes() { - Key keyBuilt = KeyBuilder.row(rowBytes).columnVisibility(visibilityBytes).build(); + Key keyBuilt = Key.builder().row(rowBytes).visibility(visibilityBytes).build(); Key keyExpected = new Key(rowBytes, EMPTY_BYTES, EMPTY_BYTES, visibilityBytes, Long.MAX_VALUE); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyVisibilityBytes() { - Key keyBuilt = KeyBuilder.row(rowBytes).columnFamily(familyBytes).columnVisibility(visibilityBytes).build(); + Key keyBuilt = Key.builder().row(rowBytes).family(familyBytes).visibility(visibilityBytes).build(); Key keyExpected = new Key(rowBytes, familyBytes, EMPTY_BYTES, visibilityBytes, Long.MAX_VALUE); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void textKeyBuildingFromRowTimestampBytes() { - Key keyBuilt = KeyBuilder.row(rowBytes).timestamp(3L).build(); + Key keyBuilt = Key.builder().row(rowBytes).timestamp(3L).build(); Key keyExpected = new Key(rowBytes, EMPTY_BYTES, EMPTY_BYTES, EMPTY_BYTES, Long.MAX_VALUE); keyExpected.setTimestamp(3L); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowText() { - Key keyBuilt = KeyBuilder.row(rowText).build(); + Key keyBuilt = Key.builder().row(rowText).build(); Key keyExpected = new Key(rowText); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyText() { - Key keyBuilt = KeyBuilder.row(rowText).columnFamily(familyText).build(); + Key keyBuilt = Key.builder().row(rowText).family(familyText).build(); Key keyExpected = new Key(rowText, familyText); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierText() { - Key keyBuilt = KeyBuilder.row(rowText).columnFamily(familyText).columnQualifier(qualifierText).build(); + Key keyBuilt = Key.builder().row(rowText).family(familyText).qualifier(qualifierText).build(); Key keyExpected = new Key(rowText, familyText, qualifierText); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierVisibilityText() { - Key keyBuilt = KeyBuilder.row(rowText).columnFamily(familyText).columnQualifier(qualifierText).columnVisibility(visibilityText).build(); + Key keyBuilt = Key.builder().row(rowText).family(familyText).qualifier(qualifierText).visibility(visibilityText).build(); Key keyExpected = new Key(rowText, familyText, qualifierText, visibilityText); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestampText() { - Key keyBuilt = KeyBuilder.row(rowText).columnFamily(familyText).columnQualifier(qualifierText).columnVisibility(visibilityText).timestamp(1L).build(); + Key keyBuilt = Key.builder().row(rowText).family(familyText).qualifier(qualifierText).visibility(visibilityText).timestamp(1L).build(); Key keyExpected = new Key(rowText, familyText, qualifierText, visibilityText, 1L); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyQualifierVisibilityTimestampDeletedText() { Key keyBuilt = - KeyBuilder + Key.builder() .row(rowText) - .columnFamily(familyText) - .columnQualifier(qualifierText) - .columnVisibility(visibilityText) + .family(familyText) + .qualifier(qualifierText) + .visibility(visibilityText) .timestamp(10L) .deleted(true) .build(); Key keyExpected = new Key(rowText, familyText, qualifierText, visibilityText, 10L); keyExpected.setDeleted(true); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowVisibilityText() { - Key keyBuilt = KeyBuilder.row(rowText).columnVisibility(visibilityText).build(); + Key keyBuilt = Key.builder().row(rowText).visibility(visibilityText).build(); Key keyExpected = new Key(rowText, new Text(), new Text(), visibilityText); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test public void testKeyBuildingFromRowFamilyVisibilityText() { - Key keyBuilt = KeyBuilder.row(rowText).columnFamily(familyText).columnVisibility(visibilityText).build(); + Key keyBuilt = Key.builder().row(rowText).family(familyText).visibility(visibilityText).build(); Key keyExpected = new Key(rowText, familyText, new Text(), visibilityText); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } @Test - public void textKeyBuildingFromRowTimestampText() { - Key keyBuilt = KeyBuilder.row(rowText).timestamp(3L).build(); + public void testKeyBuildingFromRowTimestampText() { + Key keyBuilt = Key.builder().row(rowText).timestamp(3L).build(); Key keyExpected = new Key(rowText); keyExpected.setTimestamp(3L); - assertEquals(keyBuilt, keyExpected); + assertEquals(keyExpected, keyBuilt); } + @Test + public void testKeyBuildingReusingBytes() { + byte[] reuse = new byte[] { 1, 2, 3 }; + KeyBuilder.Build keyBuilder = Key.builder(false).row(reuse); + Key keyBuilt = keyBuilder.build(); + assertEquals(reuse, keyBuilt.getRowBytes()); + } + + @Test + public void testKeyBuildingCopyBytes() { + byte[] reuse = new byte[] { 1, 2, 3 }; + KeyBuilder.Build keyBuilder = Key.builder(true).row(reuse); + Key keyBuilt = keyBuilder.build(); + assertNotEquals(reuse, keyBuilt.getRowBytes()); + KeyBuilder.Build keyBuilder2 = Key.builder().row(reuse); + Key keyBuilt2 = keyBuilder.build(); + assertNotEquals(reuse, keyBuilt2.getRowBytes()); + } + + @Test + public void testKeyHeterogeneous() { + Key keyBuilt = Key.builder().row(rowText).family(familyBytes).qualifier("foo").build(); + Text fooText = new Text("foo"); + Key keyExpected = new Key(rowText.getBytes(), 0, rowText.getLength(), familyBytes, 0, familyBytes.length, + fooText.getBytes(), 0, fooText.getLength(), EMPTY_BYTES, 0, 0, Long.MAX_VALUE); + assertEquals(keyExpected, keyBuilt); + } } \ No newline at end of file From f6a014553717e9ed8b45386d0f14ef03a0acce89 Mon Sep 17 00:00:00 2001 From: Mario Pastorelli Date: Sat, 3 Sep 2016 01:15:23 +0200 Subject: [PATCH 3/8] fix comments on KeyBuilder and better tests --- .../org/apache/accumulo/core/data/Key.java | 45 ++++- .../apache/accumulo/core/data/KeyBuilder.java | 174 +++++++++++++++--- .../accumulo/core/data/KeyBuilderTest.java | 43 ++++- 3 files changed, 228 insertions(+), 34 deletions(-) diff --git a/core/src/main/java/org/apache/accumulo/core/data/Key.java b/core/src/main/java/org/apache/accumulo/core/data/Key.java index a2c3a2658a3..b8aa0c2df52 100644 --- a/core/src/main/java/org/apache/accumulo/core/data/Key.java +++ b/core/src/main/java/org/apache/accumulo/core/data/Key.java @@ -54,21 +54,23 @@ public class Key implements WritableComparable, Cloneable { /** * Create a {@link Key} builder. * + * @since 1.9 * @param copyBytes * if the bytes of the {@link Key} components should be copied * @return the builder at the {@link KeyBuilder.RowStep} */ public static KeyBuilder.RowStep builder(boolean copyBytes) { - return new KeyBuilder.AbstractKeyBuilder(copyBytes); + return new KeyBuilder.KeyBuilderImpl(copyBytes); } /** * Create a {@link Key} builder. Copy bytes defaults to true. * + * @since 1.9 * @return the builder at the {@link KeyBuilder.RowStep} */ public static KeyBuilder.RowStep builder() { - return new KeyBuilder.AbstractKeyBuilder(true); + return new KeyBuilder.KeyBuilderImpl(true); } @Override @@ -204,6 +206,45 @@ public Key(byte row[], int rOff, int rLen, byte cf[], int cfOff, int cfLen, byte init(row, rOff, rLen, cf, cfOff, cfLen, cq, cqOff, cqLen, cv, cvOff, cvLen, ts, false, true); } + /** + * Creates a key. The delete marker defaults to false. This constructor creates a copy of each specified array. If you don't want to create a copy of the + * arrays, you should call {@link Key#Key(byte[] row, byte[] cf, byte[] cq, byte[] cv, long ts, boolean deleted, boolean copy)} instead. + * + * @param row + * bytes containing row ID + * @param rOff + * offset into row where key's row ID begins (inclusive) + * @param rLen + * length of row ID in row + * @param cf + * bytes containing column family + * @param cfOff + * offset into cf where key's column family begins (inclusive) + * @param cfLen + * length of column family in cf + * @param cq + * bytes containing column qualifier + * @param cqOff + * offset into cq where key's column qualifier begins (inclusive) + * @param cqLen + * length of column qualifier in cq + * @param cv + * bytes containing column visibility + * @param cvOff + * offset into cv where key's column visibility begins (inclusive) + * @param cvLen + * length of column visibility in cv + * @param ts + * timestamp + * @param deleted + * delete marker + * @param copy + * if true, forces copy of byte array values into key + */ + Key(byte row[], int rOff, int rLen, byte cf[], int cfOff, int cfLen, byte cq[], int cqOff, int cqLen, byte cv[], int cvOff, int cvLen, long ts, boolean deleted, boolean copy) { + init(row, rOff, rLen, cf, cfOff, cfLen, cq, cqOff, cqLen, cv, cvOff, cvLen, ts, deleted, copy); + } + /** * Creates a key. The delete marker defaults to false. This constructor creates a copy of each specified array. If you don't want to create a copy of the * arrays, you should call {@link Key#Key(byte[] row, byte[] cf, byte[] cq, byte[] cv, long ts, boolean deleted, boolean copy)} instead. diff --git a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java index cfc7fbbf644..bc7bdbe4919 100644 --- a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java +++ b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java @@ -17,6 +17,7 @@ package org.apache.accumulo.core.data; +import org.apache.accumulo.core.security.ColumnVisibility; import org.apache.hadoop.io.Text; /** @@ -32,14 +33,18 @@ *
* * The builder supports three types of components: byte[], Text and CharSequence. + * CharSequences must be UTF-8 encoded. * * The builder is mutable and not thread safe. * * @see org.apache.accumulo.core.data.Key - * @since 1.8 + * @since 1.9 */ public class KeyBuilder { + /** + * @since 1.9 + */ public interface Build { /** @@ -69,6 +74,9 @@ public interface Build { Build deleted(boolean deleted); } + /** + * @since 1.9 + */ public interface RowStep extends Build { /** @@ -94,11 +102,27 @@ public interface RowStep extends Build { * * @param row * the row to use for the key + * @param offset + * the offset within the array of the first byte to be read; must be non-negative and no larger than row.length + * @param length + * the number of bytes to be read from the given array; must be non-negative and no larger than row.length - offset + * @return this builder + */ + ColumnFamilyStep row(final byte[] row, int offset, int length); + + /** + * Set the row of the {@link Key} that this builder will build to the parameter. + * + * @param row + * the row to use for the key. The encoding must be UTF-8 * @return this builder */ ColumnFamilyStep row(final CharSequence row); } + /** + * @since 1.9 + */ public interface ColumnFamilyStep extends ColumnVisibilityStep { /** @@ -115,9 +139,13 @@ public interface ColumnFamilyStep extends ColumnVisibilityStep { * * @param columnFamily * the column family to use for the {@link Key} + * @param offset + * the offset within the array of the first byte to be read; must be non-negative and no larger than row.length + * @param length + * the number of bytes to be read from the given array; must be non-negative and no larger than row.length - offset * @return this builder */ - ColumnQualifierStep family(final Text columnFamily); + ColumnQualifierStep family(final byte[] columnFamily, int offset, int length); /** * Set the column family of the {@link Key} that this builder will build to the parameter. @@ -126,9 +154,21 @@ public interface ColumnFamilyStep extends ColumnVisibilityStep { * the column family to use for the {@link Key} * @return this builder */ + ColumnQualifierStep family(final Text columnFamily); + + /** + * Set the column family of the {@link Key} that this builder will build to the parameter. + * + * @param columnFamily + * the column family to use for the {@link Key}. The encoding must be UTF-8 + * @return this builder + */ ColumnQualifierStep family(final CharSequence columnFamily); } + /** + * @since 1.9 + */ public interface ColumnQualifierStep extends ColumnVisibilityStep { /** @@ -145,9 +185,13 @@ public interface ColumnQualifierStep extends ColumnVisibilityStep { * * @param columnQualifier * the column qualifier to use for the {@link Key} + * @param offset + * the offset within the array of the first byte to be read; must be non-negative and no larger than row.length + * @param length + * the number of bytes to be read from the given array; must be non-negative and no larger than row.length - offset * @return this builder */ - ColumnVisibilityStep qualifier(final Text columnQualifier); + ColumnVisibilityStep qualifier(final byte[] columnQualifier, int offset, int length); /** * Set the column qualifier of the {@link Key} that this builder will build to the parameter. @@ -156,9 +200,21 @@ public interface ColumnQualifierStep extends ColumnVisibilityStep { * the column qualifier to use for the {@link Key} * @return this builder */ + ColumnVisibilityStep qualifier(final Text columnQualifier); + + /** + * Set the column qualifier of the {@link Key} that this builder will build to the parameter. + * + * @param columnQualifier + * the column qualifier to use for the {@link Key}. The encoding must be UTF-8 + * @return this builder + */ ColumnVisibilityStep qualifier(final CharSequence columnQualifier); } + /** + * @since 1.9 + */ public interface ColumnVisibilityStep extends Build { /** @@ -175,9 +231,13 @@ public interface ColumnVisibilityStep extends Build { * * @param columnVisibility * the column visibility to use for the {@link Key} + * @param offset + * the offset within the array of the first byte to be read; must be non-negative and no larger than row.length + * @param length + * the number of bytes to be read from the given array; must be non-negative and no larger than row.length - offset * @return this builder */ - Build visibility(final Text columnVisibility); + Build visibility(final byte[] columnVisibility, int offset, int length); /** * Set the column qualifier of the {@link Key} that this builder will build to the parameter. @@ -186,59 +246,99 @@ public interface ColumnVisibilityStep extends Build { * the column visibility to use for the {@link Key} * @return this builder */ + Build visibility(final Text columnVisibility); + + /** + * Set the column qualifier of the {@link Key} that this builder will build to the parameter. + * + * @param columnVisibility + * the column visibility to use for the {@link Key}. The encoding must be UTF-8 + * @return this builder + */ Build visibility(final CharSequence columnVisibility); + + /** + * Set the column qualifier of the {@link Key} that this builder will build to the parameter. + * + * @param columnVisibility + * the column visibility to use for the {@link Key} + * @return this builder + */ + Build visibility(final ColumnVisibility columnVisibility); } - static class AbstractKeyBuilder implements RowStep, ColumnFamilyStep, ColumnQualifierStep, + /** + * @since 1.9 + */ + static class KeyBuilderImpl implements RowStep, ColumnFamilyStep, ColumnQualifierStep, ColumnVisibilityStep { protected static final byte EMPTY_BYTES[] = new byte[0]; private final boolean copyBytes; private byte[] row = EMPTY_BYTES; + private int rowOffset = 0; + private int rowLength = 0; private byte[] family = EMPTY_BYTES; + private int familyOffset = 0; + private int familyLength = 0; private byte[] qualifier = EMPTY_BYTES; + private int qualifierOffset = 0; + private int qualifierLength = 0; private byte[] visibility = EMPTY_BYTES; + private int visibilityOffset = 0; + private int visibilityLength = 0; private long timestamp = Long.MAX_VALUE; private boolean deleted = false; - AbstractKeyBuilder(boolean copyBytes) { + KeyBuilderImpl(boolean copyBytes) { this.copyBytes = copyBytes; } - private byte[] copyBytesIfNeeded(final byte[] bytes) { - return Key.copyIfNeeded(bytes, 0, bytes.length, this.copyBytes); + private byte[] copyBytesIfNeeded(final byte[] bytes, int offset, int length) { + return Key.copyIfNeeded(bytes, offset, length, this.copyBytes); } - private byte[] copyBytesIfNeeded(Text text) { - return Key.copyIfNeeded(text.getBytes(), 0, text.getLength(), this.copyBytes); + @Override + public ColumnFamilyStep row(final byte[] row, int offset, int length) { + this.row = copyBytesIfNeeded(row, offset, length); + this.rowOffset = this.copyBytes ? 0 : offset; + this.rowLength = this.copyBytes ? this.row.length : length; + return this; } + @Override public ColumnFamilyStep row(final byte[] row) { - this.row = copyBytesIfNeeded(row); - return this; + return row(row, 0, row.length); } + @Override public ColumnFamilyStep row(final Text row) { - this.row = copyBytesIfNeeded(row); - return this; + return row(row.getBytes(), 0, row.getLength()); } + @Override public ColumnFamilyStep row(final CharSequence row) { return row(new Text(row.toString())); } @Override - public ColumnQualifierStep family(final byte[] family) { - this.family = copyBytesIfNeeded(family); + public ColumnQualifierStep family(final byte[] family, int offset, int length) { + this.family = copyBytesIfNeeded(family, offset, length); + this.familyOffset = this.copyBytes ? 0 : offset; + this.familyLength = this.copyBytes ? this.family.length : length; return this; } + @Override + public ColumnQualifierStep family(final byte[] family) { + return family(family, 0, family.length); + } + @Override public ColumnQualifierStep family(Text family) { - this.family = copyBytesIfNeeded(family); - return this; + return family(family.getBytes(), 0, family.getLength()); } @Override @@ -247,15 +347,21 @@ public ColumnQualifierStep family(CharSequence family) { } @Override - public ColumnVisibilityStep qualifier(byte[] qualifier) { - this.qualifier = copyBytesIfNeeded(qualifier); + public ColumnVisibilityStep qualifier(final byte[] qualifier, int offset, int length) { + this.qualifier = copyBytesIfNeeded(qualifier, offset, length); + this.qualifierOffset = this.copyBytes ? 0 : offset; + this.qualifierLength = this.copyBytes ? this.qualifier.length : length; return this; } + @Override + public ColumnVisibilityStep qualifier(final byte[] qualifier) { + return qualifier(qualifier, 0, qualifier.length); + } + @Override public ColumnVisibilityStep qualifier(Text qualifier) { - this.qualifier = copyBytesIfNeeded(qualifier); - return this; + return qualifier(qualifier.getBytes(), 0, qualifier.getLength()); } @Override @@ -264,15 +370,21 @@ public ColumnVisibilityStep qualifier(CharSequence qualifier) { } @Override - public Build visibility(byte[] visibility) { - this.visibility = copyBytesIfNeeded(visibility); + public Build visibility(final byte[] visibility, int offset, int length) { + this.visibility = copyBytesIfNeeded(visibility, offset, length); + this.visibilityOffset = this.copyBytes ? 0 : offset; + this.visibilityLength = this.copyBytes ? this.visibility.length : length; return this; } + @Override + public Build visibility(final byte[] visibility) { + return visibility(visibility, 0, visibility.length); + } + @Override public Build visibility(Text visibility) { - this.visibility = copyBytesIfNeeded(visibility); - return this; + return visibility(visibility.getBytes(), 0, visibility.getLength()); } @Override @@ -280,6 +392,12 @@ public Build visibility(CharSequence visibility) { return visibility(new Text(visibility.toString())); } + @Override + public Build visibility(ColumnVisibility visibility) { + byte[] expr = visibility.getExpression(); + return visibility(expr, 0, expr.length); + } + @Override final public Build timestamp(long timestamp) { this.timestamp = timestamp; @@ -294,7 +412,9 @@ public Build deleted(boolean deleted) { @Override public Key build() { - return new Key(this.row, this.family, this.qualifier, this.visibility, this.timestamp, this.deleted, false); + return new Key(this.row, this.rowOffset, this.rowLength, this.family, this.familyOffset, this.familyLength, + this.qualifier, this.qualifierOffset, this.qualifierLength, this.visibility, this.visibilityOffset, + this.visibilityLength, this.timestamp, this.deleted, false); } } } diff --git a/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java b/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java index 387067fa3f7..77f29ba7880 100644 --- a/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java @@ -16,22 +16,26 @@ */ package org.apache.accumulo.core.data; +import org.apache.accumulo.core.security.ColumnVisibility; import org.apache.hadoop.io.Text; import org.junit.Test; +import java.nio.charset.StandardCharsets; + import static org.junit.Assert.*; public class KeyBuilderTest { private static final byte EMPTY_BYTES[] = new byte[0]; - byte[] rowBytes = "row".getBytes(); - byte[] familyBytes = "family".getBytes(); - byte[] qualifierBytes = "qualifier".getBytes(); - byte[] visibilityBytes = "visibility".getBytes(); + byte[] rowBytes = "row".getBytes(StandardCharsets.UTF_8); + byte[] familyBytes = "family".getBytes(StandardCharsets.UTF_8); + byte[] qualifierBytes = "qualifier".getBytes(StandardCharsets.UTF_8); + byte[] visibilityBytes = "visibility".getBytes(StandardCharsets.UTF_8); Text rowText = new Text(rowBytes); Text familyText = new Text(familyBytes); Text qualifierText = new Text(qualifierBytes); Text visibilityText = new Text(visibilityBytes); + ColumnVisibility visibilityVisibility = new ColumnVisibility(visibilityBytes); @Test public void testKeyBuildingFromRow() { @@ -244,6 +248,13 @@ public void testKeyBuildingFromRowFamilyVisibilityText() { assertEquals(keyExpected, keyBuilt); } + @Test + public void testKeyBuildingFromRowFamilyVisibilityVisibility() { + Key keyBuilt = Key.builder().row(rowText).family(familyText).visibility(visibilityVisibility).build(); + Key keyExpected = new Key(rowText, familyText, new Text(), visibilityVisibility, Long.MAX_VALUE); + assertEquals(keyExpected, keyBuilt); + } + @Test public void testKeyBuildingFromRowTimestampText() { Key keyBuilt = Key.builder().row(rowText).timestamp(3L).build(); @@ -266,7 +277,6 @@ public void testKeyBuildingCopyBytes() { KeyBuilder.Build keyBuilder = Key.builder(true).row(reuse); Key keyBuilt = keyBuilder.build(); assertNotEquals(reuse, keyBuilt.getRowBytes()); - KeyBuilder.Build keyBuilder2 = Key.builder().row(reuse); Key keyBuilt2 = keyBuilder.build(); assertNotEquals(reuse, keyBuilt2.getRowBytes()); } @@ -279,4 +289,27 @@ public void testKeyHeterogeneous() { fooText.getBytes(), 0, fooText.getLength(), EMPTY_BYTES, 0, 0, Long.MAX_VALUE); assertEquals(keyExpected, keyBuilt); } + + @Test + public void testKeyUsingSubsetOfBytes() { + Key keyBuilt = Key.builder().row(rowBytes, 0, rowBytes.length -1).build(); + Key keyExpected = new Key(rowBytes, 0, rowBytes.length - 1, EMPTY_BYTES, 0, 0, EMPTY_BYTES, 0, 0, EMPTY_BYTES, 0, + 0, Long.MAX_VALUE); + assertEquals(keyExpected, keyBuilt); + } + + @Test + public void testKeyBuildingWithMultipleTimestamps() { + Key keyBuilt = Key.builder().row("r").timestamp(44).timestamp(99).build(); + Key keyExpected = new Key("r", "", "", 99); + assertEquals(keyExpected, keyBuilt); + } + + @Test + public void testKeyBuildingWithMultipleDeleted() { + Key keyBuilt = Key.builder().row("r").deleted(true).deleted(false).build(); + Key keyExpected = new Key("r"); + keyExpected.setDeleted(false); + assertEquals(keyExpected, keyBuilt); + } } \ No newline at end of file From f20a52b817b67798235a679353c9ab2bd54980ad Mon Sep 17 00:00:00 2001 From: Mario Pastorelli Date: Sat, 3 Sep 2016 01:35:29 +0200 Subject: [PATCH 4/8] avoid importing with * --- .../java/org/apache/accumulo/core/data/KeyBuilderTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java b/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java index 77f29ba7880..8adb0ffb8a5 100644 --- a/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java +++ b/core/src/test/java/org/apache/accumulo/core/data/KeyBuilderTest.java @@ -22,7 +22,8 @@ import java.nio.charset.StandardCharsets; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; public class KeyBuilderTest { From 2dd0d612ab8f817247c3a27a42860b947431145e Mon Sep 17 00:00:00 2001 From: Mario Pastorelli Date: Thu, 8 Sep 2016 00:02:07 +0200 Subject: [PATCH 5/8] change @since for KeyBuilder to 2.0 --- .../org/apache/accumulo/core/data/KeyBuilder.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java index bc7bdbe4919..f1f03cc173c 100644 --- a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java +++ b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java @@ -38,12 +38,12 @@ * The builder is mutable and not thread safe. * * @see org.apache.accumulo.core.data.Key - * @since 1.9 + * @since 2.0 */ public class KeyBuilder { /** - * @since 1.9 + * @since 2.0 */ public interface Build { @@ -75,7 +75,7 @@ public interface Build { } /** - * @since 1.9 + * @since 2.0 */ public interface RowStep extends Build { @@ -121,7 +121,7 @@ public interface RowStep extends Build { } /** - * @since 1.9 + * @since 2.0 */ public interface ColumnFamilyStep extends ColumnVisibilityStep { @@ -167,7 +167,7 @@ public interface ColumnFamilyStep extends ColumnVisibilityStep { } /** - * @since 1.9 + * @since 2.0 */ public interface ColumnQualifierStep extends ColumnVisibilityStep { @@ -213,7 +213,7 @@ public interface ColumnQualifierStep extends ColumnVisibilityStep { } /** - * @since 1.9 + * @since 2.0 */ public interface ColumnVisibilityStep extends Build { @@ -268,7 +268,7 @@ public interface ColumnVisibilityStep extends Build { } /** - * @since 1.9 + * @since 2.0 */ static class KeyBuilderImpl implements RowStep, ColumnFamilyStep, ColumnQualifierStep, ColumnVisibilityStep { From 001fde9a8d369c84709ae82ec09e9b4d324e8124 Mon Sep 17 00:00:00 2001 From: Mario Pastorelli Date: Thu, 8 Sep 2016 00:02:52 +0200 Subject: [PATCH 6/8] remove wrong doc from KeyBuilder.build() --- .../src/main/java/org/apache/accumulo/core/data/KeyBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java index f1f03cc173c..a3840c4fdea 100644 --- a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java +++ b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java @@ -48,7 +48,7 @@ public class KeyBuilder { public interface Build { /** - * Build a {@link Key} from this builder. copyBytes defaults to true. + * Build a {@link Key} from this builder. * * @return * the {@link Key} built from this builder From 8337ce978ab5f195fe1b2b3fc7f425565d37e0f9 Mon Sep 17 00:00:00 2001 From: Mario Pastorelli Date: Thu, 8 Sep 2016 00:06:18 +0200 Subject: [PATCH 7/8] add javadoc to public interfaces of KeyBuilder --- .../java/org/apache/accumulo/core/data/KeyBuilder.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java index a3840c4fdea..4a81ac72d20 100644 --- a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java +++ b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java @@ -43,6 +43,8 @@ public class KeyBuilder { /** + * Base Builder interface which can be used to set the {@link Key} timestamp and delete marker and to build the {@link Key}. + * * @since 2.0 */ public interface Build { @@ -75,6 +77,8 @@ public interface Build { } /** + * Builder step used to set the row part of the {@link Key}. + * * @since 2.0 */ public interface RowStep extends Build { @@ -121,6 +125,8 @@ public interface RowStep extends Build { } /** + * Builder step used to set the columnFamily part of the {@link Key}. + * * @since 2.0 */ public interface ColumnFamilyStep extends ColumnVisibilityStep { @@ -167,6 +173,8 @@ public interface ColumnFamilyStep extends ColumnVisibilityStep { } /** + * Builder step used to set the column qualifier part of the {@link Key}. + * * @since 2.0 */ public interface ColumnQualifierStep extends ColumnVisibilityStep { @@ -213,6 +221,8 @@ public interface ColumnQualifierStep extends ColumnVisibilityStep { } /** + * Builder step used to set the column visibility part of the {@link Key}. + * * @since 2.0 */ public interface ColumnVisibilityStep extends Build { From 939a1e15c310e42e2dafda6c221deb281ce63390 Mon Sep 17 00:00:00 2001 From: Mario Pastorelli Date: Thu, 8 Sep 2016 00:21:57 +0200 Subject: [PATCH 8/8] using CharBuffer encoding instead of Text to encode CharSequence --- .../apache/accumulo/core/data/KeyBuilder.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java index 4a81ac72d20..6ab7fbd8b57 100644 --- a/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java +++ b/core/src/main/java/org/apache/accumulo/core/data/KeyBuilder.java @@ -20,6 +20,13 @@ import org.apache.accumulo.core.security.ColumnVisibility; import org.apache.hadoop.io.Text; +import java.io.UnsupportedEncodingException; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; + /** * A builder used to build {@link Key}s by defining their components. * @@ -309,6 +316,16 @@ private byte[] copyBytesIfNeeded(final byte[] bytes, int offset, int length) { return Key.copyIfNeeded(bytes, offset, length, this.copyBytes); } + private byte[] encodeCharSequence(CharSequence chars) { + CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder().onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + try { + return encoder.encode(CharBuffer.wrap(chars)).array(); + } catch (CharacterCodingException ex) { + throw new RuntimeException("KeyBuilder supports only CharSequences encoded in UTF-8", ex); + } + } + @Override public ColumnFamilyStep row(final byte[] row, int offset, int length) { this.row = copyBytesIfNeeded(row, offset, length); @@ -329,7 +346,7 @@ public ColumnFamilyStep row(final Text row) { @Override public ColumnFamilyStep row(final CharSequence row) { - return row(new Text(row.toString())); + return row(encodeCharSequence(row)); } @Override @@ -353,7 +370,7 @@ public ColumnQualifierStep family(Text family) { @Override public ColumnQualifierStep family(CharSequence family) { - return family(new Text(family.toString())); + return family(encodeCharSequence(family)); } @Override @@ -376,7 +393,7 @@ public ColumnVisibilityStep qualifier(Text qualifier) { @Override public ColumnVisibilityStep qualifier(CharSequence qualifier) { - return qualifier(new Text(qualifier.toString())); + return qualifier(encodeCharSequence(qualifier)); } @Override @@ -399,7 +416,7 @@ public Build visibility(Text visibility) { @Override public Build visibility(CharSequence visibility) { - return visibility(new Text(visibility.toString())); + return visibility(encodeCharSequence(visibility)); } @Override