Skip to content

CXF-9251_DelayedCachedOutputStreamCleaner_double_callback_out_logging - #3521

Open
vp340 wants to merge 6 commits into
apache:mainfrom
vp340:CXF-9251
Open

vp340 wants to merge 6 commits into
apache:mainfrom
vp340:CXF-9251

Conversation

@vp340

@vp340 vp340 commented Sep 29, 2026

Copy link
Copy Markdown

DelayedCachedOutputStreamCleaner held in a queue list the reference to CachedOutputStream s. The ones never unregistered from the queue are the one who has a tmp file not deleted.
When the timer thread tries to close() the cos ... if the cos is actually a LoggingOutputStream it also calls the onClose() of LoggingCallback.
In certain cases so it logs twice (the second without payload because it is already consumed)
Furthermore, it keeps inMem all the objects that are referenced in the class (such as the Message) and that are needed for logging.

I propose to deregister the callback at the end to avoid rewind calls to it.
This way even if DelayedCachedOutputStreamCleaner keeps the LoggingOutputStream in the queue, there isn't the reference to the callback and so GC can clean those object. And double logs are not produce in the first place

…logged in order to avoid double log or memory leak when tmp file not deleted are involved (CXF-9251)
@vp340

vp340 commented Sep 29, 2026

Copy link
Copy Markdown
Author

Hi @reta ,
I hope U're doing well.
After the ghost RESP_OUT log , I might have found a double RESP_OUT log ... U know how it is... just to balance things out :) ...
Let me know if U or your team needs anything.

Unfortunately, as I wrote in https://issues.apache.org/jira/browse/CXF-9251 ... I couldn't right now simulate the scenario that I had at work. For now U have to trust me on that :/ .
Not on purpose I simulate another scenario that I had described better on Jira. But instead of double logging I reproduced a delayed logging unleashed only by DelayedCachedOutputStreamCleaner .
The thing is, it's difficult to simulate all the cases that provoke https://issues.apache.org/jira/browse/CXF-7396.
Hope U have best luck with that.

If I have news I'll keep U posted.
Let me know if I had to add any tests to this PR or anything else.
I'm glad to help.

Keep me updated about what U think about this problem.
Have a great job!

@reta

reta commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Hi @reta ,
I hope U're doing well.
After the ghost RESP_OUT log , I might have found a double RESP_OUT log ... U know how it is... just to balance things out :) ...
Let me know if U or your team needs anything.

Thanks a lot @vp340 , it is very possible we have missed few places, thank you for reporting those, I will take a closer look shortly

@vp340

vp340 commented Sep 30, 2026

Copy link
Copy Markdown
Author

Thanks a lot for your time.
Sorry for the long comment lines that broke tests. :/
I'll shorten them tonight when I have PC access.

… so it launched : java.util.ConcurrentModificationException
… LoggingCallback, ensuring log only once, and prevent memory leaks
@vp340

vp340 commented Sep 30, 2026

Copy link
Copy Markdown
Author

Hi @reta,
so I fix the indentation, but found that I made a mistake.
I couldn't deregister the callback there, because onClose is called inside a cycle of the same callbacks list... so java.util.ConcurrentModificationException was thrown.

I try another simple approch: Implement a LoggingCallback wrapper (OneTimeLoggingCallback) that ensures logging occurs only once and helps prevent memory leaks by dereferencing the LoggingCallback instance upon completion, making it eligible for garbage collection.
Let me know what U think or if U have cleaner solution in mind.

Have a great evening!

P.S.
I also update the Jira ticket with more evidence about the problem, but I still couldn't resimulate what happened yesterday at work.

…sure the logging doesn't happen twice using also an atomic boolean. (if clean is set to 2 seconds and this.wrappedCallback = null is only set in the cpu cache and not wrote in memory)
} catch (Exception ex) {
// ignore
}
message.setContent(OutputStream.class, origStream);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vp340 I think we should just unregister callback on close? That would make sure, it will be called only once

message.setContent(OutputStream.class, origStream);
cos.deregisterCallback(this);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants