Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ build/*
*/.gradle/*
*/build/*
*/performance_test/*
.classpath
.project
.settings
bin/
173 changes: 173 additions & 0 deletions src/main/java/io/tiledb/java/api/Array.java
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,179 @@ public HashMap<String, Pair<Long, Long>> maxBufferElements(NativeArray subarray)
return ret;
}

/**
* Get a metadata key-value item from an open array. The array must be opened in READ mode,
* otherwise the function will error out.
*
* @param key a key to retrieve from the metadata key-value
* @return NativeArray which contains the metadata
* @throws TileDBError A TileDB exception
*/
public NativeArray getMetadata(String key) throws TileDBError {
return getMetadata(key, null);
}

/**
* Get a metadata key-value item from an open array. The array must be opened in READ mode,
* otherwise the function will error out.
*
* @param key a key to retrieve from the metadata key-value
* @param nativeType The Datatype
* @return NativeArray which contains the metadata
* @throws TileDBError A TileDB exception
*/
public NativeArray getMetadata(String key, Datatype nativeType) throws TileDBError {
checkIsOpen();

SWIGTYPE_p_p_void resultArrpp = tiledb.new_voidpArray(0);
SWIGTYPE_p_unsigned_int value_num = tiledb.new_uintp();
SWIGTYPE_p_tiledb_datatype_t value_type =
(nativeType == null)
? tiledb.new_tiledb_datatype_tp()
: tiledb.copy_tiledb_datatype_tp(nativeType.toSwigEnum());

ctx.handleError(
tiledb.tiledb_array_get_metadata(
ctx.getCtxp(), arrayp, key, value_type, value_num, resultArrpp));

Datatype derivedNativeType = Datatype.fromSwigEnum(tiledb.tiledb_datatype_tp_value(value_type));

long value = tiledb.uintp_value(value_num);
NativeArray result = new NativeArray(ctx, derivedNativeType, resultArrpp, (int) value);

tiledb.delete_uintp(value_num);
tiledb.delete_tiledb_datatype_tp(value_type);

return result;
}

/**
* Deletes a metadata key-value item from an open array. The array must be opened in WRITE mode,
* otherwise the function will error out.
*
* @param key a key to delete from the metadata key-value
* @throws TileDBError A TileDB exception
*/
public void deleteMetadata(String key) throws TileDBError {
checkIsOpen();

ctx.handleError(tiledb.tiledb_array_delete_metadata(ctx.getCtxp(), arrayp, key));
}

/**
* Gets the number of metadata items in an open array. The array must be opened in READ mode,
* otherwise the function will error out.
*
* @return the number of metadata items
* @throws TileDBError A TileDB exception
*/
public BigInteger getMetadataNum() throws TileDBError {
checkIsOpen();

SWIGTYPE_p_unsigned_long_long value_num = tiledb.new_ullp();

ctx.handleError(tiledb.tiledb_array_get_metadata_num(ctx.getCtxp(), arrayp, value_num));

BigInteger value = tiledb.ullp_value(value_num);

tiledb.delete_ullp(value_num);

return value;
}

/**
* Gets a metadata item from an open array using an index. The array must be opened in READ mode,
* otherwise the function will error out.
*
* @param index index to retrieve metadata from
* @return a pair, key and the metadata
* @throws TileDBError A TileDB exception
*/
public Pair<String, NativeArray> getMetadataFromIndex(long index) throws TileDBError {
return getMetadataFromIndex(BigInteger.valueOf(index));
}

/**
* Gets a metadata item from an open array using an index. The array must be opened in READ mode,
* otherwise the function will error out.
*
* @param index index to retrieve metadata from
* @return a pair, key and the metadata
* @throws TileDBError A TileDB exception
*/
public Pair<String, NativeArray> getMetadataFromIndex(BigInteger index) throws TileDBError {
checkIsOpen();

SWIGTYPE_p_p_char key = tiledb.new_charpp();
SWIGTYPE_p_unsigned_int key_len = tiledb.new_uintp();
SWIGTYPE_p_tiledb_datatype_t value_type = tiledb.new_tiledb_datatype_tp();
SWIGTYPE_p_unsigned_int value_num = tiledb.new_uintp();
SWIGTYPE_p_p_void value = tiledb.new_voidpArray(0);

ctx.handleError(
tiledb.tiledb_array_get_metadata_from_index(
ctx.getCtxp(), arrayp, index, key, key_len, value_type, value_num, value));

String keyString = tiledb.charpp_value(key);
long valueLength = tiledb.uintp_value(value_num);
Datatype nativeType = Datatype.fromSwigEnum(tiledb.tiledb_datatype_tp_value(value_type));

NativeArray result = new NativeArray(ctx, nativeType, value, (int) valueLength);

tiledb.delete_uintp(value_num);
tiledb.delete_uintp(key_len);
tiledb.delete_charpp(key);
tiledb.delete_tiledb_datatype_tp(value_type);

return new Pair<String, NativeArray>(keyString, result);
}

