This is an automated email from the ASF dual-hosted git repository.

jungm pushed a commit to branch johnzon-1.2.x
in repository https://gitbox.apache.org/repos/asf/johnzon.git


The following commit(s) were added to refs/heads/johnzon-1.2.x by this push:
     new 664cb73f ensure all buffers get released again in JsonStreamParserImpl
664cb73f is described below

commit 664cb73f629fd0190902a0f1080c420a509e66b0
Author: Markus Jung <ju...@apache.org>
AuthorDate: Tue Feb 13 15:33:06 2024 +0100

    ensure all buffers get released again in JsonStreamParserImpl
---
 .../apache/johnzon/core/JsonStreamParserImpl.java  |  9 ++-
 .../org/apache/johnzon/core/HugeStringTest.java    | 52 --------------
 .../johnzon/core/JsonStreamParserImplTest.java     | 84 ++++++++++++++++++++++
 3 files changed, 91 insertions(+), 54 deletions(-)

diff --git 
a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonStreamParserImpl.java 
b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonStreamParserImpl.java
index a3cfde66..a1ef78a6 100644
--- 
a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonStreamParserImpl.java
+++ 
b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonStreamParserImpl.java
@@ -74,7 +74,7 @@ public class JsonStreamParserImpl extends 
JohnzonJsonParserImpl implements JsonC
     //this buffer is used to store current String or Number value in case that
     //within the value a buffer boundary is crossed or the string contains 
escaped characters
     private char[] fallBackCopyBuffer;
-    private boolean releaseFallBackCopyBufferLength = true;
+    private boolean releaseFallBackCopyBuffer = true;
     private int fallBackCopyBufferLength;
     // when boundaries of fallBackCopyBuffer have been reached
     private List<Buffer> previousFallBackCopyBuffers;
@@ -936,6 +936,11 @@ public class JsonStreamParserImpl extends 
JohnzonJsonParserImpl implements JsonC
         index += fallBackCopyBufferLength;
 
         releasePreviousFallBackCopyBuffers();
+        if (releaseFallBackCopyBuffer) {
+            valueProvider.release(fallBackCopyBuffer);
+            releaseFallBackCopyBuffer = false;
+        }
+
         fallBackCopyBuffer = newBuffer;
         fallBackCopyBufferLength = index;
     }
@@ -1038,7 +1043,7 @@ public class JsonStreamParserImpl extends 
JohnzonJsonParserImpl implements JsonC
         }
 
         bufferProvider.release(buffer);
