[ 
https://issues.apache.org/jira/browse/JAMES-3477?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17248735#comment-17248735
 ] 

ASF GitHub Bot commented on JAMES-3477:
---------------------------------------

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:
[email protected]


> MimeMessageCopyOnWriteProxy is not thread safe
> ----------------------------------------------
>
>                 Key: JAMES-3477
>                 URL: https://issues.apache.org/jira/browse/JAMES-3477
>             Project: James Server
>          Issue Type: Wish
>            Reporter: Benoit Tellier
>            Priority: Major
>
> https://www.mail-archive.com/[email protected]/msg69221.html
> & 
> https://github.com/jeantil/james-project/commit/c0354ea21c5b0a8f6d46e9919f7db0d97db9eb23
> proves there is a concurrency issue in MimeMessageCopyOnWriteProxy class that 
> we need to investigate.
> It causes our test suite to be flacky.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to