/**
* Checks if the key is present in the Array metadata. The array must be opened in READ mode,
* otherwise the function will error out.
*
* @param key a key to retrieve from the metadata key-value
* @return true if the key is present in the metadata, false if it is not
* @throws TileDBError A TileDB exception
*/
public Boolean hasMetadataKey(String key) throws TileDBError {
checkIsOpen();

SWIGTYPE_p_tiledb_datatype_t value_type = tiledb.new_tiledb_datatype_tp();
SWIGTYPE_p_int has_key = tiledb.new_intp();

ctx.handleError(
tiledb.tiledb_array_has_metadata_key(ctx.getCtxp(), arrayp, key, value_type, has_key));

Boolean result = tiledb.intp_value(has_key) > 0;

tiledb.delete_intp(has_key);
tiledb.delete_tiledb_datatype_tp(value_type);

return result;
}

/**
* Puts a metadata key-value item to an open array. The array must be opened in WRITE mode,
* otherwise the function will error out.
*
* @param key a key to assign to the input value
* @param value the metadata to put into the Array metadata
* @throws TileDBError A TileDB exception
*/
public void putMetadata(String key, NativeArray value) throws TileDBError {
Copy link
Contributor Author

@pomadchin pomadchin May 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering, should the following overload be a part of this PR

public void putMetadata(String key, Object buffer, Class javaType) throws TileDBError {
  putMetadata(key, new NativeArray(ctx, buffer, javaType));
}

Or it can / should be discussed in a separate PR / issue in case this one would pass.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pomadchin let's look into this as a followup PR. We wanted to initial changes merged, as they are a good foundation to build upon.

For the overloads, is this something you are interested in contributing? If not, @gsvic can add them, we just want to coordinate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! #156

checkIsOpen();

ctx.handleError(
tiledb.tiledb_array_put_metadata(
ctx.getCtxp(),
arrayp,
key,
value.getNativeType().toSwigEnum(),
value.getSize(),
value.toVoidPointer()));
}

