-
Notifications
You must be signed in to change notification settings - Fork 78
[JENKINS-54566] finalize vs. flush #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
8ee0788
[JENKINS-54566] Reproducing warning sometimes from FileLogStorageTest.
jglick 5e845fe
Figured out how to make test reliably fail unless running with remoti…
jglick 8ab09d1
Capture remote log messages.
jglick d33b987
Use a phantom reference queue rather than overriding finalize.
jglick 18f1b53
Comments.
jglick 4bef56f
Rewrote DelayBufferedOutputStream to not be based on BufferedOutputSt…
jglick b944d25
Factored out GCFlushedOutputStream, and reverting 4bef56fe1ea425a8c47…
jglick File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
src/main/java/org/jenkinsci/plugins/workflow/log/GCFlushedOutputStream.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* The MIT License | ||
* | ||
* Copyright 2018 CloudBees, Inc. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
* THE SOFTWARE. | ||
*/ | ||
|
||
package org.jenkinsci.plugins.workflow.log; | ||
|
||
import java.io.BufferedOutputStream; | ||
import java.io.FilterOutputStream; | ||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.lang.ref.PhantomReference; | ||
import java.lang.ref.ReferenceQueue; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import jenkins.util.Timer; | ||
|
||
/** | ||
* A stream which will be flushed before garbage collection. | ||
* {@link BufferedOutputStream} does not do this automatically. | ||
*/ | ||
final class GCFlushedOutputStream extends FilterOutputStream { | ||
|
||
private static final Logger LOGGER = Logger.getLogger(GCFlushedOutputStream.class.getName()); | ||
|
||
GCFlushedOutputStream(OutputStream out) { | ||
super(out); | ||
FlushRef.register(this, out); | ||
} | ||
|
||
@Override public void write(byte[] b, int off, int len) throws IOException { | ||
out.write(b, off, len); // super method is surprising | ||
} | ||
|
||
@Override public String toString() { | ||
return "GCFlushedOutputStream[" + out + "]"; | ||
} | ||
|
||
/** | ||
* Flushes streams prior to garbage collection. | ||
* ({@link BufferedOutputStream} does not do this automatically.) | ||
* TODO Java 9+ could use java.util.Cleaner | ||
*/ | ||
private static final class FlushRef extends PhantomReference<GCFlushedOutputStream> { | ||
|
||
private static final ReferenceQueue<GCFlushedOutputStream> rq = new ReferenceQueue<>(); | ||
|
||
static { | ||
Timer.get().scheduleWithFixedDelay(() -> { | ||
while (true) { | ||
FlushRef ref = (FlushRef) rq.poll(); | ||
if (ref == null) { | ||
break; | ||
} | ||
LOGGER.log(Level.FINE, "flushing {0}", ref.out); | ||
try { | ||
ref.out.flush(); | ||
} catch (IOException x) { | ||
LOGGER.log(Level.WARNING, null, x); | ||
} | ||
} | ||
}, 0, 10, TimeUnit.SECONDS); | ||
} | ||
|
||
static void register(GCFlushedOutputStream fos, OutputStream out) { | ||
new FlushRef(fos, out, rq).enqueue(); | ||
} | ||
|
||
private final OutputStream out; | ||
|
||
private FlushRef(GCFlushedOutputStream fos, OutputStream out, ReferenceQueue<GCFlushedOutputStream> rq) { | ||
super(fos, rq); | ||
this.out = out; | ||
} | ||
|
||
} | ||
|
||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jglick Do you remember if there are any tests that specifically exercise
GCFlushedOutputStream
? CallingPhantomReference.enqueue
here ourselves (called in turn by theGCFlushedOutputStream
constructor) causes the cleanup code to run the next time the timer task executes (at most ~10 seconds later) regardless of the reachability of theGCFlushedOutputStream
and then never again, so I am not sure if this class is doing anything meaningful right now.You can test the behavior with a class like this.
Alternatively, you can add logging and
Thread.sleep
calls inFlushRef.register
to observe the cleanup code running within the extent of theGCFlushedOutputStream
constructor, when the object must still be strongly reachable.I think we can make the class work as intended by switching to
Cleaner
. See #388. Trying to fix the issue directly by dropping the explicit call toenqueue
runs into the problem that we need something to hold a reference to theFlushRef
that outlives theGCFlushedOutputStream
, otherwise theFlushRef
itself will just get GC'd and the cleanup code will never run.We could also just delete the class, given this has apparently never worked as intended. See #387.
Any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I recall little of this. It is possible tests in
pipeline-cloudwatch-logs
implicitly exercise this behavior. There are also some JEP-210-related tests inworkflow-durable-task-step
which deal with remoteTaskListenerDecorator
s or something like that.