Skip to content

Commit

Permalink
IGNITE-23513 Use limited representation for arrays in BinaryObjectExI…
Browse files Browse the repository at this point in the history
…mpl::toString (apache#11610)
  • Loading branch information
skorotkov authored and luchnikovbsk committed Jan 31, 2025
1 parent 8932995 commit 80a7ebe
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
Expand All @@ -37,6 +36,8 @@
import org.apache.ignite.thread.IgniteThread;
import org.jetbrains.annotations.Nullable;

import static org.apache.ignite.internal.util.tostring.GridToStringBuilder.COLLECTION_LIMIT;

/**
* Internal binary object interface.
*/
Expand Down Expand Up @@ -269,23 +270,23 @@ private Object fieldForToString(BinaryReaderHandles ctx, String name) {
private void appendValue(Object val, SB buf, BinaryReaderHandles ctx,
IdentityHashMap<BinaryObject, Integer> handles) {
if (val instanceof byte[])
buf.a(Arrays.toString((byte[])val));
buf.a(S.arrayToString(val));
else if (val instanceof short[])
buf.a(Arrays.toString((short[])val));
buf.a(S.arrayToString(val));
else if (val instanceof int[])
buf.a(Arrays.toString((int[])val));
buf.a(S.arrayToString(val));
else if (val instanceof long[])
buf.a(Arrays.toString((long[])val));
buf.a(S.arrayToString(val));
else if (val instanceof float[])
buf.a(Arrays.toString((float[])val));
buf.a(S.arrayToString(val));
else if (val instanceof double[])
buf.a(Arrays.toString((double[])val));
buf.a(S.arrayToString(val));
else if (val instanceof char[])
buf.a(Arrays.toString((char[])val));
buf.a(S.arrayToString(val));
else if (val instanceof boolean[])
buf.a(Arrays.toString((boolean[])val));
buf.a(S.arrayToString(val));
else if (val instanceof BigDecimal[])
buf.a(Arrays.toString((BigDecimal[])val));
buf.a(S.arrayToString(val));
else if (val instanceof IgniteUuid)
buf.a(val);
else if (val instanceof BinaryObjectExImpl) {
Expand All @@ -308,14 +309,20 @@ else if (val instanceof Object[]) {

buf.a('[');

for (int i = 0; i < arr.length; i++) {
int len = Math.min(arr.length, COLLECTION_LIMIT);

for (int i = 0; i < len; i++) {
Object o = arr[i];

appendValue(o, buf, ctx, handles);

if (i < arr.length - 1)
if (i < len - 1)
buf.a(", ");
}

handleOverflow(buf, arr.length);

buf.a(']');
}
else if (val instanceof Iterable) {
Iterable<Object> col = (Iterable<Object>)val;
Expand All @@ -324,15 +331,23 @@ else if (val instanceof Iterable) {

Iterator it = col.iterator();

int cnt = 0;

while (it.hasNext()) {
Object o = it.next();

appendValue(o, buf, ctx, handles);

if (++cnt == COLLECTION_LIMIT)
break;

if (it.hasNext())
buf.a(", ");
}

if (it.hasNext())
buf.a("... and more");

buf.a('}');
}
else if (val instanceof Map) {
Expand All @@ -342,6 +357,8 @@ else if (val instanceof Map) {

Iterator<Map.Entry<Object, Object>> it = map.entrySet().iterator();

int cnt = 0;

while (it.hasNext()) {
Map.Entry<Object, Object> e = it.next();

Expand All @@ -351,16 +368,34 @@ else if (val instanceof Map) {

appendValue(e.getValue(), buf, ctx, handles);

if (++cnt == COLLECTION_LIMIT)
break;

if (it.hasNext())
buf.a(", ");
}

handleOverflow(buf, map.size());

buf.a('}');
}
else
buf.a(val);
}

/**
* Writes overflow message to buffer if needed.
*
* @param buf String builder buffer.
* @param size Size to compare with limit.
*/
private static void handleOverflow(SB buf, int size) {
int overflow = size - COLLECTION_LIMIT;

if (overflow > 0)
buf.a("... and ").a(overflow).a(" more");
}

/**
* Check if object graph has circular references.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public class GridToStringBuilder {
public static final int DFLT_TO_STRING_COLLECTION_LIMIT = 100;

/** */
private static final int COLLECTION_LIMIT =
public static final int COLLECTION_LIMIT =
IgniteSystemProperties.getInteger(IGNITE_TO_STRING_COLLECTION_LIMIT, DFLT_TO_STRING_COLLECTION_LIMIT);

/** Every thread has its own string builder. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,20 @@

package org.apache.ignite.internal.binary;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ignite.IgniteSystemProperties;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.junit.Test;

import static org.apache.ignite.internal.util.tostring.GridToStringBuilder.DFLT_TO_STRING_COLLECTION_LIMIT;

/**
* Tests for {@code BinaryObject.toString()}.
*/
Expand Down Expand Up @@ -72,6 +77,87 @@ public void testToString() throws Exception {
bo.toString();
}

/**
* Check if toString produce limited representation respecting the
* {@link IgniteSystemProperties#IGNITE_TO_STRING_COLLECTION_LIMIT } limit.
*
* @throws Exception If failed.
*/
@Test
public void testToStringForLargeArrays() throws Exception {
List<String> types = Arrays.asList(
"byte",
"short",
"int",
"long",
"float",
"double",
"char",
"boolean",
"BigDecimal",
"Object",
"Iterable",
"Map"
);

for (String type : types) {
assertFalse(String.format("type=%s, size=%d", type, DFLT_TO_STRING_COLLECTION_LIMIT - 1),
containElipsis(type, getObject(type, DFLT_TO_STRING_COLLECTION_LIMIT - 1)));

assertFalse(String.format("type=%s, size=%d", type, DFLT_TO_STRING_COLLECTION_LIMIT),
containElipsis(type, getObject(type, DFLT_TO_STRING_COLLECTION_LIMIT)));

assertTrue(String.format("type=%s, size=%d", type, DFLT_TO_STRING_COLLECTION_LIMIT + 1),
containElipsis(type, getObject(type, DFLT_TO_STRING_COLLECTION_LIMIT + 1)));
}
}

/** */
private Object getObject(String type, int size) {
switch (type) {
case "byte":
return new byte[size];
case "short":
return new short[size];
case "int":
return new int[size];
case "long":
return new long[size];
case "float":
return new float[size];
case "double":
return new double[size];
case "char":
return new char[size];
case "boolean":
return new boolean[size];
case "BigDecimal":
return new BigDecimal[size];
case "Object":
return new MyObject[size];
case "Map":
Map<Integer, MyObject> map = new HashMap<>();

for (int i = 0; i < size; i++)
map.put(i, new MyObject());

return map;
default:
// Iterable
return Arrays.asList(new String[size]);
}
}

/** */
private boolean containElipsis(String type, Object val) {
BinaryObject bo = grid().binary()
.builder(type)
.setField("field", val)
.build();

return bo.toString().contains("...");
}

/**
*/
private static class MyObject {
Expand Down

0 comments on commit 80a7ebe

Please sign in to comment.