Skip to content

Introduce codec mapping caches #410

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

Closed

Conversation

frdeboffles
Copy link

@frdeboffles frdeboffles commented May 21, 2021

Fixes #409

Introduce codec mapping caches to improve encoding and decoding performances.

  • Switched the codec list to a thread safe variant to avoid the synchronized blocks. Even though CopyOnWriteArrayList is not super performant it should work fine in this context where the list should not be frequently updated.
  • Switched mockito-core to mockito-junit-jupiter for Junit 5 support

Make sure that:

  • You have read the contribution guidelines.
  • You have created a feature request first to discuss your contribution intent. Please reference the feature request ticket number in the pull request.
  • You use the code formatters provided here and have them applied to your changes. Don't submit any formatting related changes.
  • You submit test cases (unit or integration tests) that back your changes.

Issue description

See gh-409

New Public APIs

Additional context

@mp911de
Copy link
Collaborator

mp911de commented Jul 2, 2021

Thanks a lot for submitting a pull request. Introducing caching comes with quite some complexity. The on-demand cache registration of codecs resonates with my cautionary sense that the state of the codec registry changes over time (as the application keeps running) which can lead to some point to driver behavior that cannot be properly reproduced because of so many moving parts.

I'd like much more to explore a path where we pre-populate the caches to keep a stable state on a per-connection level. With doing so, potential bugs can be caught early on as each connection enters a stable state after establishing the connection.

I think to make that work, we would need to extend our codecs with some sort of interface that exposes which data types, classes and formats are supported (CodecMetadata.getFormats()/.getDataTypes()/…).

@mp911de mp911de added the type: enhancement A general enhancement label Jul 2, 2021
…decoding performances.

* Switched the codec list to a thread safe variant to avoid the synchronized blocks. Even though `CopyOnWriteArrayList` is not super performant it should work fine in this context where the list should not be frequently updated.
* Switched `mockito-core` to `mockito-junit-jupiter` for Junit 5 support
@frdeboffles frdeboffles force-pushed the feature-gh-409-codec-mapping-cache branch from 63d7b30 to 2d79aa7 Compare September 1, 2021 19:43
@frdeboffles
Copy link
Author

Sorry for the late reply. I will have a look at pre-filling the caches. This does imply that we don't support a codec that can encode sub-classes of the associated type.

@frdeboffles
Copy link
Author

frdeboffles commented Sep 4, 2021

@mp911de I followed your recommendations and tried to implement a pre-filled cache.
This time the changes I made are more invasive than before...
One issue is that we can't predict all the possible combinations given the support for nested arrays for example. I tried to cover 1 dimensional arrays in this implementation.
Please let me know if this is what you had in mind?

Note that I decided to do that in another commit instead of a fixup. Hope this is okay.

@mp911de
Copy link
Collaborator

mp911de commented Sep 6, 2021

Thanks a lot. I'm not sure about the codec finder API yet, but having each codec exposing details which data types it is able to process makes a lot of sense.

Are you able to come up with some benchmarks to see whether this optimization makes sense? We have some integrative benchmarks in the src/jmh directory. For the codecs, we could have benchmarks that do not require database interaction but rather work with the codec API directly.

@frdeboffles
Copy link
Author

I'll add benchmarks that compare the encode and decode using both the cache and default implementations of the codec finder.
About the CodecFinder API, my thinking was to offer the users the ability to use or not the cache based finder. I guess the cache based finder may come slower in some particular case where an application is constantly requesting a new connection.

@frdeboffles frdeboffles force-pushed the feature-gh-409-codec-mapping-cache branch 2 times, most recently from 3cc431c to 8ce39e3 Compare September 7, 2021 17:58
@frdeboffles
Copy link
Author

frdeboffles commented Sep 7, 2021

I added some benchmarks as follow in the last commit:

Benchmark                                                (iterations)   Mode  Cnt       Score      Error  Units
CodecRegistryBenchmarks.decodeWithCacheDisabledRegistry            10  thrpt    5   15525.438 ± 3219.915  ops/s
CodecRegistryBenchmarks.decodeWithCacheDisabledRegistry           100  thrpt    5    1438.332 ±   53.718  ops/s
CodecRegistryBenchmarks.decodeWithCacheDisabledRegistry          1000  thrpt    5     134.925 ±    2.589  ops/s
CodecRegistryBenchmarks.decodeWithCacheEnabledRegistry             10  thrpt    5   28435.893 ± 1787.007  ops/s
CodecRegistryBenchmarks.decodeWithCacheEnabledRegistry            100  thrpt    5    2859.265 ±   82.144  ops/s
CodecRegistryBenchmarks.decodeWithCacheEnabledRegistry           1000  thrpt    5     282.089 ±    9.164  ops/s
CodecRegistryBenchmarks.encodeWithCacheDisabledRegistry            10  thrpt    5   34916.352 ± 1826.371  ops/s
CodecRegistryBenchmarks.encodeWithCacheDisabledRegistry           100  thrpt    5    3505.425 ±  184.198  ops/s
CodecRegistryBenchmarks.encodeWithCacheDisabledRegistry          1000  thrpt    5     341.682 ±   29.398  ops/s
CodecRegistryBenchmarks.encodeWithCacheEnabledRegistry             10  thrpt    5  160630.081 ± 8314.723  ops/s
CodecRegistryBenchmarks.encodeWithCacheEnabledRegistry            100  thrpt    5   15919.121 ±  578.995  ops/s
CodecRegistryBenchmarks.encodeWithCacheEnabledRegistry           1000  thrpt    5    1572.680 ±   58.117  ops/s

