You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by GitBox <gi...@apache.org> on 2020/12/14 04:22:43 UTC

[GitHub] [james-project] Arsnael commented on a change in pull request #280: JAMES-3477 demonstrates concurrency issue in MimeMessageCOW

Arsnael commented on a change in pull request #280:
URL: https://github.com/apache/james-project/pull/280#discussion_r542099368



##########
File path: server/container/core/src/main/java/org/apache/james/server/core/MimeMessageCopyOnWriteProxy.java
##########
@@ -67,98 +92,208 @@ public MessageReferenceTracker(MimeMessage ref) {
             wrapped = ref;
         }
 
-        protected synchronized void incrementReferenceCount() {
-            referenceCount++;
+        protected void dispose() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount--;
+                if (referenceCount <= 0) {
+                    LifecycleUtil.dispose(wrapped);
+                    wrapped = null;
+                }
+            } finally {
+                lock.unlock();
+            }
         }
 
-        protected synchronized void decrementReferenceCount() {
-            referenceCount--;
-            if (referenceCount <= 0) {
-                LifecycleUtil.dispose(wrapped);
-                wrapped = null;
+        protected void incrementReferences() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();

Review comment:
       idem

##########
File path: server/container/core/src/main/java/org/apache/james/server/core/MimeMessageCopyOnWriteProxy.java
##########
@@ -67,98 +92,208 @@ public MessageReferenceTracker(MimeMessage ref) {
             wrapped = ref;
         }
 
-        protected synchronized void incrementReferenceCount() {
-            referenceCount++;
+        protected void dispose() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();

Review comment:
       I know this is code correct, but maybe I would rename the local variable `writeLock` to avoid any confusion with the class variable?

##########
File path: server/container/core/src/main/java/org/apache/james/server/core/MimeMessageCopyOnWriteProxy.java
##########
@@ -67,98 +92,208 @@ public MessageReferenceTracker(MimeMessage ref) {
             wrapped = ref;
         }
 
-        protected synchronized void incrementReferenceCount() {
-            referenceCount++;
+        protected void dispose() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount--;
+                if (referenceCount <= 0) {
+                    LifecycleUtil.dispose(wrapped);
+                    wrapped = null;
+                }
+            } finally {
+                lock.unlock();
+            }
         }
 
-        protected synchronized void decrementReferenceCount() {
-            referenceCount--;
-            if (referenceCount <= 0) {
-                LifecycleUtil.dispose(wrapped);
-                wrapped = null;
+        protected void incrementReferences() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount++;
+            } finally {
+                lock.unlock();
             }
         }
 
-        protected synchronized int getReferenceCount() {
-            return referenceCount;
+        protected <T> T wrapRead(Read<T> op) throws MessagingException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.read(wrapped);
+            } finally {
+                lock.unlock();
+            }
         }
 
-        public synchronized MimeMessage getWrapped() {
-            return wrapped;
+        protected <T> T wrapReadIO(ReadIO<T> op) throws MessagingException, IOException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.read(wrapped);
+            } finally {
+                lock.unlock();
+            }
         }
 
-    }
+        protected <T> T wrapReadNoException(Function<MimeMessage, T> op) {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();

Review comment:
       idem

##########
File path: server/container/core/src/main/java/org/apache/james/server/core/MimeMessageCopyOnWriteProxy.java
##########
@@ -67,98 +92,208 @@ public MessageReferenceTracker(MimeMessage ref) {
             wrapped = ref;
         }
 
-        protected synchronized void incrementReferenceCount() {
-            referenceCount++;
+        protected void dispose() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount--;
+                if (referenceCount <= 0) {
+                    LifecycleUtil.dispose(wrapped);
+                    wrapped = null;
+                }
+            } finally {
+                lock.unlock();
+            }
         }
 
-        protected synchronized void decrementReferenceCount() {
-            referenceCount--;
-            if (referenceCount <= 0) {
-                LifecycleUtil.dispose(wrapped);
-                wrapped = null;
+        protected void incrementReferences() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount++;
+            } finally {
+                lock.unlock();
             }
         }
 
-        protected synchronized int getReferenceCount() {
-            return referenceCount;
+        protected <T> T wrapRead(Read<T> op) throws MessagingException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.read(wrapped);
+            } finally {
+                lock.unlock();
+            }
         }
 
