fix!: stop static caches from pinning classes, class loaders and data sources - #436
Merged
Conversation
… sources Type-keyed caches move to ClassValue so cached reflection artifacts, metamodels, models and compiled plans share the lifetime of the class they describe. Provider and instantiator registries hold their class loader through a weak identity key and their per-loader value through a soft reference, breaking the value-to-key cycle that pinned redeployed applications. The database product name cache holds data sources weakly. The class-order cache is removed: provider lists are sorted once at load, and the Orderable.sort overloads with the cache flag are removed with it. Fixes #394
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Twenty-one unbounded static caches in storm-core held strong references to
Class,Method,ConstructorandDataSourcekeys for the life of the JVM, pinning entity classes, their class loaders and connection pools in redeployable containers and in test suites that spin many application contexts.Type-keyed caches
Every cache keyed by a class, method, constructor or type-derived composite key now lives in a
ClassValue, so the cached value shares the lifetime of the class it describes:DefaultORMReflectionImpl: record type, primary key field, canonical constructor, record components, and the method accessor cache (nested per declaring class).ObjectMapperFactory: constructor metadata, nested per declaring class.RecordReflection: Ref primary-key and data types (nested per declaring class, keyed by field name), sealed pattern detection, discriminator mappings.MetamodelFactory: root metamodels, and path-keyed metamodels nested per root table.RecordValidation: validation messages nested per type, keyed by the require-primary-key flag.ModelImpl: sealed subtype field-index maps.RecordMapper: compiled plans nested per record class, keyed by fetch plan; sealed plans in aClassValue-held holder because compilation needs theRefFactory.ModelFactory: models nested per record class, keyed by fetch plan.Class-loader-keyed caches
Providers.PROVIDER_CACHEandInstantiators.INSTANTIATOR_CACHEkeyed strong maps by class loader, and the cached provider instances themselves keep their loader reachable. The newClassLoaderCacheholds the loader through a weak identity key with a drained reference queue and the per-loader value through aSoftReference, which is what breaks the value-to-key cycle: once a loader is otherwise unreachable the collector clears the soft reference and reclaims the loader; a cleared entry for a live loader is recomputed on the next access.DataSource-keyed cache
Providers.DATABASE_PRODUCT_NAMESpinned everyDataSource(and its pool) ever inspected. It now uses weak identity keys with a drained reference queue, following theConcurrencyDetector.ConnectionIdentityidiom.Provider ordering
OrderableHelper.CLASS_ORDER_CACHEpinned provider classes through both its keys and values. The cache is gone:Providerssorts each provider list once when it is loaded into the loader-scoped cache, andenabled()preserves that order, since a filtered subset of a valid topological order is itself a valid topological order for the subset. TheOrderable.sortoverloads with thecacheflag are removed with it.Breaking:
Orderable.sort(List, boolean)andOrderable.sort(Stream, boolean)no longer exist; the single-argument overloads remain.Audited, no change needed
JdbcConnectionProviderImpl.ConcurrencyDetector.OWNERSalready uses weakConnectionIdentitykeys with a drained queue and removes entries deterministically after access.SqlTemplateImpl,TemplateFragments) are bounded LRUs and outside the scope of this issue.Tests
StaticCacheUnloadingTestloads an entity record through a child-first class loader, drives it through the reflection, metamodel and validation caches, and asserts the class is collected once the loader is dropped.DatabaseProductNameCacheTestverifies the product name is resolved once per data source identity and that a discarded data source is collected.ClassLoaderCacheTestcovers identity keying, value reuse and stale-entry cleanup.All three fail against the previous cache implementations.
Fixes #394