You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by dk...@apache.org on 2019/01/14 21:10:30 UTC

[avro] branch master updated: Make elements of an array reusable again

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

dkulp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/master by this push:
     new 806adf7  Make elements of an array reusable again
806adf7 is described below

commit 806adf7bba3dbff20002b6dd2d64d6e3be062321
Author: unchuckable <un...@wolke7.net>
AuthorDate: Thu Dec 20 23:56:28 2018 +0100

    Make elements of an array reusable again
---
 .../java/org/apache/avro/generic/GenericArray.java |  8 ++++++++
 .../java/org/apache/avro/generic/GenericData.java  | 13 +++++++++++++
 .../apache/avro/generic/GenericDatumReader.java    | 18 +++++++++++++++---
 .../org/apache/avro/generic/TestGenericData.java   | 22 ++++++++++++++++++++++
 4 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericArray.java b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericArray.java
index 428d2f3..56f4438 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericArray.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericArray.java
@@ -27,6 +27,14 @@ public interface GenericArray<T> extends List<T>, GenericContainer {
    * without allocating new objects. */
   T peek();
 
+  /** reset size counter of array to zero */
+  default void reset() {
+    clear();
+  }
+
+  /** clean up reusable objects from array (if reset didn't already) */
+  default void prune() {}
+
   /** Reverses the order of the elements in this array. */
   void reverse();
 }
diff --git a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
index 7294192..26b0872 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
@@ -267,6 +267,19 @@ public class GenericData {
       Arrays.fill(elements, 0, size, null);
       size = 0;
     }
+
+    @Override
+    public void reset() {
+      size = 0;
+    }
+
+    @Override
+    public void prune() {
+      if (size<elements.length) {
+        Arrays.fill(elements, size, elements.length, null);
+      }
+    }
+
     @Override public Iterator<T> iterator() {
       return new Iterator<T>() {
         private int position = 0;
diff --git a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java
index 9b7b04c..b5ef33b 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java
@@ -100,6 +100,7 @@ public class GenericDatumReader<D> implements DatumReader<D> {
   private static final ThreadLocal<Map<Schema,Map<Schema,ResolvingDecoder>>>
     RESOLVER_CACHE =
     new ThreadLocal<Map<Schema,Map<Schema,ResolvingDecoder>>>() {
+    @Override
     protected Map<Schema,Map<Schema,ResolvingDecoder>> initialValue() {
       return new WeakIdentityHashMap<>();
     }
@@ -269,12 +270,20 @@ public class GenericDatumReader<D> implements DatumReader<D> {
         }
         base += l;
       } while ((l = in.arrayNext()) > 0);
-      return array;
+      return pruneArray(array);
     } else {
-      return newArray(old, 0, expected);
+      return pruneArray(newArray(old, 0, expected));
     }
   }
 
+
+  private Object pruneArray(Object object) {
+    if (object instanceof GenericArray<?>) {
+      ((GenericArray<?>)object).prune();
+    }
+    return object;
+  }
+
   /** Called by the default implementation of {@link #readArray} to retrieve a
    * value from a reused instance.  The default implementation is for {@link
    * GenericArray}.*/
@@ -385,7 +394,10 @@ public class GenericDatumReader<D> implements DatumReader<D> {
    * GenericData.Array}.*/
   @SuppressWarnings("unchecked")
   protected Object newArray(Object old, int size, Schema schema) {
-    if (old instanceof Collection) {
+    if (old instanceof GenericArray) {
+      ((GenericArray)old).reset();
+      return old;
+    } else if (old instanceof Collection) {
       ((Collection) old).clear();
       return old;
     } else return new GenericData.Array(size, schema);
diff --git a/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericData.java b/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericData.java
index fe8f618..dd4c1f6 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericData.java
+++ b/lang/java/avro/src/test/java/org/apache/avro/generic/TestGenericData.java
@@ -695,4 +695,26 @@ public class TestGenericData {
       fail("StackOverflowError occurred");
     }
   }
+
+  @Test
+  /** check that GenericArray.reset() retains reusable elements and that GenericArray.prune() cleans
+   * them up properly.
+   */
+  public void testGenericArrayPeek() {
+    Schema elementSchema = SchemaBuilder.record("element").fields().requiredString("value").endRecord();
+    Schema arraySchema = Schema.createArray(elementSchema);
+
+    GenericRecord record = new GenericData.Record( elementSchema );
+    record.put("value", "string");
+
+    GenericArray<GenericRecord> list = new GenericData.Array<GenericRecord>(1, arraySchema);
+    list.add(record);
+
+    list.reset();
+    assertTrue( record == list.peek() );
+
+    list.prune();
+    assertNull( list.peek() );
+  }
+
 }