I ran the same benchmark on the main branch to compare the results and they kind of match with the cache disabled codec registry benchmarks:

Benchmark                                                (iterations)   Mode  Cnt      Score      Error  Units
CodecRegistryBenchmarks.decodeWithCacheDisabledRegistry            10  thrpt    5  14520.800 ± 1569.441  ops/s
CodecRegistryBenchmarks.decodeWithCacheDisabledRegistry           100  thrpt    5   1404.993 ±  122.501  ops/s
CodecRegistryBenchmarks.decodeWithCacheDisabledRegistry          1000  thrpt    5    136.700 ±   95.093  ops/s
CodecRegistryBenchmarks.encodeWithCacheDisabledRegistry            10  thrpt    5  32321.309 ± 3834.717  ops/s
CodecRegistryBenchmarks.encodeWithCacheDisabledRegistry           100  thrpt    5   3270.550 ±  314.711  ops/s
CodecRegistryBenchmarks.encodeWithCacheDisabledRegistry          1000  thrpt    5    362.672 ±   15.599  ops/s

@frdeboffles frdeboffles force-pushed the feature-gh-409-codec-mapping-cache branch 2 times, most recently from e502034 to f885190 Compare September 7, 2021 20:17
@mp911de
Copy link
Collaborator

mp911de commented Sep 8, 2021

Wow, that's amazing, 2x up to 10x improvement in throughput.

Out of curiosity, have you tried to backport the commits to the 0.8.x branch? I expect that some merge conflicts would arise because we introduced additional methods to the codecs, but out of curiosity, it would be good to know whether that's little or a lot of work. We plan to ship a service release for the 0.8.x development line later this month.

@frdeboffles
Copy link
Author

I originally tested this on the 0.8.x branch but this was the original commit of this PR.
I can try porting this in another PR.

* Refactored the codec registry to use a CodecFinder (default to SPI definition in the classpath)
* Provided 2 implementations of the codec finder, one without cache and another with cache
* Added a build cache method that will attempt to fill the cache when the codecs are updated. This cannot covers all the cases like the nested arrays, therefore for those type the cache will be filled dynamically on per-request basis
* Added microbenchmarks for codec encode and decode using the cache based implementation or not
* Disabled unixDomainSocketTest IT when running on Mac or Windows
@frdeboffles frdeboffles force-pushed the feature-gh-409-codec-mapping-cache branch from f885190 to 521217b Compare September 8, 2021 20:48
@mp911de
Copy link
Collaborator

mp911de commented Sep 14, 2021

Thanks a lot. I'll come back to this next week.

@mp911de mp911de changed the title gh-409: Introduce codec mapping caches Introduce codec mapping caches Sep 22, 2021
@mp911de mp911de added this to the 0.8.9.RELEASE milestone Sep 22, 2021
@mp911de mp911de self-assigned this Sep 22, 2021
mp911de pushed a commit that referenced this pull request Sep 22, 2021
…rmances.

* Switched the codec list to a thread safe variant to avoid the synchronized blocks. Even though `CopyOnWriteArrayList` is not super performant it should work fine in this context where the list should not be frequently updated.

* Switched `mockito-core` to `mockito-junit-jupiter` for Junit 5 support
* Refactored the codec registry to use a CodecFinder (default to SPI definition in the classpath)
* Provided 2 implementations of the codec finder, one without cache and another with cache
* Added a build cache method that will attempt to fill the cache when the codecs are updated. This cannot covers all the cases like the nested arrays, therefore for those type the cache will be filled dynamically on per-request basis
* Added microbenchmarks for codec encode and decode using the cache based implementation or not
* Disabled unixDomainSocketTest IT when running on Windows

[#410][resolves #409]
@mp911de mp911de closed this in bdd9e0d Sep 22, 2021
@mp911de
Copy link
Collaborator

mp911de commented Sep 22, 2021

Thank you for your contribution. That's merged and polished now.

@frdeboffles
Copy link
Author

Thank you for accepting it. I like your version better ;)

@frdeboffles frdeboffles deleted the feature-gh-409-codec-mapping-cache branch September 22, 2021 15:57
@mp911de
Copy link
Collaborator

mp911de commented Sep 23, 2021

Thanks for having a look at the polishing commits, I'll incorporate your feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Performance improvement on codec mapping
3 participants