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

dkuppitz pushed a commit to branch TINKERPOP-2126
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 62622c28696531206cf57ff9630dd7f9b6e0d3ce
Author: Daniel Kuppitz <daniel_kupp...@hotmail.com>
AuthorDate: Tue Jan 22 15:07:09 2019 -0700

    TINKERPOP-2126 Fixed concurrency issue in `ObjectWritable::toString()`.
---
 CHANGELOG.asciidoc                                 |  2 +-
 docker/Dockerfile                                  |  2 +-
 .../hadoop/structure/io/ObjectWritable.java        | 33 ++++++++++++++++++++--
 3 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index e0e4620..a8b10f0 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -30,7 +30,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Added `globalFunctionCacheEnabled` to the `GroovyCompilerGremlinPlugin` to 
allow that cache to be disabled.
 * Added `globalFunctionCacheEnabled` override to `SessionOpProcessor` 
configuration.
 * Added status code to `GremlinServerError` so that it would be more directly 
accessible during failures.
-* Fixed a concurrency issue in `TraverserSet`.
+* Fixed concurrency issues in `TraverserSet.toString()` and 
`ObjectWritable.toString()`.
 * Fixed a bug in `InlineFilterStrategy` that mixed up and's and or's when 
folding merging conditions together.
 
 [[release-3-3-5]]
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 85c9865..a908b22 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -20,7 +20,7 @@ FROM ubuntu:trusty
 MAINTAINER Daniel Kuppitz <m...@gremlin.guru>
 
 RUN apt-get update \
-    && apt-get -y install software-properties-common 
python-software-properties apt-transport-https curl \
+    && apt-get -y install software-properties-common 
python-software-properties apt-transport-https curl dpkg \
     && echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select 
true | debconf-set-selections \
     && add-apt-repository -y ppa:webupd8team/java \
     && sh -c 'curl -s 
https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb 
-o packages-microsoft-prod.deb' \
diff --git 
a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/ObjectWritable.java
 
b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/ObjectWritable.java
index 0379ee6..979cbfc 100644
--- 
a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/ObjectWritable.java
+++ 
b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/io/ObjectWritable.java
@@ -22,6 +22,8 @@ import org.apache.hadoop.io.WritableComparable;
 import org.apache.hadoop.io.WritableUtils;
 import org.apache.tinkerpop.gremlin.process.computer.MapReduce;
 import 
org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.KryoShimServiceLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.ByteArrayInputStream;
 import java.io.DataInput;
@@ -30,13 +32,16 @@ import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
+import java.util.ConcurrentModificationException;
+import java.util.Objects;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
 public final class ObjectWritable<T> implements 
WritableComparable<ObjectWritable>, Serializable {
 
-    private static final String NULL = "null";
+    private static final Logger logger = 
LoggerFactory.getLogger(ObjectWritable.class);
+
     private static final ObjectWritable<MapReduce.NullObject> 
NULL_OBJECT_WRITABLE = new ObjectWritable<>(MapReduce.NullObject.instance());
 
     T t;
@@ -45,7 +50,7 @@ public final class ObjectWritable<T> implements 
WritableComparable<ObjectWritabl
     }
 
     public ObjectWritable(final T t) {
-        this.t = t;
+        this.set(t);
     }
 
     public T get() {
@@ -58,7 +63,29 @@ public final class ObjectWritable<T> implements 
WritableComparable<ObjectWritabl
 
     @Override
     public String toString() {
-        return null == this.t ? NULL : this.t.toString();
+        // Spark's background logging apparently tries to log a `toString()` 
of certain objects while they're being
+        // modified, which then throws a ConcurrentModificationException. We 
probably can't make any arbitrary object
+        // thread-safe, but we can easily retry on such cases and eventually 
we should always get a result.
+        final int maxAttempts = 5;
+        for (int i = maxAttempts; ;) {
+            try {
+                return Objects.toString(this.t);
+            }
+            catch (ConcurrentModificationException cme) {
+                if (--i > 0) {
+                    logger.warn(String.format("Failed to toString() object 
held by ObjectWritable, retrying %d more %s.",
+                            i, i == 1 ? "time" : "times"), cme);
+                } else break;
+                if (i < maxAttempts - 1) {
+                    try {
+                        Thread.sleep((maxAttempts - i - 1) * 100);
+                    } catch (InterruptedException ignored) {
+                        break;
+                    }
+                }
+            }
+        }
+        return this.t.getClass().toString();
     }
 
     @Override

Reply via email to