added buffering to boost performance

This commit is contained in:
2019-09-28 09:41:21 +01:00
parent 428c4a68d5
commit 51a7e8ffb0
5 changed files with 42 additions and 43 deletions

View File

@@ -30,7 +30,7 @@ public class Main {
@SneakyThrows @SneakyThrows
private static InputStream extractTestData() { private static InputStream extractTestData() {
return new XZInputStream(new BufferedInputStream(Main.class.getResourceAsStream("/citylots.json.xz"))); return new XZInputStream(Main.class.getResourceAsStream("/citylots.json.xz"));
} }
@SneakyThrows @SneakyThrows
@@ -62,7 +62,7 @@ public class Main {
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
chr.reset(); chr.reset();
for (int i = 0; i < loops; i++) { for (int i = 0; i < loops; i++) {
Value value = new JSONParser().parse(smallTestData()); Value value = new JSONParser().parse(new BufferedReader(new InputStreamReader(smallTestData())));
} }
} }
worthTime = chr.stop(Chronometer.TimeUnit.MILLISECOND); worthTime = chr.stop(Chronometer.TimeUnit.MILLISECOND);
@@ -98,7 +98,7 @@ public class Main {
try (InputStream is = extractTestData()) { try (InputStream is = extractTestData()) {
chr.reset(); chr.reset();
ObjectMapper om = new ObjectMapper(); ObjectMapper om = new ObjectMapper();
om.readTree(is); om.readTree(new InputStreamReader(is));
double elapsedTime = chr.stop(Chronometer.TimeUnit.SECOND); double elapsedTime = chr.stop(Chronometer.TimeUnit.SECOND);
System.out.printf("Jackson time: %8s sec\n", String.format("%.3f", elapsedTime)); System.out.printf("Jackson time: %8s sec\n", String.format("%.3f", elapsedTime));
} }

View File

@@ -8,7 +8,11 @@ import java.io.Reader;
public class LookAheadTextInputStream extends InputStream { public class LookAheadTextInputStream extends InputStream {
private final Reader reader; private final Reader reader;
private int currentByte; private char[] buffer = new char[1024];
private int bufferFill = -1;
private int cursor = -1;
private int currentChar;
public LookAheadTextInputStream(Reader reader) { public LookAheadTextInputStream(Reader reader) {
this.reader = reader; this.reader = reader;
@@ -17,12 +21,21 @@ public class LookAheadTextInputStream extends InputStream {
@Override @Override
@SneakyThrows @SneakyThrows
public int read() { public int read() {
int result = currentByte; if (cursor > bufferFill) {
currentByte = reader.read(); return -1;
return result; } else if (cursor == bufferFill) {
do {
bufferFill = reader.read(buffer, 0, buffer.length) - 1;
cursor = 0;
} while(bufferFill == -1);
currentChar = bufferFill == -2 ? -1 : buffer[0];
} else {
currentChar = buffer[++cursor];
}
return currentChar;
} }
public int getCurrentByte(){ public int getCurrentByte() {
return currentByte; return currentChar;
} }
} }

View File

@@ -27,10 +27,10 @@ public class JSONParser extends ValueParser {
return c >= '0' && c <= '9' || c == '+' || c == '-' || c == '.' || c == 'e'; return c >= '0' && c <= '9' || c == '+' || c == '-' || c == '.' || c == 'e';
} }
private static int parseHex(LookAheadTextInputStream stream) { static int parseHex(LookAheadTextInputStream stream) {
int result = 0; int result = 0;
while (true) {
int c = stream.getCurrentByte(); int c = stream.getCurrentByte();
while (c != -1) {
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
result = result << 4; result = result << 4;
result += (c - '0'); result += (c - '0');
@@ -43,7 +43,7 @@ public class JSONParser extends ValueParser {
} else { } else {
break; break;
} }
stream.read(); c = stream.read();
} }
return result; return result;
} }
@@ -64,19 +64,19 @@ public class JSONParser extends ValueParser {
return sb.toString(); return sb.toString();
} }
private final int parseId(LookAheadTextInputStream stream) { private int parseId(LookAheadTextInputStream stream) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
boolean digitsStarted = false; boolean digitsStarted = false;
boolean digitsEnded = false; boolean digitsEnded = false;
while (true) { while (true) {
int b = stream.getCurrentByte(); int b = stream.getCurrentByte();
if(b == '(' ) { if (b == '(') {
} else if(Character.isWhitespace(b)) { } else if (Character.isWhitespace(b)) {
if(digitsStarted) digitsEnded = true; if (digitsStarted) digitsEnded = true;
} else if (b < 0 || b == ')') { } else if (b < 0 || b == ')') {
break; break;
} else if (isDecimal(b)) { } else if (isDecimal(b)) {
if(digitsEnded) { if (digitsEnded) {
error(ParseException::new, "error parsing id"); error(ParseException::new, "error parsing id");
} else { } else {
digitsStarted = true; digitsStarted = true;
@@ -85,7 +85,7 @@ public class JSONParser extends ValueParser {
} }
stream.read(); stream.read();
} }
return Integer.valueOf(sb.toString()); return Integer.parseInt(sb.toString());
} }
private String readString(LookAheadTextInputStream stream) { private String readString(LookAheadTextInputStream stream) {
@@ -151,7 +151,7 @@ public class JSONParser extends ValueParser {
} }
@Override @Override
protected <T extends RuntimeException> T error(Function<String, T> constructor, String fmt, Object ...args) { protected <T extends RuntimeException> T error(Function<String, T> constructor, String fmt, Object... args) {
return constructor.apply(String.format("Error at line %d column %d: %s", return constructor.apply(String.format("Error at line %d column %d: %s",
currentLine, currentColumn, String.format(fmt, args))); currentLine, currentColumn, String.format(fmt, args)));
} }
@@ -159,6 +159,7 @@ public class JSONParser extends ValueParser {
public static Parser newInstance() { public static Parser newInstance() {
return new JSONParser(); return new JSONParser();
} }
public static Parser newInstance(Value.Configuration cfg) { public static Parser newInstance(Value.Configuration cfg) {
return new JSONParser(cfg); return new JSONParser(cfg);
} }
@@ -192,6 +193,7 @@ public class JSONParser extends ValueParser {
return result; return result;
} }
}; };
stream.read();
try { try {
Integer currentId = null; Integer currentId = null;
@@ -204,13 +206,13 @@ public class JSONParser extends ValueParser {
currentId = parseId(stream); currentId = parseId(stream);
} else if (c == '{') { } else if (c == '{') {
Value newObject = beginObject(); Value newObject = beginObject();
if(currentId != null) valueId(currentId, newObject); if (currentId != null) valueId(currentId, newObject);
currentId = null; currentId = null;
} else if (c == '}') { } else if (c == '}') {
endObject(); endObject();
} else if (c == '[') { } else if (c == '[') {
Value newArray = beginArray(); Value newArray = beginArray();
if(currentId != null) valueId(currentId, newArray); if (currentId != null) valueId(currentId, newArray);
currentId = null; currentId = null;
} else if (c == ']') { } else if (c == ']') {
endArray(); endArray();
@@ -246,7 +248,7 @@ public class JSONParser extends ValueParser {
} else if (idMap != null && c == '$') { } else if (idMap != null && c == '$') {
stream.read(); stream.read();
String text = parseNumber(stream); String text = parseNumber(stream);
valueReference(Integer.valueOf(text)); valueReference(Integer.parseInt(text));
continue; continue;
} }
stream.read(); stream.read();
@@ -262,7 +264,7 @@ public class JSONParser extends ValueParser {
} }
throw error(ParseException::new, "Missing '%c' token", c); throw error(ParseException::new, "Missing '%c' token", c);
} }
return WorthUtils.dynamicCast(stack.getFirst(), ArrayStackLevel.class).value.get(0); return ((ArrayStackLevel) stack.getFirst()).value.get(0);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw error(ParseException::new, e.getMessage()); throw error(ParseException::new, e.getMessage());
} finally { } finally {

View File

@@ -79,18 +79,4 @@ public class JBONTest {
Assert.assertEquals(originalValue, binarySerializedValue); Assert.assertEquals(originalValue, binarySerializedValue);
} }
} }
@Test
@SneakyThrows
public void hexTest() {
String hex = "1F608";
byte[] buffer = hex.getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
Method method = JSONParser.class.getDeclaredMethod("parseHex", LookAheadTextInputStream.class);
method.setAccessible(true);
LookAheadTextInputStream ltis = new LookAheadTextInputStream(new InputStreamReader(bais));
ltis.read();
int result = (int) method.invoke(null, ltis);
Assert.assertEquals((int) Integer.valueOf(hex, 16), result);
}
} }

View File

@@ -228,11 +228,9 @@ public class JSONTest {
String hex = "1F608"; String hex = "1F608";
byte[] buffer = hex.getBytes(); byte[] buffer = hex.getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(buffer); ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
Method method = JSONParser.class.getDeclaredMethod("parseHex", LookAheadTextInputStream.class);
method.setAccessible(true);
LookAheadTextInputStream ltis = new LookAheadTextInputStream(new InputStreamReader(bais)); LookAheadTextInputStream ltis = new LookAheadTextInputStream(new InputStreamReader(bais));
ltis.read(); ltis.read();
int result = (int) method.invoke(null, ltis); int result = JSONParser.parseHex(ltis);
Assert.assertEquals((int) Integer.valueOf(hex, 16), result); Assert.assertEquals(Integer.parseInt(hex, 16), result);
} }
} }