Skip to content

WeakCache instead of WeakMap#1256

Merged
lpriima merged 1 commit into
masterfrom
lpriima/WeakCache
Mar 20, 2020
Merged

WeakCache instead of WeakMap#1256
lpriima merged 1 commit into
masterfrom
lpriima/WeakCache

Conversation

@lpriima
Copy link
Copy Markdown
Contributor

@lpriima lpriima commented Feb 25, 2020

The intention of this change is to replace (not change) our concurrent WeakMap abstraction.
Our concurrent WeakMap abstraction has a few problems… :

  • unbounded size
  • primary eviction policy isn’t size
  • always uses synchronized even around ConcurrentMaps like Guava
  • encourages computation under a lock
  • needs better setting for concurrency level

New abstraction should be a “WeakCache” not for a “WeakMap”. Maps may need to be unbounded, but caches should be bounded.

Abstraction should be quite minimal.
It doesn’t need to be as complex as our current WeakMap.Provider scheme.
Just a simple factory function that returns a Guava Cache object with reasonable defaults.

@lpriima lpriima requested a review from dougqh February 25, 2020 22:35
Comment thread dd-java-agent/agent-bootstrap/agent-bootstrap.gradle Outdated
@lpriima lpriima changed the title WeakCache intstead of WeakMap step 1 out of 2 WeakCache instead of WeakMap Feb 28, 2020
@lpriima lpriima force-pushed the lpriima/WeakCache branch 10 times, most recently from 51a9e65 to 86c1b10 Compare March 4, 2020 16:06
@lpriima lpriima force-pushed the lpriima/WeakCache branch 7 times, most recently from c492b30 to c7f5acc Compare March 7, 2020 07:17
@lpriima lpriima marked this pull request as ready for review March 9, 2020 14:49
@lpriima lpriima requested a review from a team as a code owner March 9, 2020 14:49
Copy link
Copy Markdown
Contributor

@tylerbenson tylerbenson left a comment

Choose a reason for hiding this comment

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

WeakCache should be in the bootstrap project since it's referenced by instrumentation, but Guava should not be in the bootstrap.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

did you figure this out?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

didn't figure out why. But definitely logic is expected to be like this in tests. If I use direct cache.get(key, valueSuppler) then tests are failing

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was thinking about another detail related to critical sections yesterday.

I think doing the computation inside the critical section might be a bad idea in general.
My thinking is that it increases the amount of activity under lock including likely taking other locks. In other words, it increases our potential for deadlocks. I'm not sure how much it increases our exposure, but it is strictly an increase.

@lpriima lpriima force-pushed the lpriima/WeakCache branch 3 times, most recently from 68c1178 to aac32a4 Compare March 17, 2020 05:42
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why Object key rather than K key?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

it's pretty much was a copy from guava Cache:

https://github.com/google/guava/blob/0cd4e9faa1360da4a343f84cb275d6eda0c5e732/guava/src/com/google/common/cache/Cache.java#L49

I was trying to find why it's done like this in guava and didn't find any reason, why they not using K there. They doesn't seems to care about compatibility with JDK versions before 5. Like in JDK There is always a some form of get method accepting Object in all types of map interfaces:

https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#get-java.lang.Object-
https://docs.oracle.com/javase/8/docs/api/java/util/AbstractMap.html#get-java.lang.Object-

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, I'm aware that Java maps do something similar. I think we can leave it as is. I was mostly just curious.

@lpriima lpriima force-pushed the lpriima/WeakCache branch from aac32a4 to 420b3d0 Compare March 17, 2020 16:06
@lpriima lpriima requested a review from randomanderson March 17, 2020 16:11
@randomanderson randomanderson dismissed their stale review March 17, 2020 16:39

changes addressed

@lpriima lpriima force-pushed the lpriima/WeakCache branch from 420b3d0 to 1acde59 Compare March 17, 2020 18:51
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I like the moving of the factory onto AgentTooling. I think that's a good call given the inherent coupling.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see removed the duplication. Nice.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think I'd prefer that encapsulated a bit more. As is, that ServiceLoader look-up is a lot to process.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, I'd prefer to create a static factory to wrap the look-up, so we don't have to repeat this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right now we already have several (e.g.: netty-4.0 and netty-4.1) no-dependency artifacts with a lot of copy-paste inside. If we try to move common code to separate module, the muzzle tests will fail. Do we want to make this changes inside this PR ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see.

Yes, I think part of our problem is that helper class system doesn't transitively handle parents, etc. automatically. I think that ends up discouraging reuse, but we shouldn't solve that now.

I was more wondering whether we could put a static look-up method on WeakCache or WeakCache.Provider that handles the ServiceLoader logic. I suppose that has the problem of needing to find the right ClassLoader. Hmm?

@dougqh
Copy link
Copy Markdown
Contributor

dougqh commented Mar 17, 2020

Looks like this is shaping up nicely, but I'd like to clean-up the ServiceLoader look-ups just a bit.

@lpriima lpriima force-pushed the lpriima/WeakCache branch 2 times, most recently from 6923ea3 to ffbc752 Compare March 18, 2020 07:24
@lpriima lpriima requested a review from dougqh March 18, 2020 08:02
Copy link
Copy Markdown
Contributor

@tylerbenson tylerbenson left a comment

Choose a reason for hiding this comment

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

Netty AttributeKeys can't recompute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think this class can use a cache semantic. The reason this exists is because netty will throw an error if an attribute of the same name is created more than once. (See the comment in the class.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Maybe just cache without time eviction ? only by weak reference expiration

Copy link
Copy Markdown
Contributor

@dougqh dougqh Mar 20, 2020

Choose a reason for hiding this comment

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

Conceptually, I don't think of WeakReference expiration as eviction per se. From the standpoint of retrieving something from the Map/Cache, WeakReference expiration isn't an observable difference. Only the side effect on memory is observable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think this class can use a cache semantic. The reason this exists is because netty will throw an error if an attribute of the same name is created more than once. (See the comment in the class.)

That doesn't necessarily mean that cache won't work, but it depends on the nature of the error. If Netty fails fast and in recoverable way, then we could simply handle the exception rather than introducing a side structure.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same problem here...

@lpriima lpriima force-pushed the lpriima/WeakCache branch 3 times, most recently from 623f9bf to 3aed00d Compare March 19, 2020 15:17
Copy link
Copy Markdown
Contributor

@tylerbenson tylerbenson left a comment

Choose a reason for hiding this comment

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

Only minor/optional items remaining...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is implied for fields on an interface, so this doesn't change anything.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

that's true. Do you want me to revert it back ? it's just a style question

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm fine with dropping public, but I'm less keen on dropping static. And final is a useful implied addition.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How expensive is loadWeakCacheProvider()? Is this something we should be concerned about?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, I was pondering that. I think it would be good to have the Provider captured by a static final, so we don't keep reloading it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

since you're returning a boolean and not a count, maybe doesMatch/matches/evaluateMatch instead?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is that a side effect of our prior change in this area? But yes, we should clean-up the naming.

@lpriima lpriima force-pushed the lpriima/WeakCache branch from 3aed00d to e2937bc Compare March 19, 2020 21:59
@lpriima lpriima merged commit a5a5743 into master Mar 20, 2020
@lpriima lpriima deleted the lpriima/WeakCache branch March 20, 2020 07:23
@tylerbenson tylerbenson added this to the 0.47.0 milestone Apr 10, 2020
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.

4 participants