/** @return The TileDB Context object associated with the Array instance. */
public Context getCtx() {
return ctx;
Expand Down
168 changes: 168 additions & 0 deletions src/test/java/io/tiledb/java/api/ArrayTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.tiledb.java.api;

import static io.tiledb.java.api.Datatype.*;
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;
Expand Down Expand Up @@ -34,6 +35,16 @@ public void tearDown() throws Exception {
ctx.close();
}

private Object[] getArray(Object val) {
if (val instanceof Object[]) return (Object[]) val;
int arrlength = java.lang.reflect.Array.getLength(val);
Object[] outputArray = new Object[arrlength];
for (int i = 0; i < arrlength; i++) {
outputArray[i] = java.lang.reflect.Array.get(val, i);
}
return outputArray;
}

public ArraySchema schemaCreate() throws Exception {
Dimension<Long> d1 =
new Dimension<Long>(ctx, "d1", Long.class, new Pair<Long, Long>(1l, 4l), 2l);
Expand Down Expand Up @@ -247,4 +258,161 @@ public void testArraygetNonEmptyDomainFromName() throws Exception {
} catch (TileDBError error) {
}
}

@Test
public void testArrayMetadata() throws Exception {
Array.create(arrayURI, schemaCreate());

long[] array_a = new long[] {1, 2, 3, 6};
insertArbitraryValues(new NativeArray(ctx, array_a, Long.class));

Array arrayw = new Array(ctx, arrayURI, TILEDB_WRITE);
Array array = new Array(ctx, arrayURI, TILEDB_READ);

NativeArray metadataByte = new NativeArray(ctx, new byte[] {-7, -6, -5, 0, 100}, Byte.class);

NativeArray metadataShort = new NativeArray(ctx, new short[] {18, 19, 20, 21}, Short.class);

NativeArray metadataInt =
new NativeArray(
ctx,
new int[] {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15
},
Integer.class);

NativeArray metadataFloat =
new NativeArray(
ctx,
new float[] {
0.1f, 0.2f, 1.1f, 1.2f, 2.1f, 2.2f, 3.1f, 3.2f,
4.1f, 4.2f, 5.1f, 5.2f, 6.1f, 6.2f, 7.1f, 7.2f,
8.1f, 8.2f, 9.1f, 9.2f, 10.1f, 10.2f, 11.1f, 11.2f,
12.1f, 12.2f, 13.1f, 13.2f, 14.1f, 14.2f, 15.1f, 15.2f
},
Float.class);

NativeArray metadataDouble =
new NativeArray(
ctx,
new double[] {
1.1d, 1.2d, 2.1d, 2.2d, 3.1d, 3.2d, 4.1d, 4.2d,
5.1d, 5.2d, 6.1d, 6.2d, 7.1d, 7.2d, 8.1d, 8.2d,
9.1d, 9.2d, 10.1d, 10.2d, 11.1d, 11.2d, 12.1d, 12.2d,
13.1d, 14.2d, 14.1d, 14.2d, 15.1d, 15.2d, 16.1d, 16.2d
},
Double.class);

String byteKey = "md-byte";
String shortKey = "md-short";
String intKey = "md-int";
String floatKey = "md-float";
String doubleKey = "md-double";

// metadata keys sorted in a lexicographic ordering
String[] keys = new String[] {byteKey, doubleKey, floatKey, intKey, shortKey};
Datatype[] types =
new Datatype[] {TILEDB_INT8, TILEDB_FLOAT64, TILEDB_FLOAT32, TILEDB_INT32, TILEDB_INT16};
int keysNum = keys.length;
NativeArray[] nativeArrays =
new NativeArray[] {metadataByte, metadataDouble, metadataFloat, metadataInt, metadataShort};
Object[] expectedArrays =
new Object[] {
metadataByte.toJavaArray(),
metadataDouble.toJavaArray(),
metadataFloat.toJavaArray(),
metadataInt.toJavaArray(),
metadataShort.toJavaArray()
};

for (int i = 0; i < keysNum; i++) {
Assert.assertFalse(array.hasMetadataKey(keys[i]));
}

Assert.assertEquals(0, array.getMetadataNum().intValue());
array.close();

for (int i = 0; i < keysNum; i++) {
arrayw.putMetadata(keys[i], nativeArrays[i]);
}
// submit changes
arrayw.close();

// open a new session
Array arrayn = new Array(ctx, arrayURI, TILEDB_READ);

for (int i = 0; i < keysNum; i++) {
Assert.assertTrue(arrayn.hasMetadataKey(keys[i]));
}

Assert.assertEquals(keysNum, arrayn.getMetadataNum().intValue());

// manual extraction of metadata
NativeArray metadataByteActual = arrayn.getMetadata(byteKey, TILEDB_INT8);
NativeArray metadataShortActual = arrayn.getMetadata(shortKey, TILEDB_INT16);
NativeArray metadataIntActual = arrayn.getMetadata(intKey, TILEDB_INT32);
NativeArray metadataFloatActual = arrayn.getMetadata(floatKey, TILEDB_FLOAT32);
NativeArray metadataDoubleActual = arrayn.getMetadata(doubleKey, TILEDB_FLOAT64);

Assert.assertNotNull(metadataByteActual);
Assert.assertNotNull(metadataShortActual);
Assert.assertNotNull(metadataIntActual);
Assert.assertNotNull(metadataFloatActual);
Assert.assertNotNull(metadataDoubleActual);

Assert.assertArrayEquals(
(byte[]) metadataByte.toJavaArray(), (byte[]) metadataByteActual.toJavaArray());
Assert.assertArrayEquals(
(short[]) metadataShort.toJavaArray(), (short[]) metadataShortActual.toJavaArray());
Assert.assertArrayEquals(
(int[]) metadataInt.toJavaArray(), (int[]) metadataIntActual.toJavaArray());
Assert.assertArrayEquals(
(float[]) metadataFloat.toJavaArray(), (float[]) metadataFloatActual.toJavaArray(), 1e-10f);
Assert.assertArrayEquals(
(double[]) metadataDouble.toJavaArray(),
(double[]) metadataDoubleActual.toJavaArray(),
1e-10d);

// exctracion of metadata without specifying the Datatype
for (int i = 0; i < keysNum; i++) {
NativeArray a = arrayn.getMetadata(keys[i]);
Assert.assertNotNull(a);
Assert.assertEquals(types[i], a.getNativeType());
Assert.assertEquals(nativeArrays[i].getNativeType(), a.getNativeType());
Assert.assertArrayEquals(getArray(expectedArrays[i]), getArray(a.toJavaArray()));
}

// fromIndex tests
for (int i = 0; i < arrayn.getMetadataNum().intValue(); i++) {
Pair<String, NativeArray> p = arrayn.getMetadataFromIndex(i);
NativeArray a = p.getSecond();
Assert.assertEquals(keys[i], p.getFirst());
Assert.assertEquals(types[i], a.getNativeType());
Assert.assertEquals(nativeArrays[i].getNativeType(), a.getNativeType());
Assert.assertArrayEquals(getArray(expectedArrays[i]), getArray(a.toJavaArray()));
}

arrayn.close();

// open a new write session
Array arrayd = new Array(ctx, arrayURI, TILEDB_WRITE);

for (int i = 0; i < keysNum; i++) {
arrayd.deleteMetadata(keys[i]);
}

arrayd.close();

// open a new session to check the deletion
Array arraydn = new Array(ctx, arrayURI, TILEDB_READ);

for (int i = 0; i < keysNum; i++) {
Assert.assertFalse(arraydn.hasMetadataKey(keys[i]));
}

Assert.assertEquals(0, arraydn.getMetadataNum().intValue());

arraydn.close();
}
}