diff --git a/build.gradle b/build.gradle index 523a8c52..6df44c3f 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ plugins { } group 'io.tiledb' -version '0.2.0-SNAPSHOT' +version '0.2.1-SNAPSHOT' repositories { jcenter() diff --git a/src/main/java/io/tiledb/java/api/Array.java b/src/main/java/io/tiledb/java/api/Array.java index 150c5a0a..8f8e4f9d 100644 --- a/src/main/java/io/tiledb/java/api/Array.java +++ b/src/main/java/io/tiledb/java/api/Array.java @@ -27,6 +27,7 @@ import static io.tiledb.java.api.QueryType.*; import io.tiledb.libtiledb.*; +import java.math.BigInteger; import java.util.HashMap; /** @@ -73,6 +74,25 @@ public Array(Context ctx, String uri) throws TileDBError { openArray(ctx, uri, TILEDB_READ, EncryptionType.TILEDB_NO_ENCRYPTION, new byte[] {}); } + /** + * Constructs an Array object opening the array for reading at a user-given timestamp + * (time-travelling). + * + *
Example:
+ * {@code
+ * Context ctx = new Context();
+ * Array array new Array(ctx, "s3://bucket-name/array-name");
+ * }
+ *
+ * @param ctx TileDB context
+ * @param uri The array URI
+ * @param timestamp The timestamp
+ * @exception TileDBError A TileDB exception
+ */
+ public Array(Context ctx, String uri, BigInteger timestamp) throws TileDBError {
+ openArray(ctx, uri, TILEDB_READ, EncryptionType.TILEDB_NO_ENCRYPTION, new byte[] {}, timestamp);
+ }
+
/**
* Constructs an Array object, opening the array for the given query type.
*
@@ -119,6 +139,39 @@ public Array(
openArray(ctx, uri, query_type, encryption_type, key);
}
+ /**
+ * Constructs an Array object, opening the encrypted array for the given query type.
+ *
+ * Example:
+ * {@code
+ * Context ctx = new Context();
+ * String key = "0123456789abcdeF0123456789abcdeF";
+ * Array array new Array(ctx, "s3://bucket-name/array-name",
+ * TILEDB_READ,
+ * TILEDB_AES_256_GCM,
+ * key.getBytes(StandardCharsets.UTF_8));
+ * }
+ *
+ *
+ * @param ctx TileDB context
+ * @param uri The array URI
+ * @param query_type Query type to open the array for
+ * @param encryption_type The encryption type to use
+ * @param key The encryption key to use
+ * @param timestamp The timestamp
+ * @throws TileDBError A TileDB exception
+ */
+ public Array(
+ Context ctx,
+ String uri,
+ QueryType query_type,
+ EncryptionType encryption_type,
+ byte[] key,
+ BigInteger timestamp)
+ throws TileDBError {
+ openArray(ctx, uri, query_type, encryption_type, key, timestamp);
+ }
+
private synchronized void openArray(
Context ctx, String uri, QueryType query_type, EncryptionType encryption_type, byte[] key)
throws TileDBError {
@@ -155,6 +208,48 @@ private synchronized void openArray(
this.arrayp = _arrayp;
}
+ private synchronized void openArray(
+ Context ctx,
+ String uri,
+ QueryType query_type,
+ EncryptionType encryption_type,
+ byte[] key,
+ BigInteger timestamp)
+ throws TileDBError {
+ SWIGTYPE_p_p_tiledb_array_t _arraypp = tiledb.new_tiledb_array_tpp();
+ try {
+ ctx.handleError(tiledb.tiledb_array_alloc(ctx.getCtxp(), uri, _arraypp));
+ } catch (TileDBError err) {
+ tiledb.delete_tiledb_array_tpp(_arraypp);
+ throw err;
+ }
+ SWIGTYPE_p_tiledb_array_t _arrayp = tiledb.tiledb_array_tpp_value(_arraypp);
+ ArraySchema _schema;
+ try (NativeArray keyArray = new NativeArray(ctx, key, Byte.class)) {
+ try {
+ ctx.handleError(
+ tiledb.tiledb_array_open_at_with_key(
+ ctx.getCtxp(),
+ _arrayp,
+ query_type.toSwigEnum(),
+ encryption_type.toSwigEnum(),
+ keyArray.toVoidPointer(),
+ keyArray.getSize(),
+ timestamp));
+ } catch (TileDBError err) {
+ tiledb.delete_tiledb_array_tpp(_arraypp);
+ throw err;
+ }
+ _schema = new ArraySchema(ctx, uri, encryption_type, key);
+ }
+ this.ctx = ctx;
+ this.uri = uri;
+ this.query_type = query_type;
+ this.schema = _schema;
+ this.arraypp = _arraypp;
+ this.arrayp = _arrayp;
+ }
+
private void checkIsOpen() throws TileDBError {
if (arrayp == null) {
throw new TileDBError("TileDB Array " + uri + " is closed");
diff --git a/src/test/java/io/tiledb/java/api/ArrayTest.java b/src/test/java/io/tiledb/java/api/ArrayTest.java
index 7f0dd341..d7e84cb0 100644
--- a/src/test/java/io/tiledb/java/api/ArrayTest.java
+++ b/src/test/java/io/tiledb/java/api/ArrayTest.java
@@ -1,6 +1,13 @@
package io.tiledb.java.api;
+import static io.tiledb.java.api.Layout.TILEDB_ROW_MAJOR;
+import static io.tiledb.java.api.QueryType.TILEDB_READ;
+import static io.tiledb.java.api.QueryType.TILEDB_WRITE;
+
+import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
+import java.sql.Timestamp;
+import java.util.Arrays;
import org.junit.*;
import org.junit.rules.TemporaryFolder;
@@ -8,6 +15,7 @@ public class ArrayTest {
private Context ctx;
private String arrayURI;
+ private String attributeName;
private byte[] key;
@Rule public TemporaryFolder temp = new TemporaryFolder();
@@ -16,6 +24,7 @@ public class ArrayTest {
public void setup() throws Exception {
ctx = new Context();
arrayURI = temp.getRoot().toString();
+ attributeName = "a1";
String keyString = "0123456789abcdeF0123456789abcdeF";
key = keyString.getBytes(StandardCharsets.US_ASCII);
}
@@ -31,7 +40,7 @@ public ArraySchema schemaCreate() throws Exception {
Domain domain = new Domain(ctx);
domain.addDimension(d1);
- Attribute a1 = new Attribute(ctx, "a1", Integer.class);
+ Attribute a1 = new Attribute(ctx, attributeName, Long.class);
ArraySchema schema = new ArraySchema(ctx, ArrayType.TILEDB_DENSE);
schema.setTileOrder(Layout.TILEDB_ROW_MAJOR);
schema.setCellOrder(Layout.TILEDB_ROW_MAJOR);
@@ -41,6 +50,59 @@ public ArraySchema schemaCreate() throws Exception {
return schema;
}
+ public void insertArbitraryValuesMeth(Array array, NativeArray a_data) throws TileDBError {
+ // Create query
+ try (Query query = new Query(array, TILEDB_WRITE)) {
+ query.setLayout(TILEDB_ROW_MAJOR).setBuffer(attributeName, a_data);
+ query.submit();
+ }
+ array.close();
+ }
+
+ public void insertArbitraryValues(NativeArray a_data) throws TileDBError {
+ Array array = new Array(ctx, arrayURI, TILEDB_WRITE);
+ insertArbitraryValuesMeth(array, a_data);
+ array.close();
+ }
+
+ public void insertArbitraryValuesEncrypted(NativeArray a_data) throws TileDBError {
+ Array array = new Array(ctx, arrayURI, TILEDB_WRITE, EncryptionType.TILEDB_AES_256_GCM, key);
+ insertArbitraryValuesMeth(array, a_data);
+ array.close();
+ }
+
+ public long[] readArray(Array array) throws TileDBError {
+ NativeArray sub_array = new NativeArray(ctx, new long[] {1, 4, 1, 2}, Long.class);
+ // Create query
+ Query query = new Query(array, TILEDB_READ);
+ query.setLayout(TILEDB_ROW_MAJOR);
+ query.setSubarray(sub_array);
+ query.setBuffer(attributeName, new NativeArray(ctx, 10, Long.class));
+
+ // Submit query
+ query.submit();
+
+ long[] a_buff = (long[]) query.getBuffer(attributeName);
+
+ query.close();
+ array.close();
+
+ return a_buff;
+ }
+
+ public long[] readArray() throws TileDBError {
+ return readArray(new Array(ctx, arrayURI));
+ }
+
+ public long[] readArrayAt(BigInteger timestamp) throws TileDBError {
+ return readArray(new Array(ctx, arrayURI, timestamp));
+ }
+
+ public long[] readArrayAtEncrypted(BigInteger timestamp) throws TileDBError {
+ return readArray(
+ new Array(ctx, arrayURI, TILEDB_READ, EncryptionType.TILEDB_AES_256_GCM, key, timestamp));
+ }
+
@Test
public void testArrayExists() throws Exception {
// Test that we can create an array
@@ -97,4 +159,54 @@ public void testLoadingEncryptedArrayWrongKeyLenErrors() throws Exception {
EncryptionType.TILEDB_AES_256_GCM,
keyString.getBytes(StandardCharsets.US_ASCII));
}
+
+ @Test
+ public void testArrayOpenAt() throws Exception {
+ Array.create(arrayURI, schemaCreate());
+
+ long[] array_a = new long[] {1, 2, 3, 6};
+ insertArbitraryValues(new NativeArray(ctx, array_a, Long.class));
+ long ts_a = new Timestamp(System.currentTimeMillis()).toInstant().toEpochMilli();
+
+ Thread.sleep(1000);
+
+ long[] array_b = new long[] {1, 1, 1, 1};
+ insertArbitraryValues(new NativeArray(ctx, array_b, Long.class));
+ long ts_b = new Timestamp(System.currentTimeMillis()).toInstant().toEpochMilli();
+
+ Thread.sleep(1000);
+
+ long[] array_c = new long[] {0, 0, 0, 0};
+ insertArbitraryValues(new NativeArray(ctx, array_c, Long.class));
+ long ts_c = new Timestamp(System.currentTimeMillis()).toInstant().toEpochMilli();
+
+ assert Arrays.equals(readArrayAt(BigInteger.valueOf(ts_a)), array_a);
+ assert Arrays.equals(readArrayAt(BigInteger.valueOf(ts_b)), array_b);
+ assert Arrays.equals(readArrayAt(BigInteger.valueOf(ts_c)), array_c);
+ }
+
+ @Test
+ public void testArrayOpenAtEncrypted() throws Exception {
+ Array.create(arrayURI, schemaCreate(), EncryptionType.TILEDB_AES_256_GCM, key);
+
+ long[] array_a = new long[] {1, 2, 3, 6};
+ insertArbitraryValuesEncrypted(new NativeArray(ctx, array_a, Long.class));
+ long ts_a = new Timestamp(System.currentTimeMillis()).toInstant().toEpochMilli();
+
+ Thread.sleep(1000);
+
+ long[] array_b = new long[] {1, 1, 1, 1};
+ insertArbitraryValuesEncrypted(new NativeArray(ctx, array_b, Long.class));
+ long ts_b = new Timestamp(System.currentTimeMillis()).toInstant().toEpochMilli();
+
+ Thread.sleep(1000);
+
+ long[] array_c = new long[] {0, 0, 0, 0};
+ insertArbitraryValuesEncrypted(new NativeArray(ctx, array_c, Long.class));
+ long ts_c = new Timestamp(System.currentTimeMillis()).toInstant().toEpochMilli();
+
+ assert Arrays.equals(readArrayAtEncrypted(BigInteger.valueOf(ts_a)), array_a);
+ assert Arrays.equals(readArrayAtEncrypted(BigInteger.valueOf(ts_b)), array_b);
+ assert Arrays.equals(readArrayAtEncrypted(BigInteger.valueOf(ts_c)), array_c);
+ }
}