Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IGNITE-23513 Use limited representation for arrays in BinaryObjectExImpl::toString #11610

Merged
merged 6 commits into from
Oct 28, 2024
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
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