-        public synchronized MimeMessage getWrapped() {
-            return wrapped;
+        protected <T> T wrapReadIO(ReadIO<T> op) throws MessagingException, IOException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();

Review comment:
       idem

##########
File path: server/container/core/src/main/java/org/apache/james/server/core/MimeMessageCopyOnWriteProxy.java
##########
@@ -67,98 +92,208 @@ public MessageReferenceTracker(MimeMessage ref) {
             wrapped = ref;
         }
 
-        protected synchronized void incrementReferenceCount() {
-            referenceCount++;
+        protected void dispose() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount--;
+                if (referenceCount <= 0) {
+                    LifecycleUtil.dispose(wrapped);
+                    wrapped = null;
+                }
+            } finally {
+                lock.unlock();
+            }
         }
 
-        protected synchronized void decrementReferenceCount() {
-            referenceCount--;
-            if (referenceCount <= 0) {
-                LifecycleUtil.dispose(wrapped);
-                wrapped = null;
+        protected void incrementReferences() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount++;
+            } finally {
+                lock.unlock();
             }
         }
 
-        protected synchronized int getReferenceCount() {
-            return referenceCount;
+        protected <T> T wrapRead(Read<T> op) throws MessagingException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();

Review comment:
       idem with `readLock`

##########
File path: server/container/core/src/main/java/org/apache/james/server/core/MimeMessageCopyOnWriteProxy.java
##########
@@ -67,98 +92,208 @@ public MessageReferenceTracker(MimeMessage ref) {
             wrapped = ref;
         }
 
-        protected synchronized void incrementReferenceCount() {
-            referenceCount++;
+        protected void dispose() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount--;
+                if (referenceCount <= 0) {
+                    LifecycleUtil.dispose(wrapped);
+                    wrapped = null;
+                }
+            } finally {
+                lock.unlock();
+            }
         }
 
-        protected synchronized void decrementReferenceCount() {
-            referenceCount--;
-            if (referenceCount <= 0) {
-                LifecycleUtil.dispose(wrapped);
-                wrapped = null;
+        protected void incrementReferences() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount++;
+            } finally {
+                lock.unlock();
             }
         }
 
-        protected synchronized int getReferenceCount() {
-            return referenceCount;
+        protected <T> T wrapRead(Read<T> op) throws MessagingException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.read(wrapped);
+            } finally {
+                lock.unlock();
+            }
         }
 
-        public synchronized MimeMessage getWrapped() {
-            return wrapped;
+        protected <T> T wrapReadIO(ReadIO<T> op) throws MessagingException, IOException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.read(wrapped);
+            } finally {
+                lock.unlock();
+            }
         }
 
-    }
+        protected <T> T wrapReadNoException(Function<MimeMessage, T> op) {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.apply(wrapped);
+            } finally {
+                lock.unlock();
+            }
+        }
 
-    protected MessageReferenceTracker refCount;
+        protected MessageReferenceTracker wrapWrite(Write op) throws MessagingException {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to write a disposed message");
+                if (referenceCount > 1) {
+                    referenceCount--;
+                    MessageReferenceTracker newRef = new MessageReferenceTracker(new MimeMessageWrapper(wrapped));
+                    newRef.wrapWrite(op);
+                    return newRef;
+                } else {
+                    op.write(wrapped);
+                    return this;
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        protected MessageReferenceTracker wrapWriteIO(WriteIO op) throws MessagingException, IOException {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();

Review comment:
       idem

##########
File path: server/container/core/src/main/java/org/apache/james/server/core/MimeMessageCopyOnWriteProxy.java
##########
@@ -67,98 +92,208 @@ public MessageReferenceTracker(MimeMessage ref) {
             wrapped = ref;
         }
 
-        protected synchronized void incrementReferenceCount() {
-            referenceCount++;
+        protected void dispose() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount--;
+                if (referenceCount <= 0) {
+                    LifecycleUtil.dispose(wrapped);
+                    wrapped = null;
+                }
+            } finally {
+                lock.unlock();
+            }
         }
 
-        protected synchronized void decrementReferenceCount() {
-            referenceCount--;
-            if (referenceCount <= 0) {
-                LifecycleUtil.dispose(wrapped);
-                wrapped = null;
+        protected void incrementReferences() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount++;
+            } finally {
+                lock.unlock();
             }
         }
 
-        protected synchronized int getReferenceCount() {
-            return referenceCount;
+        protected <T> T wrapRead(Read<T> op) throws MessagingException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.read(wrapped);
+            } finally {
+                lock.unlock();
+            }
         }
 
-        public synchronized MimeMessage getWrapped() {
-            return wrapped;
+        protected <T> T wrapReadIO(ReadIO<T> op) throws MessagingException, IOException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.read(wrapped);
+            } finally {
+                lock.unlock();
+            }
         }
 