-        if (releaseFallBackCopyBufferLength) {
+        if (releaseFallBackCopyBuffer) {
             valueProvider.release(fallBackCopyBuffer);
         }
         releasePreviousFallBackCopyBuffers();
diff --git 
a/johnzon-core/src/test/java/org/apache/johnzon/core/HugeStringTest.java 
b/johnzon-core/src/test/java/org/apache/johnzon/core/HugeStringTest.java
deleted file mode 100644
index 5e0bf8b0..00000000
--- a/johnzon-core/src/test/java/org/apache/johnzon/core/HugeStringTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.johnzon.core;
-
-import org.junit.Ignore;
-import org.junit.Test;
-
-import javax.json.Json;
-import javax.json.JsonReader;
-import java.io.StringReader;
-
-@Ignore
-public class HugeStringTest {
-    @Test
-    public void test() {
-        StringBuilder jsonBuilder = new StringBuilder("{\"data\":\"");
-        for (int i = 0; i < 50 * 1024 * 1024 + 1; i++) {
-            jsonBuilder.append("a");
-        }
-        jsonBuilder.append("\"}");
-        String json = jsonBuilder.toString();
-
-        // Warmup
-        for (int i = 0; i < 10; i++) {
-            try (JsonReader reader = Json.createReader(new 
StringReader(json))) {
-                reader.readObject();
-            }
-        }
-
-        long start = System.currentTimeMillis();
-        try (JsonReader reader = Json.createReader(new StringReader(json))) {
-            reader.readObject();
-        }
-        System.err.println("Took " + (System.currentTimeMillis() - start) + 
"ms");
-    }
-}
diff --git 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonStreamParserImplTest.java
 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonStreamParserImplTest.java
index f155d138..ef3e03e5 100644
--- 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonStreamParserImplTest.java
+++ 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonStreamParserImplTest.java
@@ -18,18 +18,26 @@
  */
 package org.apache.johnzon.core;
 
+import org.junit.Ignore;
 import org.junit.Test;
 
+import javax.json.Json;
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.json.spi.JsonProvider;
 import javax.json.stream.JsonParser;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.StringReader;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyMap;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 public class JsonStreamParserImplTest {
     @Test
@@ -63,4 +71,80 @@ public class JsonStreamParserImplTest {
                 asList("START_OBJECT", "KEY_NAME", "VALUE_STRING", 
"{\"foo\":\"barbar\\barbarbar\"}", "END_OBJECT"),
                 events);
     }
+
+    @Test
+    @Ignore("No real test, just run directly from your IDE")
+    public void largeStringPerformance() {
+        StringBuilder jsonBuilder = new StringBuilder("{\"data\":\"");
+        for (int i = 0; i < 50 * 1024 * 1024 + 1; i++) {
+            jsonBuilder.append("a");
+        }
+        jsonBuilder.append("\"}");
+        String json = jsonBuilder.toString();
+
+        // Warmup
+        for (int i = 0; i < 10; i++) {
+            try (JsonReader reader = Json.createReader(new 
StringReader(json))) {
+                reader.readObject();
+            }
+        }
+
+        long start = System.currentTimeMillis();
+        try (JsonReader reader = Json.createReader(new StringReader(json))) {
+            reader.readObject();
+        }
+        System.err.println("Took " + (System.currentTimeMillis() - start) + 
"ms");
+    }
+
+    @Test
+    public void allBuffersReleased() {
+        StringBuilder jsonBuilder = new StringBuilder("{\"data\":\"");
+        for (int i = 0; i < JsonParserFactoryImpl.DEFAULT_MAX_STRING_LENGTH * 
2; i++) {
+            jsonBuilder.append("a");
+        }
+        jsonBuilder.append("\"}");
+        String json = jsonBuilder.toString();
+
+        JsonReaderFactory readerFactory = 
JsonProvider.provider().createReaderFactory(Collections.singletonMap(
+                JsonParserFactoryImpl.BUFFER_STRATEGY, 
TrackingBufferStrategy.class.getName()));
+
+        try (JsonReader reader = readerFactory.createReader(new 
StringReader(json))) {
+            reader.readObject();
+        }
+
+        
assertTrue(TrackingBufferStrategy.TrackingBufferProvider.borrowed.isEmpty());
+    }
+
+    public static class TrackingBufferStrategy implements BufferStrategy {
+        private final BufferStrategy delegate = 
BufferStrategyFactory.valueOf("BY_INSTANCE");
+
+        @Override
+        public BufferProvider<char[]> newCharProvider(int size) {
+            return new TrackingBufferProvider(delegate.newCharProvider(size));
+        }
+
+        public static class TrackingBufferProvider implements 
BufferStrategy.BufferProvider<char[]> {
+            protected static List<char[]> borrowed = new ArrayList<>();
+
+            private final BufferStrategy.BufferProvider<char[]> delegate;
+
+            public 
TrackingBufferProvider(BufferStrategy.BufferProvider<char[]> delegate) {
+                this.delegate = delegate;
+            }
+
+            @Override
+            public char[] newBuffer() {
+                char[] result = delegate.newBuffer();
+                borrowed.add(result);
+
+                return result;
+            }
+
+            @Override
+            public void release(char[] value) {
+                borrowed.remove(value);
+                delegate.release(value);
+            }
+        }
+    }
 }

Reply via email to