-
Notifications
You must be signed in to change notification settings - Fork 408
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
Refresh LogstashBasicMarker implementation and remove synchronisation #617
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
8f0926a
Use a CopyOnWriteArrayList instead of Vector and remove synchronisation
brenuart a2e26eb
Remove useless synchronisation on LogstashMarker
brenuart e42b7e6
Additional tests to assert equals/hashCode takes references into account
brenuart 1484243
Remove references from equals/hashCode and rely on the default behaviour
brenuart 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 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 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 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.
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.
I realize this is coming from slf4j-api's implementation, but this seems like a step in the wrong direction, since it will result in a lot of unused lists being allocated.
If markers and/or structured args are used heavily by an application, this will have an impact on memory usage and garbage collection.
The previous logic of deferring list creation until a reference is added seems better from a memory and garbage collection standpoint.
Having said that, I don't have exact numbers to back these claims up, so probably better to go with slf4j-api's implementation until proven otherwise.
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.
I agree with you... creating the list lazily would be better. However, this makes supporting concurrent accesses without synchronisation far less easier...
AFAIK people are not supposed to create many markers - hence the MarkerFactory caching previously created markers. Is it still true with Logstash?
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.
LogstashBasicMarker is the superclass of all of the markers and structured argument implementations provided by logstash-logback-encoder. Caching is not used for any of these. So, for example, a marker (with an unused list) will be created every time this log line is executed.
If that line is executed frequently, it'll create a lot of unused list garbage.
slf4j-api can cache the markers it creates, since those markers are simple string values, so they are easily cachable.
In any case, I understand the synchronization problems being addressed, so we can leave it as is. It's prioritizing performance over memory usage. Classic tradeoff.
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.
But I'm also fighting against excessive memory allocations ;-)
The key point is whether LogstashBasicMarker must be thread-safe or not... IMHO, markers are not shared/mutated by multiple threads in most scenarios.
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.
@philsttr I'm tempted to "drop" the thread-safe nature of the marker... certainly if we consider what has been said in #613 (comment)
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.
@philsttr Back on the
referenceList
again... The overhead of creating the COW list up-front is:Not much - but still too much if we consider that most LogstashMarkers won't have any children/references. BTW, what would be the use case? Can't we simply drop support for references and make the relevant methods "not implemented" ?
Alternatives:
(1) make it 'not thread-safe'. Start with a null reference list and lazy initialise it with a standard ArrayList when needed. Behaviour becomes unexpected if the Marker is accessed from multiple threads concurrently. Note that a COW list won't probably make multi-threaded usage more predictable: a first call to hasReferences() may return true but the list may be empty when you start iterating over it if another thread removed the elements in the meantime.
(2) keep it "thread-safe" but use an AtomicReference to hold the COW list. The overhead when no reference is ever added to the marker is limited to this atomic reference which is cheaper than the empty COW itself.
What's your opinion?
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.
Unfortunately not, since the slf4j-api Logger methods only accept a single Marker argument. Support for multiple markers is implemented by having markers reference others.
Regarding thread-safety. I would rather keep it threadsafe. Another option (3).... similar to (2) but instead of using an
AtomicReference
, we could use a volatile field accessed via a staticAtomicReferenceFieldUpdater
. This prevents memory overhead of creating a lot ofAtomicReference
instances, at the expense of slightly slower access time and slightly more complex code.