-    }
+        protected <T> T wrapReadNoException(Function<MimeMessage, T> op) {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.apply(wrapped);
+            } finally {
+                lock.unlock();
+            }
+        }
 
-    protected MessageReferenceTracker refCount;
+        protected MessageReferenceTracker wrapWrite(Write op) throws MessagingException {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to write a disposed message");
+                if (referenceCount > 1) {
+                    referenceCount--;
+                    MessageReferenceTracker newRef = new MessageReferenceTracker(new MimeMessageWrapper(wrapped));
+                    newRef.wrapWrite(op);
+                    return newRef;
+                } else {
+                    op.write(wrapped);
+                    return this;
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        protected MessageReferenceTracker wrapWriteIO(WriteIO op) throws MessagingException, IOException {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to write a disposed message");
+                if (referenceCount > 1) {
+                    referenceCount--;
+                    MessageReferenceTracker newRef = new MessageReferenceTracker(new MimeMessageWrapper(wrapped));
+                    newRef.wrapWriteIO(op);
+                    return newRef;
+                } else {
+                    op.write(wrapped);
+                    return this;
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
 
-    public MimeMessageCopyOnWriteProxy(MimeMessage original) throws MessagingException {
-        this(original, false);
+        private MimeMessage getWrapped() {
+            return wrapped;
+        }
+
+        protected MessageReferenceTracker newRef() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();

Review comment:
       idem

##########
File path: server/container/core/src/main/java/org/apache/james/server/core/MimeMessageCopyOnWriteProxy.java
##########
@@ -67,98 +92,208 @@ public MessageReferenceTracker(MimeMessage ref) {
             wrapped = ref;
         }
 
-        protected synchronized void incrementReferenceCount() {
-            referenceCount++;
+        protected void dispose() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount--;
+                if (referenceCount <= 0) {
+                    LifecycleUtil.dispose(wrapped);
+                    wrapped = null;
+                }
+            } finally {
+                lock.unlock();
+            }
         }
 
-        protected synchronized void decrementReferenceCount() {
-            referenceCount--;
-            if (referenceCount <= 0) {
-                LifecycleUtil.dispose(wrapped);
-                wrapped = null;
+        protected void incrementReferences() {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();
+            lock.lock();
+            try {
+                referenceCount++;
+            } finally {
+                lock.unlock();
             }
         }
 
-        protected synchronized int getReferenceCount() {
-            return referenceCount;
+        protected <T> T wrapRead(Read<T> op) throws MessagingException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.read(wrapped);
+            } finally {
+                lock.unlock();
+            }
         }
 
-        public synchronized MimeMessage getWrapped() {
-            return wrapped;
+        protected <T> T wrapReadIO(ReadIO<T> op) throws MessagingException, IOException {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.read(wrapped);
+            } finally {
+                lock.unlock();
+            }
         }
 
-    }
+        protected <T> T wrapReadNoException(Function<MimeMessage, T> op) {
+            ReentrantReadWriteLock.ReadLock lock = this.lock.readLock();
+            lock.lock();
+            try {
+                Preconditions.checkState(referenceCount > 0, "Attempt to read a disposed message");
+                return op.apply(wrapped);
+            } finally {
+                lock.unlock();
+            }
+        }
 
-    protected MessageReferenceTracker refCount;
+        protected MessageReferenceTracker wrapWrite(Write op) throws MessagingException {
+            ReentrantReadWriteLock.WriteLock lock = this.lock.writeLock();

Review comment:
       idem




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org